From a51d362b7a5a8006305795a41d1398719b636aa2 Mon Sep 17 00:00:00 2001 From: Eric Berry Date: Thu, 28 Apr 2022 12:51:39 +0100 Subject: [PATCH] Initial commit --- .clang-format | 58 + .clang-tidy | 351 ++ .gitignore | 35 + CMakeLists.txt | 168 + CONTRIBUTING.md | 12 + COPYING | 1 + LICENSE | 252 ++ NOTICE | 29 + README.md | 80 + cmake/ClangFormat.cmake | 53 + cmake/FindSACLIENT.cmake | 36 + cmake/FindYAJL.cmake | 36 + include/sec_security.h | 989 ++++++ include/sec_security_asn1kc.h | 113 + include/sec_security_comcastids.h | 123 + include/sec_security_common.h | 767 +++++ include/sec_security_datatype.h | 646 ++++ include/sec_version.h | 19 + src/sec_adapter_asn1kc.c | 753 ++++ src/sec_adapter_buffer.c | 65 + src/sec_adapter_bundle.c | 374 ++ src/sec_adapter_bundle.h | 29 + src/sec_adapter_certificate.c | 734 ++++ src/sec_adapter_cipher.c | 1169 +++++++ src/sec_adapter_cipher.h | 33 + src/sec_adapter_common.c | 169 + src/sec_adapter_digest.c | 311 ++ src/sec_adapter_engine.c | 355 ++ src/sec_adapter_key.c | 3428 +++++++++++++++++++ src/sec_adapter_key.h | 55 + src/sec_adapter_key_legacy.h | 44 + src/sec_adapter_keyexchange.c | 246 ++ src/sec_adapter_logger.c | 70 + src/sec_adapter_mac.c | 239 ++ src/sec_adapter_processor.c | 505 +++ src/sec_adapter_processor.h | 120 + src/sec_adapter_pubops.c | 629 ++++ src/sec_adapter_pubops.h | 51 + src/sec_adapter_random.c | 104 + src/sec_adapter_signature.c | 545 +++ src/sec_adapter_store.c | 446 +++ src/sec_adapter_store.h | 119 + src/sec_adapter_svp.c | 161 + src/sec_adapter_svp.h | 30 + src/sec_adapter_utils.c | 1216 +++++++ src/sec_adapter_utils.h | 208 ++ src/sec_adapter_utils_time.c | 48 + test/main/cpp/bundle.cpp | 129 + test/main/cpp/bundle.h | 30 + test/main/cpp/cert.cpp | 298 ++ test/main/cpp/cert.h | 36 + test/main/cpp/cipher.cpp | 1373 ++++++++ test/main/cpp/cipher.h | 84 + test/main/cpp/concurrent.cpp | 131 + test/main/cpp/concurrent.h | 29 + test/main/cpp/digest.cpp | 188 + test/main/cpp/digest.h | 34 + test/main/cpp/exchange.cpp | 663 ++++ test/main/cpp/exchange.h | 30 + test/main/cpp/jtype.cpp | 471 +++ test/main/cpp/jtype.h | 42 + test/main/cpp/key.cpp | 1283 +++++++ test/main/cpp/key.h | 71 + test/main/cpp/keyctrl.cpp | 1813 ++++++++++ test/main/cpp/keyctrl.h | 106 + test/main/cpp/mac.cpp | 306 ++ test/main/cpp/mac.h | 40 + test/main/cpp/processor.cpp | 114 + test/main/cpp/processor.h | 34 + test/main/cpp/random.cpp | 47 + test/main/cpp/random.h | 26 + test/main/cpp/sec_api_utest_main.cpp | 1365 ++++++++ test/main/cpp/sec_api_utest_main.h | 31 + test/main/cpp/sign.cpp | 483 +++ test/main/cpp/sign.h | 34 + test/main/cpp/svp.cpp | 335 ++ test/main/cpp/svp.h | 41 + test/main/cpp/test_creds_clear.cpp | 1303 +++++++ test/main/cpp/test_ctx.cpp | 493 +++ test/main/cpp/wrapped.cpp | 1370 ++++++++ test/main/cpp/wrapped.h | 60 + test/main/headers/test_creds.h | 161 + test/main/headers/test_ctx.h | 192 ++ test/openssl/headers/sa_soc_key_container.h | 29 + test/openssl/headers/test_creds.h | 164 + test/openssl/headers/test_ctx.h | 192 ++ test/openssl/src/sa_soc_key_container.cpp | 189 + test/openssl/src/test_creds_soc.cpp | 225 ++ test/valgrind.supp | 70 + 89 files changed, 30139 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CONTRIBUTING.md create mode 120000 COPYING create mode 100644 LICENSE create mode 100644 NOTICE create mode 100644 README.md create mode 100644 cmake/ClangFormat.cmake create mode 100755 cmake/FindSACLIENT.cmake create mode 100755 cmake/FindYAJL.cmake create mode 100644 include/sec_security.h create mode 100644 include/sec_security_asn1kc.h create mode 100644 include/sec_security_comcastids.h create mode 100644 include/sec_security_common.h create mode 100755 include/sec_security_datatype.h create mode 100644 include/sec_version.h create mode 100644 src/sec_adapter_asn1kc.c create mode 100644 src/sec_adapter_buffer.c create mode 100644 src/sec_adapter_bundle.c create mode 100644 src/sec_adapter_bundle.h create mode 100644 src/sec_adapter_certificate.c create mode 100644 src/sec_adapter_cipher.c create mode 100644 src/sec_adapter_cipher.h create mode 100644 src/sec_adapter_common.c create mode 100644 src/sec_adapter_digest.c create mode 100644 src/sec_adapter_engine.c create mode 100644 src/sec_adapter_key.c create mode 100644 src/sec_adapter_key.h create mode 100644 src/sec_adapter_key_legacy.h create mode 100644 src/sec_adapter_keyexchange.c create mode 100644 src/sec_adapter_logger.c create mode 100644 src/sec_adapter_mac.c create mode 100644 src/sec_adapter_processor.c create mode 100644 src/sec_adapter_processor.h create mode 100644 src/sec_adapter_pubops.c create mode 100644 src/sec_adapter_pubops.h create mode 100644 src/sec_adapter_random.c create mode 100644 src/sec_adapter_signature.c create mode 100644 src/sec_adapter_store.c create mode 100644 src/sec_adapter_store.h create mode 100644 src/sec_adapter_svp.c create mode 100644 src/sec_adapter_svp.h create mode 100644 src/sec_adapter_utils.c create mode 100644 src/sec_adapter_utils.h create mode 100644 src/sec_adapter_utils_time.c create mode 100644 test/main/cpp/bundle.cpp create mode 100644 test/main/cpp/bundle.h create mode 100644 test/main/cpp/cert.cpp create mode 100644 test/main/cpp/cert.h create mode 100644 test/main/cpp/cipher.cpp create mode 100644 test/main/cpp/cipher.h create mode 100644 test/main/cpp/concurrent.cpp create mode 100644 test/main/cpp/concurrent.h create mode 100644 test/main/cpp/digest.cpp create mode 100644 test/main/cpp/digest.h create mode 100644 test/main/cpp/exchange.cpp create mode 100644 test/main/cpp/exchange.h create mode 100644 test/main/cpp/jtype.cpp create mode 100644 test/main/cpp/jtype.h create mode 100644 test/main/cpp/key.cpp create mode 100644 test/main/cpp/key.h create mode 100644 test/main/cpp/keyctrl.cpp create mode 100644 test/main/cpp/keyctrl.h create mode 100644 test/main/cpp/mac.cpp create mode 100644 test/main/cpp/mac.h create mode 100644 test/main/cpp/processor.cpp create mode 100644 test/main/cpp/processor.h create mode 100644 test/main/cpp/random.cpp create mode 100644 test/main/cpp/random.h create mode 100644 test/main/cpp/sec_api_utest_main.cpp create mode 100644 test/main/cpp/sec_api_utest_main.h create mode 100644 test/main/cpp/sign.cpp create mode 100644 test/main/cpp/sign.h create mode 100644 test/main/cpp/svp.cpp create mode 100644 test/main/cpp/svp.h create mode 100644 test/main/cpp/test_creds_clear.cpp create mode 100644 test/main/cpp/test_ctx.cpp create mode 100644 test/main/cpp/wrapped.cpp create mode 100644 test/main/cpp/wrapped.h create mode 100644 test/main/headers/test_creds.h create mode 100644 test/main/headers/test_ctx.h create mode 100644 test/openssl/headers/sa_soc_key_container.h create mode 100644 test/openssl/headers/test_creds.h create mode 100644 test/openssl/headers/test_ctx.h create mode 100644 test/openssl/src/sa_soc_key_container.cpp create mode 100644 test/openssl/src/test_creds_soc.cpp create mode 100644 test/valgrind.supp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..dc1baf0 --- /dev/null +++ b/.clang-format @@ -0,0 +1,58 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: None +AlignEscapedNewlines: DontAlign +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true # forces brace next to typdef enum { +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +DerivePointerAlignment: false +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PointerAlignment: Left +ReflowComments: false +SortIncludes: true +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..a0aac7c --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,351 @@ +Checks: 'clang-diagnostic-*,clang-analyzer-*,*,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-llvm-header-guard,-misc-unused-parameters,-google-readability-braces-around-statements,-hicpp-braces-around-statements,-readability-braces-around-statements,-cppcoreguidelines-init-variables,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,-hicpp-signed-bitwise,-google-readability-todo,-cppcoreguidelines-special-member-functions,-hicpp-special-member-functions,-cert-err58-cpp,-cppcoreguidelines-owning-memory,-cppcoreguidelines-macro-usage,-modernize-use-trailing-return-type,-modernize-use-using,-hicpp-avoid-c-arrays,-modernize-avoid-c-arrays,-cppcoreguidelines-avoid-c-arrays,-fuchsia-statically-constructed-objects,-cppcoreguidelines-pro-type-vararg,-hicpp-vararg,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-google-runtime-references,-cppcoreguidelines-pro-type-union-access,-fuchsia-default-arguments-calls,-hicpp-no-array-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-google-build-using-namespace,-hicpp-no-malloc,-cppcoreguidelines-no-malloc,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-fuchsia-default-arguments-declarations,-cppcoreguidelines-pro-bounds-constant-array-index,-llvmlibc-restrict-system-libc-headers,-llvmlibc-implementation-in-namespace,-llvmlibc-callee-namespace,-altera-unroll-loops,-altera-id-dependent-backward-branch,-altera-struct-pack-align,-cppcoreguidelines-avoid-non-const-global-variables,-readability-function-cognitive-complexity,-misc-no-recursion' +WarningsAsErrors: '' +HeaderFilterRegex: ((?!openssl/).)* +AnalyzeTemporaryDtors: false +FormatStyle: none +User: user +CheckOptions: + - key: abseil-string-find-startswith.AbseilStringsMatchHeader + value: 'absl/strings/match.h' + - key: abseil-string-find-startswith.IncludeStyle + value: llvm + - key: abseil-string-find-startswith.StringLikeClasses + value: '::std::basic_string' + - key: bugprone-argument-comment.CommentBoolLiterals + value: '0' + - key: bugprone-argument-comment.CommentCharacterLiterals + value: '0' + - key: bugprone-argument-comment.CommentFloatLiterals + value: '0' + - key: bugprone-argument-comment.CommentIntegerLiterals + value: '0' + - key: bugprone-argument-comment.CommentNullPtrs + value: '0' + - key: bugprone-argument-comment.CommentStringLiterals + value: '0' + - key: bugprone-argument-comment.CommentUserDefinedLiterals + value: '0' + - key: bugprone-argument-comment.IgnoreSingleArgument + value: '0' + - key: bugprone-argument-comment.StrictMode + value: '0' + - key: bugprone-assert-side-effect.AssertMacros + value: assert + - key: bugprone-assert-side-effect.CheckFunctionCalls + value: '0' + - key: bugprone-dangling-handle.HandleClasses + value: 'std::basic_string_view;std::experimental::basic_string_view' + - key: bugprone-dynamic-static-initializers.HeaderFileExtensions + value: ',h,hh,hpp,hxx' + - key: bugprone-exception-escape.FunctionsThatShouldNotThrow + value: '' + - key: bugprone-exception-escape.IgnoredExceptions + value: '' + - key: bugprone-misplaced-widening-cast.CheckImplicitCasts + value: '0' + - key: bugprone-not-null-terminated-result.WantToUseSafeFunctions + value: '1' + - key: bugprone-signed-char-misuse.CharTypdefsToIgnore + value: '' + - key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant + value: '1' + - key: bugprone-sizeof-expression.WarnOnSizeOfConstant + value: '1' + - key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression + value: '0' + - key: bugprone-sizeof-expression.WarnOnSizeOfThis + value: '1' + - key: bugprone-string-constructor.LargeLengthThreshold + value: '8388608' + - key: bugprone-string-constructor.WarnOnLargeLength + value: '1' + - key: bugprone-suspicious-enum-usage.StrictMode + value: '0' + - key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens + value: '5' + - key: bugprone-suspicious-missing-comma.RatioThreshold + value: '0.200000' + - key: bugprone-suspicious-missing-comma.SizeThreshold + value: '5' + - key: bugprone-suspicious-string-compare.StringCompareLikeFunctions + value: '' + - key: bugprone-suspicious-string-compare.WarnOnImplicitComparison + value: '1' + - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison + value: '0' + - key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit + value: '16' + - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField + value: '1' + - key: bugprone-unused-return-value.CheckedFunctions + value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty' + - key: cert-dcl16-c.IgnoreMacros + value: '1' + - key: cert-dcl16-c.NewSuffixes + value: 'L;LL;LU;LLU' + - key: cert-dcl59-cpp.HeaderFileExtensions + value: ',h,hh,hpp,hxx' + - key: cert-err09-cpp.CheckThrowTemporaries + value: '1' + - key: cert-err61-cpp.CheckThrowTemporaries + value: '1' + - key: cert-msc32-c.DisallowedSeedTypes + value: 'time_t,std::time_t' + - key: cert-msc51-cpp.DisallowedSeedTypes + value: 'time_t,std::time_t' + - key: cert-oop11-cpp.IncludeStyle + value: llvm + - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField + value: '0' + - key: cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal + value: '0' + - key: cppcoreguidelines-explicit-virtual-functions.FinalSpelling + value: final + - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors + value: '1' + - key: cppcoreguidelines-explicit-virtual-functions.OverrideSpelling + value: override + - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic + value: '1' + - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays + value: '0' + - key: cppcoreguidelines-pro-type-member-init.UseAssignment + value: '0' + - key: fuchsia-header-anon-namespaces.HeaderFileExtensions + value: ',h,hh,hpp,hxx' + - key: fuchsia-restrict-system-includes.Includes + value: '*' + - key: google-build-namespaces.HeaderFileExtensions + value: ',h,hh,hpp,hxx' + - key: google-global-names-in-headers.HeaderFileExtensions + value: ',h,hh,hpp,hxx' + - key: google-readability-braces-around-statements.ShortStatementLines + value: '1' + - key: google-readability-function-size.BranchThreshold + value: '4294967295' + - key: google-readability-function-size.LineThreshold + value: '4294967295' + - key: google-readability-function-size.NestingThreshold + value: '4294967295' + - key: google-readability-function-size.ParameterThreshold + value: '4294967295' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-function-size.VariableThreshold + value: '4294967295' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: google-runtime-int.SignedTypePrefix + value: int + - key: google-runtime-int.TypeSuffix + value: '' + - key: google-runtime-int.UnsignedTypePrefix + value: uint + - key: hicpp-function-size.BranchThreshold + value: '4294967295' + - key: hicpp-function-size.LineThreshold + value: '4294967295' + - key: hicpp-function-size.NestingThreshold + value: '4294967295' + - key: hicpp-function-size.ParameterThreshold + value: '4294967295' + - key: hicpp-function-size.StatementThreshold + value: '800' + - key: hicpp-function-size.VariableThreshold + value: '4294967295' + - key: hicpp-member-init.IgnoreArrays + value: '0' + - key: hicpp-member-init.UseAssignment + value: '0' + - key: hicpp-move-const-arg.CheckTriviallyCopyableMove + value: '1' + - key: hicpp-multiway-paths-covered.WarnOnMissingElse + value: '0' + - key: hicpp-named-parameter.IgnoreFailedSplit + value: '0' + - key: hicpp-uppercase-literal-suffix.IgnoreMacros + value: '1' + - key: hicpp-uppercase-literal-suffix.NewSuffixes + value: '' + - key: hicpp-use-auto.MinTypeNameLength + value: '5' + - key: hicpp-use-auto.RemoveStars + value: '0' + - key: hicpp-use-emplace.ContainersWithPushBack + value: '::std::vector;::std::list;::std::deque' + - key: hicpp-use-emplace.SmartPointers + value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' + - key: hicpp-use-emplace.TupleMakeFunctions + value: '::std::make_pair;::std::make_tuple' + - key: hicpp-use-emplace.TupleTypes + value: '::std::pair;::std::tuple' + - key: hicpp-use-equals-default.IgnoreMacros + value: '1' + - key: hicpp-use-equals-delete.IgnoreMacros + value: '1' + - key: hicpp-use-noexcept.ReplacementString + value: '' + - key: hicpp-use-noexcept.UseNoexceptFalse + value: '1' + - key: hicpp-use-nullptr.NullMacros + value: '' + - key: hicpp-use-override.AllowOverrideAndFinal + value: '0' + - key: hicpp-use-override.FinalSpelling + value: final + - key: hicpp-use-override.IgnoreDestructors + value: '0' + - key: hicpp-use-override.OverrideSpelling + value: override + - key: misc-definitions-in-headers.HeaderFileExtensions + value: ',h,hh,hpp,hxx' + - key: misc-definitions-in-headers.UseHeaderFileExtension + value: '1' + - key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries + value: '1' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-make-shared.IgnoreMacros + value: '1' + - key: modernize-make-shared.IncludeStyle + value: llvm + - key: modernize-make-shared.MakeSmartPtrFunction + value: 'std::make_shared' + - key: modernize-make-shared.MakeSmartPtrFunctionHeader + value: memory + - key: modernize-make-unique.IgnoreMacros + value: '1' + - key: modernize-make-unique.IncludeStyle + value: llvm + - key: modernize-make-unique.MakeSmartPtrFunction + value: 'std::make_unique' + - key: modernize-make-unique.MakeSmartPtrFunctionHeader + value: memory + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-pass-by-value.ValuesOnly + value: '0' + - key: modernize-raw-string-literal.ReplaceShorterLiterals + value: '0' + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-replace-random-shuffle.IncludeStyle + value: llvm + - key: modernize-use-auto.MinTypeNameLength + value: '5' + - key: modernize-use-auto.RemoveStars + value: '0' + - key: modernize-use-default-member-init.IgnoreMacros + value: '1' + - key: modernize-use-default-member-init.UseAssignment + value: '0' + - key: modernize-use-emplace.ContainersWithPushBack + value: '::std::vector;::std::list;::std::deque' + - key: modernize-use-emplace.SmartPointers + value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' + - key: modernize-use-emplace.TupleMakeFunctions + value: '::std::make_pair;::std::make_tuple' + - key: modernize-use-emplace.TupleTypes + value: '::std::pair;::std::tuple' + - key: modernize-use-equals-default.IgnoreMacros + value: '1' + - key: modernize-use-equals-delete.IgnoreMacros + value: '1' + - key: modernize-use-nodiscard.ReplacementString + value: '[[nodiscard]]' + - key: modernize-use-noexcept.ReplacementString + value: '' + - key: modernize-use-noexcept.UseNoexceptFalse + value: '1' + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: modernize-use-override.AllowOverrideAndFinal + value: '0' + - key: modernize-use-override.FinalSpelling + value: final + - key: modernize-use-override.IgnoreDestructors + value: '0' + - key: modernize-use-override.OverrideSpelling + value: override + - key: modernize-use-transparent-functors.SafeMode + value: '0' + - key: objc-forbidden-subclassing.ForbiddenSuperClassNames + value: 'ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView' + - key: openmp-exception-escape.IgnoredExceptions + value: '' + - key: performance-faster-string-find.StringLikeClasses + value: 'std::basic_string' + - key: performance-for-range-copy.AllowedTypes + value: '' + - key: performance-for-range-copy.WarnOnAllAutoCopies + value: '0' + - key: performance-inefficient-string-concatenation.StrictMode + value: '0' + - key: performance-inefficient-vector-operation.EnableProto + value: '0' + - key: performance-inefficient-vector-operation.VectorLikeClasses + value: '::std::vector' + - key: performance-move-const-arg.CheckTriviallyCopyableMove + value: '1' + - key: performance-move-constructor-init.IncludeStyle + value: llvm + - key: performance-no-automatic-move.AllowedTypes + value: '' + - key: performance-type-promotion-in-math-fn.IncludeStyle + value: llvm + - key: performance-unnecessary-copy-initialization.AllowedTypes + value: '' + - key: performance-unnecessary-value-param.AllowedTypes + value: '' + - key: performance-unnecessary-value-param.IncludeStyle + value: llvm + - key: portability-simd-intrinsics.Std + value: '' + - key: portability-simd-intrinsics.Suggest + value: '0' + - key: readability-else-after-return.WarnOnUnfixable + value: '1' + - key: readability-function-size.BranchThreshold + value: '4294967295' + - key: readability-function-size.LineThreshold + value: '4294967295' + - key: readability-function-size.NestingThreshold + value: '4294967295' + - key: readability-function-size.ParameterThreshold + value: '4294967295' + - key: readability-function-size.StatementThreshold + value: '800' + - key: readability-function-size.VariableThreshold + value: '4294967295' + - key: readability-identifier-naming.IgnoreFailedSplit + value: '0' + - key: readability-inconsistent-declaration-parameter-name.IgnoreMacros + value: '1' + - key: readability-inconsistent-declaration-parameter-name.Strict + value: '0' + - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors + value: '0' + - key: readability-redundant-smartptr-get.IgnoreMacros + value: '1' + - key: readability-redundant-string-init.StringNames + value: '::std::basic_string' + - key: readability-simplify-boolean-expr.ChainedConditionalAssignment + value: '0' + - key: readability-simplify-boolean-expr.ChainedConditionalReturn + value: '0' + - key: readability-simplify-subscript-expr.Types + value: '::std::basic_string;::std::basic_string_view;::std::vector;::std::array' + - key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold + value: '3' + - key: readability-uppercase-literal-suffix.IgnoreMacros + value: '1' + - key: readability-uppercase-literal-suffix.NewSuffixes + value: '' + - key: zircon-temporary-objects.Names + value: '' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f751c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +cmake-build-* +.idea diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a9ae85a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,168 @@ +# Copyright 2020-2022 Comcast Cable Communications Management, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.16) +project(sec_api_2_adapter C CXX) + +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GNU_SOURCE -pthread") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE") + +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../cmake" ${CMAKE_MODULE_PATH}) +message("CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") +include(ClangFormat) + +if (DEFINED ENABLE_CLANG_TIDY) + find_program(CLANG_TIDY_COMMAND NAMES clang-tidy) + if (CLANG_TIDY_COMMAND) + set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_COMMAND}; ) + set(CMAKE_C_CLANG_TIDY ${CLANG_TIDY_COMMAND}; ) + message("clang-tidy found--enabling") + else () + message("clang-tidy not found") + endif () +else() + message("clang-tidy disabled") +endif () + +if (DEFINED ENABLE_SOC_KEY_TESTS) + set(CMAKE_CXX_FLAGS "-DENABLE_SOC_KEY_TESTS ${CMAKE_CXX_FLAGS}") + set(CMAKE_C_FLAGS "-DENABLE_SOC_KEY_TESTS ${CMAKE_C_FLAGS}") +endif () + +enable_testing() + +# Set OPENSSL_ROOT_DIR if not found +find_package(OpenSSL REQUIRED) +# Set YAJL_ROOT if not found +find_package(YAJL REQUIRED) +# Set SACLIENT_ROOT if not found +find_package(SACLIENT REQUIRED) + +include_directories( + ${OPENSSL_INCLUDE_DIR} + ${YAJL_INCLUDE_DIR} + ${SACLIENT_INCLUDE_DIR} + include + src +) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + add_compile_options(-DSEC_TARGET_IOS=1) +endif () + +add_compile_options(-DYAJL_V2=true) + +add_library(sec_api SHARED + include/sec_security.h + include/sec_security_asn1kc.h + include/sec_security_comcastids.h + include/sec_security_common.h + include/sec_security_datatype.h + include/sec_version.h + src/sec_adapter_bundle.h src/sec_adapter_bundle.c + src/sec_adapter_cipher.h src/sec_adapter_cipher.c + src/sec_adapter_key.h src/sec_adapter_key.c + src/sec_adapter_processor.h src/sec_adapter_processor.c + src/sec_adapter_pubops.h src/sec_adapter_pubops.c + src/sec_adapter_store.h src/sec_adapter_store.c + src/sec_adapter_svp.h src/sec_adapter_svp.c + src/sec_adapter_asn1kc.c + src/sec_adapter_buffer.c + src/sec_adapter_certificate.c + src/sec_adapter_common.c + src/sec_adapter_digest.c + src/sec_adapter_engine.c + src/sec_adapter_keyexchange.c + src/sec_adapter_logger.c + src/sec_adapter_mac.c + src/sec_adapter_random.c + src/sec_adapter_signature.c + src/sec_adapter_utils.c + src/sec_adapter_utils_time.c + src/sec_adapter_key_legacy.h) + +set_target_properties(sec_api PROPERTIES + LINKER_LANGUAGE C + SO_VERSION 2.3 + VERSION 2.3.2.4 + ) + +target_link_libraries(sec_api + PRIVATE + ${SACLIENT_LIBRARY} + ${OPENSSL_CRYPTO_LIBRARY} + ) + +target_clangformat_setup(sec_api) + +add_executable(sec_api_2_adapter_test + test/main/headers/test_creds.h + test/openssl/headers/test_ctx.h + test/main/cpp/bundle.cpp + test/main/cpp/cert.cpp + test/main/cpp/cipher.cpp + test/main/cpp/concurrent.cpp + test/main/cpp/digest.cpp + test/main/cpp/exchange.cpp + test/main/cpp/jtype.cpp + test/main/cpp/key.cpp + test/main/cpp/keyctrl.cpp + test/main/cpp/mac.cpp + test/main/cpp/processor.cpp + test/main/cpp/random.cpp + test/main/cpp/sec_api_utest_main.cpp + test/main/cpp/sign.cpp + test/main/cpp/svp.cpp + test/main/cpp/test_creds_clear.cpp + test/main/cpp/test_ctx.cpp + test/main/cpp/wrapped.cpp + test/openssl/headers/test_ctx.h + test/openssl/headers/test_creds.h + test/openssl/src/test_creds_soc.cpp + test/openssl/src/sa_soc_key_container.cpp + ) + +target_include_directories(sec_api_2_adapter_test + PRIVATE + src + test/main/cpp + test/openssl/headers + ) + +target_link_libraries(sec_api_2_adapter_test + PRIVATE + sec_api + ${SACLIENT_LIBRARY} + ${OPENSSL_CRYPTO_LIBRARY} + ${YAJL_LIBRARY} + ) + +add_test(sec_api2_adapter_test sec_api_utest_main) + +target_clangformat_setup(sec_api_2_adapter_test) + +# 'make install' to the correct locations (provided by GNUInstallDirs). +install(TARGETS sec_api sec_api_2_adapter_test + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + +install(DIRECTORY include/ DESTINATION include) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..dba4929 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,12 @@ +Contributing +============ + +If you wish to make code contributions to this project, the master source is hosted at +[code.rdkcentral.com](https://code.rdkcentral.com/r/#/admin/projects/components/generic/secapi2-adapter). +You can submit your changes for review via that site. + +Please follow the [workflow](https://wiki.rdkcentral.com/display/CMF/Gerrit+Development+Workflow) when making a +contribution. + +In order to contribute code, first-time users are requested to agree to the +[license](https://wiki.rdkcentral.com/signup.action). diff --git a/COPYING b/COPYING new file mode 120000 index 0000000..7a694c9 --- /dev/null +++ b/COPYING @@ -0,0 +1 @@ +LICENSE \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5e41586 --- /dev/null +++ b/LICENSE @@ -0,0 +1,252 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Comcast Cable Communications Management, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +Extracts from RFC 3526 are: +Copyright (C) The Internet Society (2003). All Rights Reserved. + +This document and translations of it may be copied and furnished to +others, and derivative works that comment on or otherwise explain it +or assist in its implementation may be prepared, copied, published +and distributed, in whole or in part, without restriction of any +kind, provided that the above copyright notice and this paragraph are +included on all such copies and derivative works. However, this +document itself may not be modified in any way, such as by removing +the copyright notice or references to the Internet Society or other +Internet organizations, except as needed for the purpose of +developing Internet standards in which case the procedures for +copyrights defined in the Internet Standards process must be +followed, or as required to translate it into languages other than +English. + +The limited permissions granted above are perpetual and will not be +revoked by the Internet Society or its successors or assigns. +This document and the information contained herein is provided on an +"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING +TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION +HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF +MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..b419829 --- /dev/null +++ b/NOTICE @@ -0,0 +1,29 @@ +secapi2_adapter + +Copyright 2020 Comcast Cable Communications Management, LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +SPDX-License-Identifier: Apache-2.0 + +This product includes software developed at Comcast (http://www.comcast.com/). + +The component may include material which is licensed under other licenses / copyrights as +listed below. Your use of this material within the component is also subject to the terms and +conditions of these licenses. The LICENSE file contains the text of all the licenses which apply within this component. + +Extracts from RFC 3526 are: +Copyright (C) The Internet Society (2003). All Rights Reserved. + +Copyright Tomas Zeman 2019-2020 +Distributed under the Boost Software License, Version 1.0. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9f95a7d --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# sec_api_2_adapter + +## Summary + +sec_api_2_adapter is a SOC neutral implementation of SecApi 2.3 that uses SecApi 3 as it's cryptographic implementation. +sec_api_2_adapter uses SecApi 2.3 unit tests to test the library. + +There are a few features in SecApi 2.3 that are not supported due to incompatibility with SecApi 3: + +- SecCipher_ProcessCtrWithOpaqueDataShift (Data shift not supported) +- SecCipher_ProcessCtrWithDataShift (Data shift not supported) +- SecProcessor_GetInstance (Deprecated function) +- SecOpaqueBuffer_Release (Not supported by SecApi 3) +- SecCodeIntegrity_SecureBootEnabled (Not supported by SecApi 3) +- SecSVP_SetTime (Not supported by SecApi 3) + +Calling any of these functions will return a SEC_RESULT_UNIMPLEMENTED_FEATURE error. + +## Directories + +- The include directory contains the SecApi 2.3 API include files. +- The src directory contains the sources for the sec_api_2_adapter. +- The test directory contains the SecApi 2.3 tests that have been modified to test the sec_api_2_adapter. +- The cmake directory contains additional cmake build helper files. +- The root directory contains the master cmake build files. + +## Building + +### Generate Build Files + +To build sec_api_2_adapter, first run cmake to generate build files. + +The build assumes that the following packages have already been installed: +YAJL - include -DYAJL_ROOT= if not found +OPENSSL - include -DOPENSSL_ROOT_DIR= if not found +SecApi3 - include -DSACLIENT_ROOT= if not found +Add -DCMAKE_INSTALL_PREFIX= to install to a non-standard install directory. + + +``` +cmake -S . -B cmake-build +``` + + +### Build + +To build sec_api_2_adapter, run a cmake build + +``` +cmake --build cmake-build +``` + +This creates a library, libsec_api.(so/dll/dylib) containing the adapter code (the extension .so/.dll/.dylib +created depends on which platform you are building on). It also creates a test application, sec_api_2_adapter_test, to +test the library. + +SOC and root key tests are also disabled by default. To enable these tests, add -DENABLE_SOC_KEY_TESTS=1. The test_root +key defined in test_creds_clear.cpp must match the root key defined on the test device for these tests to pass. + +Run unit test suite + +``` +cmake-build/sec_api_2_adapter_test +``` + +The tests for the reference implementation expect a SA_TEST_CLEAR_SOC_KEY_FORMAT to +exist so that SOC based key containers can be tested. + + +### Install + +To install sec_api_2_adapter, run a cmake install + +``` +cmake --install cmake-build +``` + +This copies the include files, the library, libsec_api.(so/dll/dylib) containing the adapter code (the +extension .so/.dll/.dylib created depends on which platform you are building on), and the test application, +sec_api_2_adapter_test, to their appropriate locations on the system. diff --git a/cmake/ClangFormat.cmake b/cmake/ClangFormat.cmake new file mode 100644 index 0000000..d041d14 --- /dev/null +++ b/cmake/ClangFormat.cmake @@ -0,0 +1,53 @@ +# Copyright Tomas Zeman 2019-2020. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +function(prefix_clangformat_setup prefix) + if(NOT CLANGFORMAT_EXECUTABLE) + set(CLANGFORMAT_EXECUTABLE clang-format) + endif() + + if(NOT EXISTS ${CLANGFORMAT_EXECUTABLE}) + find_program(clangformat_executable_tmp ${CLANGFORMAT_EXECUTABLE}) + if(clangformat_executable_tmp) + message("clang-format found--enabling") + set(CLANGFORMAT_EXECUTABLE ${clangformat_executable_tmp}) + unset(clangformat_executable_tmp) + else() + message("clang-format not found") + endif() + endif() + + foreach(clangformat_source ${ARGN}) + get_filename_component(clangformat_source ${clangformat_source} ABSOLUTE) + list(APPEND clangformat_sources ${clangformat_source}) + endforeach() + + add_custom_target(${prefix}_clangformat + COMMAND + ${CLANGFORMAT_EXECUTABLE} + -style=file + -i + ${clangformat_sources} + WORKING_DIRECTORY + ${CMAKE_SOURCE_DIR} + COMMENT + "Formatting ${prefix} with ${CLANGFORMAT_EXECUTABLE} ..." + ) + + if(TARGET clangformat) + add_dependencies(clangformat ${prefix}_clangformat) + else() + add_custom_target(clangformat DEPENDS ${prefix}_clangformat) + endif() +endfunction() + +function(clangformat_setup) + prefix_clangformat_setup(${PROJECT_NAME} ${ARGN}) +endfunction() + +function(target_clangformat_setup target) + get_target_property(target_sources ${target} SOURCES) + prefix_clangformat_setup(${target} ${target_sources}) +endfunction() diff --git a/cmake/FindSACLIENT.cmake b/cmake/FindSACLIENT.cmake new file mode 100755 index 0000000..d954a52 --- /dev/null +++ b/cmake/FindSACLIENT.cmake @@ -0,0 +1,36 @@ +# +# Copyright 2020-2022 Comcast Cable Communications Management, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# Find libyajl + +FIND_PATH(SACLIENT_INCLUDE_DIR sa.h) + +SET(SACLIENT_NAMES ${SACLIENT_NAMES} saclient libsaclient) +FIND_LIBRARY(SACLIENT_LIBRARY NAMES ${SACLIENT_NAMES} PATH) + +IF(SACLIENT_INCLUDE_DIR AND SACLIENT_LIBRARY) + SET(SACLIENT_FOUND TRUE) +ENDIF(SACLIENT_INCLUDE_DIR AND SACLIENT_LIBRARY) + +IF(SACLIENT_FOUND) + IF(NOT SACLIENT_FIND_QUIETLY) + MESSAGE(STATUS "Found SACLIENT: ${SACLIENT_LIBRARY}") + ENDIF (NOT SACLIENT_FIND_QUIETLY) +ELSE(SACLIENT_FOUND) + IF(SACLIENT_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find saclient") + ENDIF(SACLIENT_FIND_REQUIRED) +ENDIF(SACLIENT_FOUND) diff --git a/cmake/FindYAJL.cmake b/cmake/FindYAJL.cmake new file mode 100755 index 0000000..0ce6d45 --- /dev/null +++ b/cmake/FindYAJL.cmake @@ -0,0 +1,36 @@ +# +# Copyright 2020-2021 Comcast Cable Communications Management, LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# Find libyajl + +FIND_PATH(YAJL_INCLUDE_DIR yajl/yajl_common.h) + +SET(YAJL_NAMES ${YAJL_NAMES} yajl libyajl) +FIND_LIBRARY(YAJL_LIBRARY NAMES ${YAJL_NAMES} PATH) + +IF(YAJL_INCLUDE_DIR AND YAJL_LIBRARY) + SET(YAJL_FOUND TRUE) +ENDIF(YAJL_INCLUDE_DIR AND YAJL_LIBRARY) + +IF(YAJL_FOUND) + IF(NOT Yajl_FIND_QUIETLY) + MESSAGE(STATUS "Found Yajl: ${YAJL_LIBRARY}") + ENDIF (NOT Yajl_FIND_QUIETLY) +ELSE(YAJL_FOUND) + IF(Yajl_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find yajl") + ENDIF(Yajl_FIND_REQUIRED) +ENDIF(YAJL_FOUND) diff --git a/include/sec_security.h b/include/sec_security.h new file mode 100644 index 0000000..d0c13e5 --- /dev/null +++ b/include/sec_security.h @@ -0,0 +1,989 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_SECURITY_H +#define SEC_SECURITY_H + +#include "sec_security_common.h" +#include "sec_security_datatype.h" +#if !defined(SEC_TARGET_IOS) && !defined(SEC_TARGET_TVOS) +#include +#endif +#include + +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif + +#define OPENSSL_SUCCESS 1 + +#define SEC_KEYSTORAGE_FILE_DEFAULT_DIR "/opt/drm" +#define SEC_CERTIFICATESTORAGE_FILE_DEFAULT_DIR "/opt/drm" +#define SEC_BUNDLESTORAGE_FILE_DEFAULT_DIR "/opt/drm" + +/* macro to string */ +#define SEC_MTOS_(x) #x +#define SEC_MTOS(x) SEC_MTOS_(x) + +/* min */ +#ifndef SEC_MIN +#define SEC_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/* max */ +#ifndef SEC_MAX +#define SEC_MAX(a, b) (((a) < (b)) ? (b) : (a)) +#endif + +#define SEC_FREE(x) \ + do { \ + if ((x) != NULL) { \ + free(x); \ + (x) = NULL; \ + } \ + } while (0) +#define SEC_RSA_FREE(x) \ + do { \ + if ((x) != NULL) { \ + RSA_free(x); \ + (x) = NULL; \ + } \ + } while (0) +#define SEC_ECC_FREE(x) \ + do { \ + if ((x) != NULL) { \ + EC_KEY_free(x); \ + (x) = NULL; \ + } \ + } while (0) +#define SEC_EVPPKEY_FREE(x) \ + do { \ + if ((x) != NULL) { \ + EVP_PKEY_free(x); \ + (x) = NULL; \ + } \ + } while (0) +#define SEC_BIO_FREE(x) \ + do { \ + if ((x) != NULL) { \ + BIO_free(x); \ + (x) = NULL; \ + } \ + } while (0) +#define SEC_X509_FREE(x) \ + do { \ + if ((x) != NULL) { \ + X509_free(x); \ + (x) = NULL; \ + } \ + } while (0) + +/* debug prints */ +#define SEC_PRINT(fmt, ...) \ + do { \ + if (Sec_GetLogger() != NULL) { \ + Sec_GetLogger()(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#if defined(SEC_TARGET_IOS) || defined(SEC_TARGET_TVOS) +#define SEC_LOG(txt, ...) \ + do { \ + SEC_PRINT("" txt " (%s, %s, line %d)\n", ##__VA_ARGS__, __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + } while (0) +#else +#define SEC_LOG(txt, ...) \ + do { \ + SEC_PRINT("[%ld] " txt " (%s, %s, line %d)\n", (long int) syscall(SYS_gettid), ##__VA_ARGS__, \ + __PRETTY_FUNCTION__, __FILE__, __LINE__); \ + } while (0) +#endif + +#define SEC_LOG_ERROR(txt, ...) \ + do { \ + SEC_LOG("ERROR: " txt, ##__VA_ARGS__); \ + } while (0) + +#define SEC_TRACE(enabled, txt, ...) \ + do { \ + if (enabled) { \ + SEC_LOG(#enabled ": " txt, ##__VA_ARGS__); \ + } \ + } while (0) + +/** + * @brief Initialize secure processor + * + * Initializes the secure processor, generates key derivation base key, + * sets up all required resources. Only one secure processor can be + * active at a time. + * + * @param processorHandle pointer to a processor handle that will be set to + * a constructed handle. + * @param socInitParams pointer to initialization information for the secure + * processor. This structure is implementation specific. + * + * @return The status of the operation + */ +Sec_Result SecProcessor_GetInstance(Sec_ProcessorHandle** processorHandle, + Sec_ProcessorInitParams* socInitParams); + +/** + * @brief Initialize secure processor + * + * Initializes the secure processor, generates key derivation base key, + * sets up all required resources. Only one secure processor can be + * active at a time. + * + * @param processorHandle pointer to a processor handle that will be set to + * a constructed handle. + * @param globalDir path to the read only object directory. Can be set to NULL. + * @param appDir path to the read/write object directory. Can be set to NULL. + * + * @return The status of the operation + */ +Sec_Result SecProcessor_GetInstance_Directories(Sec_ProcessorHandle** processorHandle, const char* globalDir, + const char* appDir); + +/** + * @brief Get the minimum depth of the hardware key ladder + * + * @param handle pointer to a handle + * @param root root key type + * + * @return The key ladder depth + */ +SEC_SIZE SecProcessor_GetKeyLadderMinDepth(Sec_ProcessorHandle* processorHandle, Sec_KeyLadderRoot root); + +/** + * @brief Get the maximum depth of the hardware key ladder + * + * @param handle pointer to a handle + * @param root root key type + * + * @return The key ladder depth + */ +SEC_SIZE SecProcessor_GetKeyLadderMaxDepth(Sec_ProcessorHandle* processorHandle, Sec_KeyLadderRoot root); + +/** + * @brief Prints SOC specific version info + * + * @param processorHandle secure processor handle + */ +Sec_Result SecProcessor_PrintInfo(Sec_ProcessorHandle* processorHandle); + +/** + * @brief Get the Security Processor information (SecAPI version and build + * information). + * + * @param processorHandle secure processor handle + * @param pointer to secure processor information + */ +Sec_Result SecProcessor_GetInfo(Sec_ProcessorHandle* processorHandle, Sec_ProcessorInfo* secProcInfo); + +/** + * @brief Obtain the device id + * + * @param processorHandle secure processor handle + * @param deviceId pointer to a buffer that is SEC_DEVICEID_LEN long. The + * buffer will be filled with a device id. + * + * @return The status of the operation + */ +Sec_Result SecProcessor_GetDeviceId(Sec_ProcessorHandle* processorHandle, SEC_BYTE* deviceId); + +/** + * @brief Release the security processor + * + * @param processorHandle secure processor handle + * + * @return The status of the operation + */ +Sec_Result SecProcessor_Release(Sec_ProcessorHandle* processorHandle); + +/** + * @brief Initialize cipher object + * + * @param processorHandle secure processor handle + * @param algorithm cipher algorithm to use + * @param mode cipher mode to use + * @param keyHandle handle to use + * @param iv initialization vector value. Can be set to NULL is the cipher + * algorithm chosen does not require it. + * @param cipherHandle pointer to a cipher handle that will be set once + * the cipher object is constructed + * + * @return The status of the operation + */ +Sec_Result SecCipher_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_CipherAlgorithm algorithm, + Sec_CipherMode mode, Sec_KeyHandle* keyHandle, SEC_BYTE* iv, Sec_CipherHandle** cipherHandle); + +/** + * @brief Update the IV on the cipher handle + */ +Sec_Result SecCipher_UpdateIV(Sec_CipherHandle* cipherHandle, SEC_BYTE* iv); + +/** + * @brief En/De-cipher specified input data into and output buffer + * + * @param cipherHandle cipher handle + * @param input pointer to input data + * @param inputSize the length of input data in bytes + * @param lastInput boolean value specifying whether this is the last chunk + * of input that will be processed. + * @param output pointer to output data buffer + * @param outputSize the size of the output buffer + * @param bytesWritten pointer to a value that will be set to number + * of bytes written to the output buffer + * + * @return The status of the operation + */ +Sec_Result SecCipher_Process(Sec_CipherHandle* cipherHandle, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BOOL lastInput, + SEC_BYTE* output, SEC_SIZE outputSize, SEC_SIZE* bytesWritten); + +/** + * @brief En/De-cipher specified fragmented input data into and output buffer + * + * @param cipherHandle cipher handle + * @param input pointer to input data + * @param inputSize the length of input data in bytes + * @param lastInput boolean value specifying whether this is the last chunk + * of input that will be processed. + * @param output pointer to output data buffer + * @param outputSize the size of the output buffer + * @param bytesWritten pointer to a value that will be set to number + * of bytes written to the output buffer + * @param framentOffset offset in bytes of the fragment data within larger packet + * @param fragmentSize length in bytes of the data fragment + * @param fragmentPeriod the length in bytes of the packet containing the fragment + * + * @return The status of the operation + */ +Sec_Result SecCipher_ProcessFragmented(Sec_CipherHandle* cipherHandle, SEC_BYTE* input, SEC_SIZE inputSize, + SEC_BOOL lastInput, SEC_BYTE* output, SEC_SIZE outputSize, SEC_SIZE* bytesWritten, SEC_SIZE fragmentOffset, + SEC_SIZE fragmentSize, SEC_SIZE fragmentPeriod); + +/** + * @brief Process the opaque buffers that were obtained with Sec_OpaqueBufferMalloc + * + * @param cipherHandle cipher handle + * @param inputHandle opaque buffer containing input + * @param outputHandle opaque buffer for writing output + * @param inputSize the length of input to process + * @param lastInput boolean value specifying whether this is the last chunk + * of input that will be processed. + * @param bytesWritten pointer to a value that will be set to number + * of bytes written to the output buffer + */ +Sec_Result SecCipher_ProcessOpaque(Sec_CipherHandle* cipherHandle, Sec_OpaqueBufferHandle* inOpaqueBufferHandle, + Sec_OpaqueBufferHandle* outOpaqueBufferHandle, SEC_SIZE inputSize, SEC_BOOL lastInput, SEC_SIZE* bytesWritten); + +Sec_Result SecCipher_ProcessCtrWithOpaqueDataShift(Sec_CipherHandle* cipherHandle, + Sec_OpaqueBufferHandle* inOpaqueBufferHandle, Sec_OpaqueBufferHandle* outOpaqueBufferHandle, SEC_SIZE inputSize, + SEC_SIZE* bytesWritten, SEC_SIZE dataShift); + +/** + * @brief Perform cipher operation on the opaque input handle and check the output against the expected value. + * + * @param cipherHandle pointer to Sec_CipherHandle + * @param opaqueBufferHandle pointer to opaque buffer containing input + * @param SEC_SIZE checkLength number of bytes used for comparison + * @param SEC_BYTE expected expected value used for comparison + */ +Sec_Result SecCipher_KeyCheckOpaque(Sec_CipherHandle* cipherHandle, Sec_OpaqueBufferHandle* opaqueBufferHandle, + SEC_SIZE checkLength, SEC_BYTE* expected); +/** + * @brief Release the cipher object + * + * @param cipherHandle cipher handle + * + * @return The status of the operation + */ +Sec_Result SecCipher_Release(Sec_CipherHandle* cipherHandle); + +/** + * @brief Obtain a digest object handle + * + * @param processorHandle secure processor handle + * @param algorithm digest algorithm to use + * @param digestHandle output digest object handle + * + * @return The status of the operation + */ +Sec_Result SecDigest_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_DigestAlgorithm algorithm, + Sec_DigestHandle** digestHandle); + +/** + * @brief Update the digest value with the specified input + * + * @param digestHandle handle of the digest object + * @param input pointer to the input buffer + * @param inputSize size of the input buffer + * + * @return The status of the operation + */ +Sec_Result SecDigest_Update(Sec_DigestHandle* digestHandle, SEC_BYTE* input, SEC_SIZE inputSize); +/** + * @brief Update the digest value with the key data + * + * @param digestHandle handle of the digest object + * @param keyHandle key to use + * + * @return The status of the operation + */ +Sec_Result SecDigest_UpdateWithKey(Sec_DigestHandle* digestHandle, Sec_KeyHandle* keyHandle); + +/** + * @brief Calculate the resulting digest value and release the digest object + * + * @param digestHandle digest handle + * @param digestOutput pointer to an output buffer that will be filled with the resulting + * digest value. Buffer should be SEC_DIGEST_MAX_LEN bytes long. + * @param digestSize pointer to a value that will be set to actual size of the digest value + * + * @return The status of the operation + */ +Sec_Result SecDigest_Release(Sec_DigestHandle* digestHandle, SEC_BYTE* digestOutput, SEC_SIZE* digestSize); + +/** + * @brief Obtian a handle to the signature calculator + * + * @param processorHandle secure processor handle + * @param algorithm signing algorithm + * @param mode signing mode + * @param keyHandle key used for signing operations + * @param signatureHandle output signature handle + * + * @return The status of the operation + */ +Sec_Result SecSignature_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, Sec_KeyHandle* keyHandle, Sec_SignatureHandle** signatureHandle); + +/** + * @brief Sign/Verify Signature of the input data + * + * @param signatureHandle signature handle + * @param input pointer to the input buffer whose signature we are generating/verifying + * @param inputSize the length of the input + * @param signature buffer where signature is/will be stored + * @param signatureSize output variable that will be set to the signature size + * + * @return The status of the operation + */ +Sec_Result SecSignature_Process(Sec_SignatureHandle* signatureHandle, SEC_BYTE* input, SEC_SIZE inputSize, + SEC_BYTE* signature, SEC_SIZE* signatureSize); + +/** + * @brief Release the signature object + * + * @param signatureHandle cipher handle + * + * @return The status of the operation + */ +Sec_Result SecSignature_Release(Sec_SignatureHandle* signatureHandle); + +/** + * @brief Obtain a handle for the MAC calculator + * + * @param processorHandle secure processor handle + * @param algorithm MAC algorithm to use for MAC calculation + * @param keyHandle key to use for the MAC calculation + * @param macHandle output MAC calculator handle + * + * @return The status of the operation + */ +Sec_Result SecMac_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm algorithm, + Sec_KeyHandle* keyHandle, Sec_MacHandle** macHandle); + +/** + * @brief Updates the digest value with the input data + * + * @param macHandle mac handle + * @param input pointer to the input data + * @param size of the input buffer + * + * @return The status of the operation + */ +Sec_Result SecMac_Update(Sec_MacHandle* macHandle, SEC_BYTE* input, SEC_SIZE inputSize); + +/** + * @brief Updates the digest value with the contents of a key + * + * @param macHandle mac handle + * @param keyHandle key to use + * + * @return The status of the operation + */ +Sec_Result SecMac_UpdateWithKey(Sec_MacHandle* macHandle, Sec_KeyHandle* keyHandle); + +/** + * @brief Calculate the resulting MAC value and release the MAC object + * + * @param macHandle mac handle + * @param macBuffer pointer to an output buffer that will be filled with the resulting + * MAC value. Buffer should be SEC_MAC_MAX_LEN bytes long. + * @param macSize pointer to a value that will be set to actual size of the MAC value + * + * @return The status of the operation + */ +Sec_Result SecMac_Release(Sec_MacHandle* macHandle, SEC_BYTE* macBuffer, SEC_SIZE* macSize); + +/** + * @brief Obtain a handle to the random number generator + * + * @param processorHandle secure processor handle + * @param algorithm random number algorithm to use + * @param randomHandle output handle for the random number generator + * + * @return The status of the operation + */ +Sec_Result SecRandom_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_RandomAlgorithm algorithm, + Sec_RandomHandle** randomHandle); + +/** + * @brief Generate random data + * + * @param randomHandle random number generator handle + * @param output pointer to the output buffer where the random data will be stored + * @param outpuSize the size of the output buffer + * + * @return The status of the operation + */ +Sec_Result SecRandom_Process(Sec_RandomHandle* randomHandle, SEC_BYTE* output, SEC_SIZE outputSize); + +/** + * @brief Release the random object + * + * @param randomHandle random handle + * + * @return The status of the operation + */ +Sec_Result SecRandom_Release(Sec_RandomHandle* randomHandle); + +/** + * @brief Obtain a handle to the provisioned certificate + * + * @param processorHandle secure processor handle + * @param object_id id of the certificate + * @param certHandle output certificate handle + * + * @return The status of the operation + */ +Sec_Result SecCertificate_GetInstance(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_CertificateHandle** certHandle); + +/** + * @brief Provision a certificate onto the system + * + * @param processorHandle secure processor handle + * @param object_id id of the certificate to provision + * @param location location where the certificate should be provisioned to + * @param data_type container type for the input certificate data + * @param data pointer to certificate container data + * @param data_len certificate container data length + * + * @return The status of the operation + */ +Sec_Result SecCertificate_Provision(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_StorageLoc location, Sec_CertificateContainer data_type, SEC_BYTE* data, SEC_SIZE data_len); + +/** + * @brief Delete the specified certificate from the system + * + * @param processorHandle secure processor handle + * @param object_id id of the certificate to delete + * + * @return The status of the operation + */ +Sec_Result SecCertificate_Delete(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id); + +/** + * @brief Extract the RSA public key information from the certificate + * + * @param certificateHandle certificate handle + * @param public_key pointer to the output structure that will be filled with + * public key data + * + * @return The status of the operation + */ +Sec_Result SecCertificate_ExtractRSAPublicKey(Sec_CertificateHandle* certificateHandle, + Sec_RSARawPublicKey* public_key); + +/** + * @brief Extract the ECC public key information from the certificate + * + * @param certificateHandle certificate handle + * @param public_key pointer to the output structure that will be filled with + * public key data + * + * @return The status of the operation + */ +Sec_Result SecCertificate_ExtractECCPublicKey(Sec_CertificateHandle* certificateHandle, + Sec_ECCRawPublicKey* public_key); + +/** + * @brief Verify certificate signature + * + * @param certificateHandle certificate handle + * @param key_handle handle of the private key used for signing or it's corresponding + * public key + * + * @return The status of the operation + */ +Sec_Result SecCertificate_Verify(Sec_CertificateHandle* certificateHandle, Sec_KeyHandle* keyHandle); + +/** + * @brief Verify certificate signature + * + * @param certificateHandle certificate handle + * @param public_key structure holding the public key information + * + * @return The status of the operation + */ +Sec_Result SecCertificate_VerifyWithRawRSAPublicKey(Sec_CertificateHandle* certificateHandle, + Sec_RSARawPublicKey* public_key); + +/** + * @brief Verify certificate signature - ECC + * + * @param certificateHandle certificate handle + * @param public_key structure holding the public key information + * + * @return The status of the operation + */ +Sec_Result SecCertificate_VerifyWithRawECCPublicKey(Sec_CertificateHandle* certificateHandle, + Sec_ECCRawPublicKey* public_key); + +/** + * @brief Obtain the certificate data in clear text DER format + * + * @param certificateHandle certificate handle + * @param buffer pointer to the output buffer that will be filled with certificate data + * @param buffer_len the length of the output buffer + * @param written pointer to the output value specifying the number of bytes written to the + * output buffer + * + * @return The status of the operation + */ +Sec_Result SecCertificate_Export(Sec_CertificateHandle* certificateHandle, SEC_BYTE* buffer, SEC_SIZE buffer_len, + SEC_SIZE* written); + +/** + * @brief Release the certificate object + * + * @param certificateHandle certificate handle + * + * @return The status of the operation + */ +Sec_Result SecCertificate_Release(Sec_CertificateHandle* certificateHandle); + +/** + * @brief Obtain a list of all provisioned items. At most maxNumItems will be written to the output buffer. + * + * @param proc Secure processor handle + * @param items buffer that the found item ids will be stored in + * @param maxNumItems maximum number of items that can be written to the output buffer + * + * @return number of items written + */ +SEC_SIZE SecCertificate_List(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID* items, SEC_SIZE maxNumItems); + +/** + * @brief Get the properties for the key handle. + * + * @param keyHandle pointer to Sec_KeyHandle + * @param keyProps pointer to Sec_KeyProperties where information is stored. + */ +Sec_Result SecKey_GetKeyProperties(Sec_KeyHandle* keyHandle, Sec_KeyProperties* keyProps); + +/** + * @brief Get the length of the specified key in bytes + * + * In case of symetric keys, the length returned is the actual size of the key data. + * In case of asymetric keys, the length returned is the size of the modulus in bytes. + * + * @param keyHandle key handle + * + * @return The status of the operation + */ +SEC_SIZE SecKey_GetKeyLen(Sec_KeyHandle* keyHandle); + +/** + * @brief Get the key type of the specified key handle + * + * @param keyHandle key handle + * + * @return The key type or SEC_KEYTYPE_NUM if the key handle is invalid + */ +Sec_KeyType SecKey_GetKeyType(Sec_KeyHandle* keyHandle); + +/** + * @brief Obtain a handle to a provisioned key + * + * @param processorHandle secure processor handle + * @param object_id id of the provisioned key that we are attempting to abtain + * @param keyHandle pointer to the output key handle + * + * @return The status of the operation + */ +Sec_Result SecKey_GetInstance(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_KeyHandle** keyHandle); + +/** + * @brief Extract an RSA public key from a specified private key handle + * + * @param key_handle handle of the private key + * @param public_key pointer to the output structure containing the public rsa key + * + * @return The status of the operation + */ +Sec_Result SecKey_ExtractRSAPublicKey(Sec_KeyHandle* keyHandle, Sec_RSARawPublicKey* public_key); + +/** + * @brief Extract an ECC public key from a specified private key handle + * + * @param key_handle handle of the private key + * @param public_key pointer to the output structure containing the public ecc key + * + * @return The status of the operation + */ +Sec_Result SecKey_ExtractECCPublicKey(Sec_KeyHandle* keyHandle, Sec_ECCRawPublicKey* public_key); + +/** + * @brief Generate and provision a new key. + * + * @param processorHandle secure processor handle + * @param object_id id of the key to generate + * @param keyType type of the key to generate + * @param location location where the key should be stored + * + * @return The status of the operation + */ +Sec_Result SecKey_Generate(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_KeyType keyType, + Sec_StorageLoc location); + +/** + * @brief Provision a key + * + * @param processorHandle secure processor handle + * @param object_id id of the key to provision + * @param location storage location where the key should be provisioned + * @param data_type type of input key container that is being used + * @param data pointer to the input key container + * @param data_len the size of the input key container + * + * @return The status of the operation + */ +Sec_Result SecKey_Provision(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_StorageLoc location, + Sec_KeyContainer data_type, SEC_BYTE* data, SEC_SIZE data_len); + +/** + * @brief Derive and provision a key using the HKDF algorithm + * + * @param processorHandle secure processor handle + * @param object_id_derived id of the key to provision + * @param type_derived derived key type + * @param loc_derived storage location where the derived key should be provisioned + * @param macAlgorithm mac algorithm to use in the key derivation process + * @param salt pointer to the salt value to use in key derivation process + * @param saltSize the length of the salt buffer in bytes + * @param info pointer to the info value to use in key derivation process + * @param infoSize the length of the info buffer in bytes + * + * @return The status of the operation + */ +Sec_Result SecKey_Derive_HKDF(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_KeyType type_derived, Sec_StorageLoc loc_derived, Sec_MacAlgorithm macAlgorithm, SEC_BYTE* nonce, + SEC_BYTE* salt, SEC_SIZE saltSize, SEC_BYTE* info, SEC_SIZE infoSize); + +/** + * @brief Derive and provision a key using the Concat KDF algorithm + * + * @param processorHandle secure processor handle + * @param object_id_derived id of the key to provision + * @param type_derived derived key type + * @param loc_derived storage location where the derived key should be provisioned + * @param digestAlgorithm digest algorithm to use in the key derivation process + * @param otherInfo pointer to the info value to use in key derivation process + * @param otherInfoSize the length of the other info buffer in bytes + * + * @return The status of the operation + */ +Sec_Result SecKey_Derive_ConcatKDF(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_KeyType type_derived, Sec_StorageLoc loc_derived, Sec_DigestAlgorithm digestAlgorithm, SEC_BYTE* nonce, + SEC_BYTE* otherInfo, SEC_SIZE otherInfoSize); + +/** + * @brief Derive and provision an AES 128-bit key a vendor specific key ladder algorithm. + * + * This function will generate a key derived from one of the OTP keys. The + * result of this function may not be usable in Digest and Mac _UpdateWithKey + * functions. In general, this function will keep the derived key more secure + * then the other SecKey_Derive functions because the key will not be accessable + * by the host even during the generation time. + * + * @param processorHandle secure processor handle + * @param object_id_derived id of the key to provision + * @param loc_derived storage location where the derived key should be provisioned + * @param input input buffer for the key derivation + * @param input_len the length of the input buffer + * + * @return The status of the operation + */ +Sec_Result SecKey_Derive_VendorAes128(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_StorageLoc loc_derived, SEC_BYTE* input, SEC_SIZE input_len); + +/** + * @brief Derive and provision an AES 128-bit key. + * + * This function will generate a key derived from one of the OTP keys. The + * result of this function may not be usable in Digest and Mac _UpdateWithKey + * functions. In general, this function will keep the derived key more secure + * then the other SecKey_Derive functions because the key will not be accessable + * by the host even during the generation time. + * + * @param processorHandle secure processor handle + * @param object_id_derived id of the key to provision + * @param type_derived derived key type + * @param loc_derived storage location where the derived key should be provisioned + * @param input1 16 byte input for stage 1 of the key ladder + * @param input2 16 byte input for stage 2 of the key ladder + * @param input3 16 byte input for stage 3 of the key ladder + * @param input4 16 byte input for stage 4 of the key ladder + * + * @return The status of the operation + */ +Sec_Result SecKey_Derive_KeyLadderAes128(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_StorageLoc loc_derived, Sec_KeyLadderRoot root, SEC_BYTE* input1, SEC_BYTE* input2, SEC_BYTE* input3, + SEC_BYTE* input4); + +Sec_Result SecKey_Derive_CMAC_AES128(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID idDerived, + Sec_KeyType typeDerived, Sec_StorageLoc locDerived, SEC_OBJECTID derivationKey, SEC_BYTE* otherData, + SEC_SIZE otherDataSize, SEC_BYTE* counter, SEC_SIZE counterSize); + +/** + * @brief Delete a provisioned key + * + * @param processorHandle secure processor handle + * @param object_id id of the key to delete + * + * @return The status of the operation + */ +Sec_Result SecKey_Delete(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id); + +/** + * @brief Release the key object + * + * @param keyHandle key handle to release + * + * @return The status of the operation + */ +Sec_Result SecKey_Release(Sec_KeyHandle* keyHandle); + +/** + * @brief Obtain a digest value computed over the base key contents + * + * @param processorHandle secure processor handle + * @param nonce client nonce + * @param alg digest algorithm + * @param digest output digest value + * @param digest_len the length of output digest value + * + * @return status of the operation + */ +Sec_Result SecKey_ComputeBaseKeyDigest(Sec_ProcessorHandle* processorHandle, SEC_BYTE* nonce, Sec_DigestAlgorithm alg, + SEC_BYTE* digest, SEC_SIZE* digest_len); + +/** + * @brief Obtain a processor handle + * + * @param keyHandle key handle + * + * @return Processor handle + */ +Sec_ProcessorHandle* SecKey_GetProcessor(Sec_KeyHandle* keyHandle); + +/** + * @brief Generates a shared symmetric key and stores it in a specified location. + * + * A shared secret is calculated using the ECDH algorithm. The shared + * secret is converted to a key using the Concat KDF (SP800-56A Section + * 5.8.1). If the key with the same id already exists, the call will + * overwrite the existing key with the new key. SHA-256 is the digest + * algorithm. + * + * @param keyHandle Handle of my private ECC key + * @param otherPublicKey Public key for other party in key agreement + * @param type_derived Type of key to generate. Only symmetric keys can be derived + * @param id_derived 64-bit object id identifying the key to be generated + * @param loc_id Location where the resulting key will be stored + * @param digestAlgorithm Digest algorithm to use in KDF (typically SEC_DIGESTALGORITHM_SHA256) + * @param otherInfo Input keying material + * AlgorithmID || PartyUInfo || PartyVInfo {|| SuppPubInfo }{|| SuppPrivInfo} + * @param otherInfoSize Size of otherInfo (in bytes) + */ +Sec_Result SecKey_ECDHKeyAgreementWithKDF(Sec_KeyHandle* keyHandle, Sec_ECCRawPublicKey* otherPublicKey, + Sec_KeyType type_derived, SEC_OBJECTID id_derived, Sec_StorageLoc loc_derived, Sec_Kdf kdf, + Sec_DigestAlgorithm digestAlgorithm, const SEC_BYTE* otherInfo, SEC_SIZE otherInfoSize); + +/** + * @brief Obtain a handle to a provisioned bundle + * + * @param processorHandle secure processor handle + * @param object_id id of the provisioned bundle that we are attempting to abtain + * @param bundleHandle pointer to the output key handle + * + * @return The status of the operation + */ +Sec_Result SecBundle_GetInstance(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_BundleHandle** bundleHandle); + +/** + * @brief Provision a bundle + * + * @param processorHandle secure processor handle + * @param object_id id of the bundle to provision + * @param location storage location where the bundle should be provisioned + * @param data pointer to the input key container + * @param data_len the size of the input key container + * + * @return The status of the operation + */ +Sec_Result SecBundle_Provision(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_StorageLoc location, + SEC_BYTE* data, SEC_SIZE data_len); + +/** + * @brief Delete a provisioned bundle + * + * @param processorHandle secure processor handle + * @param object_id id of the key to delete + * + * @return The status of the operation + */ +Sec_Result SecBundle_Delete(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id); + +/** + * @brief Release the bundle object + * + * @param bundleHandle bundle handle to release + * + * @return The status of the operation + */ +Sec_Result SecBundle_Release(Sec_BundleHandle* bundleHandle); + +/** + * @brief Obtain the bundle data + * + * @param bundleHandle bundle handle + * @param buffer pointer to the output buffer that will be filled with bundle data + * @param buffer_len the length of the output buffer + * @param written pointer to the output value specifying the number of bytes written to the + * output buffer + * + * @return The status of the operation + */ +Sec_Result SecBundle_Export(Sec_BundleHandle* bundleHandle, SEC_BYTE* buffer, SEC_SIZE buffer_len, SEC_SIZE* written); + +/** + * @brief Allocate platform specific memory optimized for encryption/decryption. Used + * With SEC_CIPHERMODE_ENCRYPT_NATIVEMEM and SEC_CIPHERMODE_DECRYPT_NATIVEMEM + */ +SEC_BYTE* Sec_NativeMalloc(Sec_ProcessorHandle* processorHandle, SEC_SIZE length); + +/** + * @brief Free memory allocated with Sec_NativeMalloc + */ +void Sec_NativeFree(Sec_ProcessorHandle* processorHandle, void* ptr); + +Sec_Result SecCipher_ProcessCtrWithDataShift(Sec_CipherHandle* cipherHandle, SEC_BYTE* input, SEC_SIZE inputSize, + SEC_BYTE* output, SEC_SIZE outputSize, SEC_SIZE* bytesWritten, SEC_SIZE dataShift); + +Sec_Result SecKey_ExportKey(Sec_KeyHandle* keyHandle, SEC_BYTE* derivationInput, SEC_BYTE* exportedKey, + SEC_SIZE keyBufferLen, SEC_SIZE* keyBytesWritten); + +Sec_Result SecKey_GetProperties(Sec_KeyHandle* keyHandle, Sec_KeyProperties* keyProperties); + +/** + * @brief Checks secure boot configuration to verify that Secure Boot is enabled. + */ +Sec_Result SecCodeIntegrity_SecureBootEnabled(void); + +Sec_Result SecSVP_SetTime(time_t time); + +/* 2.2 */ +Sec_Result Sec_OpaqueBufferMalloc(SEC_SIZE bufLength, void** handle, void* params) + __attribute__((deprecated)); + +Sec_Result Sec_OpaqueBufferWrite(Sec_OpaqueBufferHandle* opaqueBufferHandle, SEC_SIZE offset, void* data, + SEC_SIZE length) __attribute__((deprecated)); + +Sec_Result Sec_OpaqueBufferFree(Sec_OpaqueBufferHandle* opaqueBufferHandle, void* params) __attribute__((deprecated)); + +Sec_Result SecOpaqueBuffer_Malloc(SEC_SIZE bufLength, Sec_OpaqueBufferHandle** handle); + +Sec_Result SecOpaqueBuffer_Write(Sec_OpaqueBufferHandle* opaqueBufferHandle, SEC_SIZE offset, SEC_BYTE* data, + SEC_SIZE length); + +Sec_Result SecOpaqueBuffer_Free(Sec_OpaqueBufferHandle* opaqueBufferHandle); + +Sec_Result SecOpaqueBuffer_Release(Sec_OpaqueBufferHandle* opaqueBufferHandle, Sec_ProtectedMemHandle** svpHandle); + +Sec_Result SecOpaqueBuffer_Copy(Sec_OpaqueBufferHandle* outOpaqueBufferHandle, SEC_SIZE out_offset, + Sec_OpaqueBufferHandle* inOpaqueBufferHandle, SEC_SIZE in_offset, SEC_SIZE num_to_copy); + +Sec_Result SecOpaqueBuffer_Check(Sec_DigestAlgorithm digestAlgorithm, Sec_OpaqueBufferHandle* opaqueBufferHandle, + SEC_SIZE length, SEC_BYTE* expected, SEC_SIZE expectedLength); + +Sec_Result SecKeyExchange_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_KeyExchangeAlgorithm exchangeType, + void* exchangeParameters, Sec_KeyExchangeHandle** keyExchangeHandle); + +Sec_Result SecKeyExchange_GenerateKeys(Sec_KeyExchangeHandle* keyExchangeHandle, SEC_BYTE* publicKey, + SEC_SIZE pubKeySize); + +Sec_Result SecKeyExchange_ComputeSecret(Sec_KeyExchangeHandle* keyExchangeHandle, SEC_BYTE* otherPublicKey, + SEC_SIZE otherPublicKeySize, Sec_KeyType typeComputed, SEC_OBJECTID idComputed, Sec_StorageLoc locComputed); + +Sec_Result SecKeyExchange_Release(Sec_KeyExchangeHandle* keyExchangeHandle); + +Sec_Result SecKey_Derive_BaseKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID idDerived, Sec_KeyType key_type, + Sec_StorageLoc loc, SEC_BYTE* nonce); + +Sec_Result SecKey_Derive_HKDF_BaseKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID idDerived, + Sec_KeyType typeDerived, Sec_StorageLoc locDerived, Sec_MacAlgorithm macAlgorithm, SEC_BYTE* salt, + SEC_SIZE saltSize, SEC_BYTE* info, SEC_SIZE infoSize, SEC_OBJECTID baseKeyId); + +Sec_Result SecKey_Derive_ConcatKDF_BaseKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID idDerived, + Sec_KeyType typeDerived, Sec_StorageLoc locDerived, Sec_DigestAlgorithm digestAlgorithm, SEC_BYTE* otherInfo, + SEC_SIZE otherInfoSize, SEC_OBJECTID baseKeyId); + +typedef struct { + SEC_SIZE clear; + SEC_SIZE encrypted; +} SEC_MAP; + +Sec_Result SecCipher_ProcessOpaqueWithMap(Sec_CipherHandle* cipherHandle, SEC_BYTE* iv, SEC_BYTE* input, + SEC_SIZE inputSize, SEC_BOOL lastInput, SEC_MAP* map, SEC_SIZE mapLength, Sec_OpaqueBufferHandle** outputHandle, + SEC_SIZE* bytesWritten); + +#ifdef __cplusplus +} +#endif + +#endif /* SEC_SECURITY_H */ diff --git a/include/sec_security_asn1kc.h b/include/sec_security_asn1kc.h new file mode 100644 index 0000000..9419157 --- /dev/null +++ b/include/sec_security_asn1kc.h @@ -0,0 +1,113 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_COMMON_17 + +#ifndef SEC_SECURITY_ASN1KC_H +#define SEC_SECURITY_ASN1KC_H + +#include "sec_security_datatype.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Opaque certificate handle + * + */ +#define ASN1KCATTRIBUTE_T_CHOICE_INTEGER 0 +#define ASN1KCATTRIBUTE_T_CHOICE_BITSTRING 1 +#define ASN1KCATTRIBUTE_T_CHOICE_OCTETSTRING 2 +#define ASN1KCATTRIBUTE_T_CHOICE_NULL 3 +#define ASN1KCATTRIBUTE_T_CHOICE_IA5STRING 4 +#define ASN1KCATTRIBUTE_T_CHOICE_UTCTIME 5 + +typedef struct { + int type; + union { + ASN1_INTEGER* integer; + ASN1_BIT_STRING* bitstring; + ASN1_OCTET_STRING* octetstring; + ASN1_NULL* null; + ASN1_IA5STRING* ia5string; + ASN1_UTCTIME* utctime; + } c; +} Asn1KCAttribute_t_c; + +typedef struct { + ASN1_IA5STRING* name; + Asn1KCAttribute_t_c* value; +} Asn1KCAttribute_t; + +typedef STACK_OF(Asn1KCAttribute_t) Sec_Asn1KC; +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DECLARE_STACK_OF(Asn1KCAttribute_t); +#define sk_Asn1KCAttribute_t_push(st, val) SKM_sk_push(Asn1KCAttribute_t, st, val) +#define sk_Asn1KCAttribute_t_value(st, i) SKM_sk_value(Asn1KCAttribute_t, st, i) +#define sk_Asn1KCAttribute_t_num(st) SKM_sk_num(Asn1KCAttribute_t, st) +#else +DEFINE_STACK_OF(Asn1KCAttribute_t); // NOLINT +#endif + +Sec_Asn1KC* SecAsn1KC_Alloc(); + +void SecAsn1KC_Free(Sec_Asn1KC* kc); + +Sec_Result SecAsn1KC_Encode(Sec_Asn1KC* kc, SEC_BYTE* buf, SEC_SIZE buf_len, SEC_SIZE* written); + +Sec_Asn1KC* SecAsn1KC_Decode(const SEC_BYTE* buf, SEC_SIZE buf_len); + +SEC_BOOL SecAsn1KC_HasAttr(Sec_Asn1KC* kc, const char* key); + +Sec_Result SecAsn1KC_AddAttrUlong(Sec_Asn1KC* kc, const char* key, uint64_t val); + +Sec_Result SecAsn1KC_AddAttrUint64(Sec_Asn1KC* kc, const char* key, uint64_t val); + +Sec_Result SecAsn1KC_AddAttrLong(Sec_Asn1KC* kc, const char* key, int64_t val); + +Sec_Result SecAsn1KC_AddAttrInt64(Sec_Asn1KC* kc, const char* key, int64_t val); + +Sec_Result SecAsn1KC_AddAttrString(Sec_Asn1KC* kc, const char* key, const char* val); + +Sec_Result SecAsn1KC_AddAttrBuffer(Sec_Asn1KC* kc, const char* key, void* buf, SEC_SIZE buf_len); + +Sec_Result SecAsn1KC_GetAttrUlong(Sec_Asn1KC* kc, const char* key, uint64_t* val); + +Sec_Result SecAsn1KC_GetAttrUint64(Sec_Asn1KC* kc, const char* key, uint64_t* val); + +Sec_Result SecAsn1KC_GetAttrLong(Sec_Asn1KC* kc, const char* key, int64_t* val); + +Sec_Result SecAsn1KC_GetAttrInt64(Sec_Asn1KC* kc, const char* key, int64_t* val); + +Sec_Result SecAsn1KC_GetAttrBuffer(Sec_Asn1KC* kc, const char* key, SEC_BYTE* buffer, SEC_SIZE buffer_len, + SEC_SIZE* written); + +Sec_Result SecAsn1KC_GetAttrString(Sec_Asn1KC* kc, const char* key, char* buffer, SEC_SIZE buffer_len, + SEC_SIZE* written); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/include/sec_security_comcastids.h b/include/sec_security_comcastids.h new file mode 100644 index 0000000..0ca5113 --- /dev/null +++ b/include/sec_security_comcastids.h @@ -0,0 +1,123 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_SECURITY_COMCASTIDS_H +#define SEC_SECURITY_COMCASTIDS_H + +#include "sec_security_datatype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* adobe reserved space */ +#define SEC_OBJECTID_ADOBE_TOP 0xffffffffffff0400ULL +#define SEC_OBJECTID_ADOBE_BASE 0xffffffffffff0000ULL + +/* comcast object ids */ +#define SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY 0xffffffff00000001ULL +#define SEC_OBJECTID_COMCAST_XCALSESSIONMACKEYTOKEN 0xffffffff00000002ULL +#define SEC_OBJECTID_COMCAST_SOCIDPHMACKEY 0xffffffff00000003ULL +#define SEC_OBJECTID_COMCAST_XCALSESSIONCONTEXTTOKEN 0xffffffff00000004ULL +#define SEC_OBJECTID_COMCAST_CIMAACCTTOKEN 0xffffffff00000005ULL +#define SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY_HASH 0xffffffff00000006ULL +#define SEC_OBJECTID_COMCAST_XCALSESSIONMACKEYTOKEN_HASH 0xffffffff00000007ULL +#define SEC_OBJECTID_COMCAST_FKPSRT_MANIFEST 0xffffffff00000008ULL +#define SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY 0xffffffff00000009ULL +#define SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY_HASH 0xffffffff0000000aULL + +#define SEC_OBJECTID_COMCAST_SGNCERT 0x0111000001110001ULL +#define SEC_OBJECTID_COMCAST_SGNSUBCACERT 0x0111000001110002ULL +#define SEC_OBJECTID_COMCAST_SGNROOTCACERT 0x0111000001110003ULL +#define SEC_OBJECTID_COMCAST_ENCCERT 0x0111000001110004ULL +#define SEC_OBJECTID_COMCAST_ENCSUBCACERT 0x0111000001110005ULL +#define SEC_OBJECTID_COMCAST_ENCROOTCACERT 0x0111000001110006ULL +#define SEC_OBJECTID_COMCAST_TLSCERT 0x0111000001110007ULL +#define SEC_OBJECTID_COMCAST_TLSSUBCACERT 0x0111000001110008ULL +#define SEC_OBJECTID_COMCAST_TLSROOTCACERT 0x0111000001110009ULL +#define SEC_OBJECTID_COMCAST_KEKCERT 0x011100000111000AULL +#define SEC_OBJECTID_COMCAST_CERTCA01CERT 0x0211000002110001ULL +#define SEC_OBJECTID_COMCAST_STATUSCA01CERT 0x0211000002110002ULL +#define SEC_OBJECTID_COMCAST_SGNKEY 0x0311000003110001ULL +#define SEC_OBJECTID_COMCAST_ENCKEY 0x0311000003110002ULL +#define SEC_OBJECTID_COMCAST_TLSKEY 0x0311000003110003ULL +#define SEC_OBJECTID_COMCAST_TRANSFORMKEY 0x0311000003110004ULL +#define SEC_OBJECTID_COMCAST_KEKKEY 0x0311000003110005ULL +#define SEC_OBJECTID_COMCAST_PKIBUNDLE 0x0511000005110001ULL +#define SEC_OBJECTID_COMCAST_BRCM_OTP 0x0611000006110003ULL +#define SEC_OBJECTID_COMCAST_HASHLOCKED 0x0711000007110001ULL +#define SEC_OBJECTID_COMCAST_SECUREDRM 0x0711000007110004ULL + +/* adobe object ids */ +#define SEC_OBJECTID_ADOBE_DRMMODELSGNKEY 0x0321000003254030ULL /* temp id - will change */ +#define SEC_OBJECTID_ADOBE_DRMMODELSGNCERT 0x0121000001210012ULL /* temp id - will change */ +#define SEC_OBJECTID_ADOBE_DRMMODELENCKEY 0x0321000003264030ULL /* temp id - will change */ +#define SEC_OBJECTID_ADOBE_DRMMODELENCCERT 0x0121000001210013ULL /* temp id - will change */ +#define SEC_OBJECTID_ADOBE_DRMMODELKEY 0x0321000003214030ULL +#define SEC_OBJECTID_ADOBE_DRMMODELCERT 0x0121000001210001ULL +#define SEC_OBJECTID_ADOBE_DRMMODELINTERMEDIATERUNTIMEDRMCACERT 0x0121000001210002ULL +#define SEC_OBJECTID_ADOBE_DRMMODELINTERMEDIATECACERT 0x0121000001210003ULL +#define SEC_OBJECTID_ADOBE_DRMMODELROOTCACERT 0x0121000001210004ULL +#define SEC_OBJECTID_ADOBE_SD01CERT 0x0121000001210005ULL +#define SEC_OBJECTID_ADOBE_SD01INTERMEDIATERUNTIMEDRMCACERT 0x0121000001210006ULL +#define SEC_OBJECTID_ADOBE_SD01INTERMEDIATECACERT 0x0121000001210007ULL +#define SEC_OBJECTID_ADOBE_SD01ROOTCACERT 0x0121000001210008ULL +#define SEC_OBJECTID_ADOBE_SD02CERT 0x0121000001210009ULL +#define SEC_OBJECTID_ADOBE_SD02INTERMEDIATERUNTIMEDRMCACERT 0x012100000121000AULL +#define SEC_OBJECTID_ADOBE_SD02INTERMEDIATECACERT 0x012100000121000BULL +#define SEC_OBJECTID_ADOBE_SD02ROOTCACERT 0x012100000121000CULL +#define SEC_OBJECTID_ADOBE_SD03CERT 0x012100000121000DULL +#define SEC_OBJECTID_ADOBE_SD03INTERMEDIATERUNTIMEDRMCACERT 0x012100000121000EULL +#define SEC_OBJECTID_ADOBE_SD03INTERMEDIATECACERT 0x012100000121000FULL +#define SEC_OBJECTID_ADOBE_SD03ROOTCACERT 0x0121000001210010ULL +#define SEC_OBJECTID_ADOBE_INDIVTRANSPORTCERT 0x0121000001210011ULL +#define SEC_OBJECTID_ADOBE_SD01KEY 0x0321000003224030ULL +#define SEC_OBJECTID_ADOBE_SD02KEY 0x0321000003234030ULL +#define SEC_OBJECTID_ADOBE_SD03KEY 0x0321000003244030ULL +#define SEC_OBJECTID_ADOBE_TRANSFORMKEY 0x0321000003254030ULL +#define SEC_OBJECTID_ADOBE_PRODADOBEROOTDIGEST 0x0421000004210001ULL +#define SEC_OBJECTID_ADOBE_DRMPKI 0x0621000006210001ULL +#define SEC_OBJECTID_ADOBE_DRMPKI_ENHANCED 0x0621000006210002ULL + +#define SEC_OBJECTID_PLAYREADY_MODELCERT 0x0631000006310001ULL +#define SEC_OBJECTID_PLAYREADY_MODELKEY 0x0331000003310001ULL + +#define SEC_OBJECTID_WV_KEY 0x0351000003510001ULL +#define SEC_OBJECTID_WV_CERTBUNDLE 0x0651000006510001ULL + +#define SEC_OBJECTID_COMCAST_BRCM_DRMBIN 0x0611000006110004ULL + +//service manager keys +#define SEC_OBJECTID_CW_NETFLIX_STORAGE_KEY 0x0361000003610001ULL +#define SEC_OBJECTID_CW_YOUTUBE_STORAGE_KEY 0x0361000003610002ULL +#define SEC_OBJECTID_CW_HLU_STORAGE_KEY 0x0361000003610003ULL + +#define SEC_FKPSTYPE_CERTIFICATE 0x01 +#define SEC_FKPSTYPE_CACERTIFICATE 0x02 +#define SEC_FKPSTYPE_KEYCONTAINER 0x03 +#define SEC_FKPSTYPE_MESSAGEDIGEST 0x04 +#define SEC_FKPSTYPE_PKIBUNDLE 0x05 +#define SEC_FKPSTYPE_DRMPKIBUNDLE 0x06 +#define SEC_FKPSTYPE_HASHLOCKED 0x07 +#define SEC_FKPSTYPE_RESERVED 0xFF + +#ifdef __cplusplus +} +#endif + +#endif /* SEC_SECURITY_COMCASTIDS_H */ diff --git a/include/sec_security_common.h b/include/sec_security_common.h new file mode 100644 index 0000000..4bd6bf9 --- /dev/null +++ b/include/sec_security_common.h @@ -0,0 +1,767 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file sec_security_common.h + * + * @brief Common functions used by all platform implementations + * + */ + +#ifndef SEC_SECURITY_COMMON_H +#define SEC_SECURITY_COMMON_H + +#include "sec_security_datatype.h" + +#ifndef SEC_COMMON_17 + +#include "sec_security_asn1kc.h" + +#endif + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Buffer information structure + */ +typedef struct { + SEC_BYTE* base; + SEC_SIZE size; + SEC_SIZE written; +} Sec_Buffer; + +/** + * @brief initialize the Sec_Buffer structure + * + * @param buffer Sec_Buffer structure to initialize + * @param mem memory buffer to use + * @param len size of the memory buffer + */ +void SecBuffer_Init(Sec_Buffer* buffer, void* mem, SEC_SIZE len); + +/** + * @brief reset the buffer + * + * @param buffer Sec_Buffer structure to initialize + */ +void SecBuffer_Reset(Sec_Buffer* buffer); + +/** + * @brief Write data to a buffer + * + * @param buffer pointer to a Sec_Buffer structure to use + * @param data input data to write + * @param len length of input data + * + * @return Status of the operation. Error status will be returned if there + * is not enough space left in the output buffer. + */ +Sec_Result SecBuffer_Write(Sec_Buffer* buffer, void* data, SEC_SIZE len); + +typedef enum { + SEC_ENDIANESS_BIG, + SEC_ENDIANESS_LITTLE, + SEC_ENDIANESS_UNKNOWN +} Sec_Endianess; + +/** + * @brief Obtain chip endianess at runtime + */ +Sec_Endianess Sec_GetEndianess(void); + +/** + * @brief Convert big endian bytes to native uint32 + */ +uint32_t Sec_BEBytesToUint32(SEC_BYTE* bytes); + +/** + * @brief Convert big endian bytes to native uint64 + */ +uint64_t Sec_BEBytesToUint64(SEC_BYTE* bytes); + +/** + * @brief Convert native uint32 to big endian bytes + */ +void Sec_Uint32ToBEBytes(uint32_t val, SEC_BYTE* bytes); + +/** + * @brief Convert native uint64 to big endian bytes + */ +void Sec_Uint64ToBEBytes(uint64_t val, SEC_BYTE* bytes); + +/** + * @brief Endian swap + */ +uint16_t Sec_EndianSwap_uint16(uint16_t val); + +/** + * @brief Endian swap + */ +int16_t Sec_EndianSwap_int16(int16_t val); + +/** + * @brief Endian swap + */ +uint32_t Sec_EndianSwap_uint32(uint32_t val); + +/** + * @brief Endian swap + */ +int32_t Sec_EndianSwap_int32(int32_t val); + +/** + * @brief Endian swap + */ +int64_t Sec_EndianSwap_int64(int64_t val); + +/** + * @brief Endian swap + */ +uint64_t Sec_EndianSwap_uint64(uint64_t val); + +/** + * @brief memcmp replacement with constant time runtime + */ +int Sec_Memcmp(const void* ptr1, const void* ptr2, size_t num); + +/** + * @brief memset replacement that cannot be optimized out + */ +void* Sec_Memset(void* ptr, int value, size_t num); + +/** + * @brief Check whether the mode is any form of encrypt + * + * @param mode cipher mode + * + * @return 1 if encrypt, else 0 + */ +int SecCipher_IsModeEncrypt(Sec_CipherMode mode); + +/** + * @brief Check whether the mode is any form of decrypt + * + * @param mode cipher mode + * + * @return 1 if decrypt, else 0 + */ +int SecCipher_IsModeDecrypt(Sec_CipherMode mode); + +/** + * @brief Check whether the supplied key and iv are valid for the chosen cipher algorithm + * + * @param key_type key type + * @param algorithm cipher algorithm + * @param mode cipher mode + * @param iv initialization vector + * + * @return status of the call + */ +Sec_Result SecCipher_IsValidKey(Sec_KeyType key_type, Sec_CipherAlgorithm algorithm, Sec_CipherMode mode, + const SEC_BYTE* iv); + +SEC_BOOL SecCipher_IsCBC(Sec_CipherAlgorithm alg); + +/** + * @brief get the required output buffer size for the specified combination of input parameters + * + * Write required output buffer size for cipher configuration. + * Returns SEC_RESULT_SUCCESS if the cipher configuration parameters are valid. + * Returns SEC_RESULT_FAILURE otherwise (e.g. input size is not valid). + * + * @param algorithm cipher algorithm + * @param mode cipher mode + * @param keyType key type + * @param inputSize size of the input buffer + * @param outputSize size of the output buffer + * @param lastInput is this the last input to the cipher + * + * @return status of the call + */ +Sec_Result SecCipher_GetRequiredOutputSize(Sec_CipherAlgorithm algorithm, Sec_CipherMode mode, Sec_KeyType keyType, + SEC_SIZE inputSize, SEC_SIZE* outputSize, SEC_BOOL lastInput); + +/** + * @brief get the required output buffer length for fragemnted encryption/decryption + * + * @param algorithm cipher algorithm + * @param mode cipher mode + * @param keyType key type + * @param inputSize size of the input buffer + * @param outputSize size of the output buffer + * @param lastInput is this the last input to the cipher + * @param framentOffset offset in bytes of the fragment data within larger packet + * @param fragmentSize length in bytes of the data fragment + * @param fragmentPeriod the length in bytes of the packet containing the fragment + * + * @return status of the call + */ +Sec_Result SecCipher_GetRequiredOutputSizeFragmented(Sec_CipherAlgorithm algorithm, Sec_CipherMode mode, + Sec_KeyType keyType, SEC_SIZE inputSize, SEC_SIZE* outputSize, SEC_BOOL lastInput, SEC_SIZE fragmentOffset, + SEC_SIZE fragmentSize, SEC_SIZE fragmentPeriod); + +/** + * @brief Apply PKCS7 padding to the AES input block + * + * @param inputBlock input data to pad + * @param inputSize size of input data + * @param outputBlock Output block. Has to be the size of SEC_AES_BLOCKSIZE + */ +void SecCipher_PadAESPKCS7Block(SEC_BYTE* inputBlock, SEC_SIZE inputSize, SEC_BYTE* outputBlock); + +/** + * @brief Checks whether the specified cipher algorithm is AES + */ +SEC_BOOL SecCipher_IsAES(Sec_CipherAlgorithm alg); + +/** + * @brief Checks whether the specified cipher algorithm is RSA + */ +SEC_BOOL SecCipher_IsRsa(Sec_CipherAlgorithm alg); + +/** + * @brief Checks whether the specified cipher algorithm is ECC + */ +SEC_BOOL SecCipher_IsEcc(Sec_CipherAlgorithm alg); + +Sec_Result SecCipher_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_CipherAlgorithm alg, Sec_CipherMode mode, + Sec_KeyHandle* keyHandle, SEC_BYTE* iv, SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* output, + SEC_SIZE output_len, SEC_SIZE* written); + +Sec_Result SecCipher_SingleInputId(Sec_ProcessorHandle* processorHandle, Sec_CipherAlgorithm alg, Sec_CipherMode mode, + SEC_OBJECTID key, SEC_BYTE* iv, SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* output, SEC_SIZE output_len, + SEC_SIZE* written); + +SEC_BOOL SecCipher_IsPKCS7Padded(Sec_CipherAlgorithm algorithm); + +SEC_BOOL SecCipher_IsDecrypt(Sec_CipherMode mode); + +/** + * @brief Checks whether the passed in key is valid for a chosen signing algorithm and mode + * + * @param key_type key type + * @param algorithm signing algorithm + * @param mode signing mode + * + * @return status of the operation + */ +Sec_Result SecSignature_IsValidKey(Sec_KeyType key_type, Sec_SignatureAlgorithm algorithm, Sec_SignatureMode mode); + +/** + * @brief Returns TRUE if the signature algorithm is an RSA variant + * + * @param alg signing algorithm + * + * @return true if RSA + */ +SEC_BOOL SecSignature_IsRsa(Sec_SignatureAlgorithm alg); + +Sec_KeyType SecKey_GetRSAKeyTypeForBitLength(int numBits); + +Sec_KeyType SecKey_GetRSAKeyTypeForByteLength(int numBytes); + +/** + * @brief Returns TRUE if the signature algorithm is an ECC variant + * + * @param alg signing algorithm + * + * @return true if ECC + */ +SEC_BOOL SecSignature_IsEcc(Sec_SignatureAlgorithm alg); + +/** + * @brief Returns the size of the algorithm's ECC signature + * + * @param alg signing algorithm + * + * @return size in bytes or 0 if unsupported algorithm + */ +SEC_SIZE SecSignature_GetEccSignatureSize(Sec_SignatureAlgorithm alg); + +/** + * @brief Obtain a digest algorithm used by a specific signing algorithm + * + * @param alg signing algorithm + * + * @return digest algorithm used + */ +Sec_DigestAlgorithm SecSignature_GetDigestAlgorithm(Sec_SignatureAlgorithm alg); + +/** + * @brief Signature util that handles Sec_SignatureHandle generation and release + * + * @param processorHandle processor handle + * @param algorithm signing algorithm + * @param mode signing mode + * @param keyHandle key used for signing operations + * @param input pointer to the input buffer whose signature we are generating/verifying + * @param inputSize the length of the input + * @param signature buffer where signature is/will be stored + * @param signatureSize output variable that will be set to the signature size + * + * @return The status of the operation + */ +Sec_Result SecSignature_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, Sec_KeyHandle* keyHandle, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* signature, + SEC_SIZE* signatureSize); + +Sec_Result SecSignature_SingleInputCert(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, Sec_CertificateHandle* certificateHandle, SEC_BYTE* input, SEC_SIZE inputSize, + SEC_BYTE* signature, SEC_SIZE* signatureSize); + +Sec_Result SecSignature_SingleInputId(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, SEC_OBJECTID id, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* signature, + SEC_SIZE* signatureSize); + +Sec_Result SecSignature_SingleInputCertId(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, SEC_OBJECTID cert_id, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* signature, + SEC_SIZE* signatureSize); + +/** + * @brief Check whether the passed in key type is valid for a chosen MAC algorithm + * + * @param key_type key type + * @param algorithm MAC algorithm + * + * @return status of the operation + */ +Sec_Result SecMac_IsValidKey(Sec_KeyType key_type, Sec_MacAlgorithm algorithm); + +/** + * @brief Obtain a digest algorithm used by a specified MAC algorithm + * + * @param alg MAC algorithm + * + * @return digest algorithm used + */ +Sec_DigestAlgorithm SecMac_GetDigestAlgorithm(Sec_MacAlgorithm alg); + +Sec_Result SecMac_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm alg, Sec_KeyHandle* keyHandle, + SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* mac, SEC_SIZE* mac_len); + +Sec_Result SecMac_SingleInputId(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm alg, SEC_OBJECTID key, + SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* mac, SEC_SIZE* mac_len); + +/** + * @brief Checks if a passed in key type is symetric. + * + * @param type key type + * + * @return 1 if key type is symetric, 0 if asymetric + */ +SEC_BOOL SecKey_IsSymetric(Sec_KeyType type); + +/** + * @brief Checks if a passed in key type is an AES key. + * + * @param type key type + * + * @return 1 if key type is AES, 0 if not + */ +SEC_BOOL SecKey_IsAES(Sec_KeyType type); + +SEC_BOOL SecKey_IsHMAC(Sec_KeyType type); + +/** + * @brief Checks if a passed in key type is RSA + * + * @param type key type + * + * @return 1 if key type is rsa, 0 otherwise + */ +SEC_BOOL SecKey_IsRsa(Sec_KeyType type); + +/** + * @brief Checks if a passed in key type is pub RSA + * + * @param type key type + * + * @return 1 if key type is pub rsa, 0 otherwise + */ +SEC_BOOL SecKey_IsPubRsa(Sec_KeyType type); + +/** + * @brief Checks if a passed in key type is priv RSA + * + * @param type key type + * + * @return 1 if key type is priv rsa, 0 otherwise + */ +SEC_BOOL SecKey_IsPrivRsa(Sec_KeyType type); + +/** + * @brief Checks if a passed in key type is ECC + * + * @param type key type + * + * @return 1 if key type is priv ECC, 0 otherwise + */ +SEC_BOOL SecKey_IsEcc(Sec_KeyType type); + +/** + * @brief Checks if a passed in key type is priv ECC + * + * @param type key type + * + * @return 1 if key type is priv ECC, 0 otherwise + */ +SEC_BOOL SecKey_IsPrivEcc(Sec_KeyType type); + +/** + * @brief Checks if a passed in key type is pub ECC + * + * @param type key type + * + * @return 1 if key type is pub ECC, 0 otherwise + */ +SEC_BOOL SecKey_IsPubEcc(Sec_KeyType type); + +/** + * @brief Obtain a key length in bytes for a specified key type. + * + * For symetric keys, the return value will be the actual key size. For asymetric keys + * the return value will be the modulus size. + * + * @param keyType key type + * + * @return key size + */ +SEC_SIZE SecKey_GetKeyLenForKeyType(Sec_KeyType keyType); + +/** + * @brief Is the specified container a raw (clear) container + */ +SEC_BOOL SecKey_IsClearKeyContainer(Sec_KeyContainer kct); + +/** + * @brief Obtain a key container type for a specified key type + * + * @param key_type key type + * @return key container type + */ +Sec_KeyContainer SecKey_GetClearContainer(Sec_KeyType key_type); + +Sec_KeyType SecKey_GetKeyTypeForClearKeyContainer(Sec_KeyContainer kc); + +/** + * @brief Find if the key with a specific id has been provisioned + * + * @param processorHandle secure processor handle + * @param object_id id of the certificate + * + * @return 1 if an object has been provisioned, 0 if it has not been + */ +SEC_BOOL SecKey_IsProvisioned(Sec_ProcessorHandle* processorHandle, + SEC_OBJECTID object_id); + +/** + * @brief finds the first available key id in the range passed in + * + * @param proc secure processor + * @param base bottom of the range to search + * @param top top of the range to search + * @return + */ +SEC_OBJECTID SecKey_ObtainFreeObjectId(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID base, SEC_OBJECTID top); + +/** + * @brief Get the type (msd byte) of the object id + */ +uint8_t SecKey_GetObjectType(SEC_OBJECTID object_id); + +/** + * @brief Obtain a digest value computed over a specified key + * + * @param proc secure processor handle + * @param key_id key id + * @param alg digest algorithm to use + * @param digest output digest value + * @param digest_len size of the written digest value + * @return + */ +Sec_Result SecKey_ComputeKeyDigest(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID key_id, Sec_DigestAlgorithm alg, + SEC_BYTE* digest, SEC_SIZE* digest_len); + +/** + * @brief Obtain the size of the digest for a specified digest algorithm + * + * @param alg digest algorithm + * + * @return digest size in bytes + */ +SEC_SIZE SecDigest_GetDigestLenForAlgorithm(Sec_DigestAlgorithm alg); + +/** + * @brief compute inputs for the base key ladder + */ +Sec_Result SecKey_ComputeBaseKeyLadderInputs(Sec_ProcessorHandle* processorHandle, const char* inputDerivationStr, + const char* cipherAlgorithmStr, SEC_BYTE* nonce, Sec_DigestAlgorithm digestAlgorithm, SEC_SIZE inputSize, + SEC_BYTE* c1, SEC_BYTE* c2, SEC_BYTE* c3, SEC_BYTE* c4); + +/** + * @brief Check if provided algorithm takes digest as an input + */ +SEC_BOOL SecSignature_IsDigest(Sec_SignatureAlgorithm alg); + +SEC_BOOL SecSignature_IsRsaPss(Sec_SignatureAlgorithm alg); + +/** + * log callback function + */ +typedef void (*SecApiLogCallback)(const char* fmt, ...); + +/** + * @brief set log callback function + * + * @param cb pointer to the logger function + */ +void Sec_SetLogger(SecApiLogCallback cb); + +/** + * @brief get the log callback function + * + * @return pointer to the logger function + */ +SecApiLogCallback Sec_GetLogger(void); + +/** + * @brief default logger implementation (stdout) + */ +void Sec_DefaultLoggerCb(const char* fmt, ...); + +/** + * @brief NOP logger implementation + */ +void Sec_NOPLoggerCb(const char* fmt, ...); + +/** + * @brief Print a hexadecimal value + */ +void Sec_PrintHex(void* data, SEC_SIZE numBytes); + +/** + * Print OpenSSL version information + */ +void Sec_PrintOpenSSLVersion(); + +/** + * Initialize all OpenSSL algorithms used by the Security API. Register securityapi engine. + */ +void Sec_InitOpenSSL(void); + +/** + * @brief Obtain an OpenSSL RSA key from the Security API key handle. This RSA + * key will support performing RSA encrypt/decrypt/sign/verify operations in hardware + * when used by OpenSSL functions such as PKCS7_sign, PKCS7_verify, etc. + */ +RSA* SecKey_ToEngineRSA(Sec_KeyHandle* keyHandle); + +RSA* SecKey_ToEngineRSAWithCert(Sec_KeyHandle* keyHandle, Sec_CertificateHandle* certificateHandle); + +/** + * @brief Obtain an OpenSSL EC key from the Security API key handle. This EC + * key will support performing EC encrypt/decrypt/sign/verify operations in hardware + * when used by OpenSSL functions. + */ +EC_KEY* SecKey_ToEngineEcc(Sec_KeyHandle* keyHandle); + +/** + * @brief Load an OpenSSL X509 object from a DER format + */ +X509* SecCertificate_DerToX509(void* mem, SEC_SIZE len); + +/** + * @brief Obtain an OpenSSL X509 certificate from the Security API cert handle. + */ +X509* SecCertificate_ToX509(Sec_CertificateHandle* certificateHandle); + +/** + * @brief Find if the certificate with a specific id has been provisioned + * + * @param processorHandle secure processor handle + * @param object_id id of the certificate + * + * @return 1 if an object has been provisioned, 0 if it has not been + */ +SEC_BOOL SecCertificate_IsProvisioned(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id); + +/** + * @brief Obtain the size of the certificate in DER format + * + * @param certHandle certificate whose size we want to obtain + */ +SEC_SIZE SecCertificate_GetSize(Sec_CertificateHandle* certificateHandle); + +/** + * @brief Returns the key type of the public key contained in a certificate. + * + * @param certHandle Handle of a certificate whose type will be returned + */ +Sec_KeyType SecCertificate_GetKeyType(Sec_CertificateHandle* certificateHandle); + +/** + * @brief finds the first available certificate id in the range passed in + * + * @param proc secure processor + * @param base bottom of the range to search + * @param top top of the range to search + * @return + */ +SEC_OBJECTID SecCertificate_ObtainFreeObjectId(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID base, + SEC_OBJECTID top); + +/** + * @brief Utility function for calculating a digest value of a single input buffer + * + * @param proc secure processor handle + * @param alg digest algorithm to use + * @param input input data to calculate digest over + * @param input_len size of input data in bytes + * @param digest output buffer where the calculated digest value will be written + * @param digest_len number of bytes written to the output digest buffer + * + * @return status of the operation + */ +Sec_Result +SecDigest_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_DigestAlgorithm alg, SEC_BYTE* input, + SEC_SIZE input_len, SEC_BYTE* digest, SEC_SIZE* digest_len); + +/** + * @brief Utility function for calculating a digest value of a single input buffer + * + * @param proc secure processor handle + * @param alg digest algorithm to use + * @param key_id id of the key over which the digest is being calculated + * @param digest output buffer where the calculated digest value will be written + * @param digest_len number of bytes written to the output digest buffer + * + * @return status of the operation + */ +Sec_Result SecDigest_SingleInputWithKeyId(Sec_ProcessorHandle* processorHandle, Sec_DigestAlgorithm alg, + SEC_OBJECTID key_id, SEC_BYTE* digest, SEC_SIZE* digest_len); + +/** + * @brief Utility function for filling out a random value + * + * @param proc secure processor handle + * @param alg random algorithm to use + * @param output output buffer where the random value will be written + * @param output_len number of bytes written to the output buffer + * + * @return status of the operation + */ +Sec_Result SecRandom_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_RandomAlgorithm alg, SEC_BYTE* output, + SEC_SIZE output_len); + +/** + * @brief Find if the bundle with a specific id has been provisioned + * + * @param processorHandle secure processor handle + * @param object_id id of the certificate + * + * @return 1 if an object has been provisioned, 0 if it has not been + */ +SEC_BOOL SecBundle_IsProvisioned(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id); + +/** + * @brief finds the first available bundle id in the range passed in + * + * @param proc secure processor + * @param base bottom of the range to search + * @param top top of the range to search + * @return + */ +SEC_OBJECTID SecBundle_ObtainFreeObjectId(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID base, SEC_OBJECTID top); + +#ifndef SEC_COMMON_17 + +/** + * @brief Generate an Asn1 key container for wrapped keys + */ +Sec_Result SecKey_GenerateWrappedKeyAsn1(SEC_BYTE* wrappedKey, SEC_SIZE wrappedKeyLen, Sec_KeyType wrappedKeyType, + SEC_OBJECTID wrappingKeyId, SEC_BYTE* wrappingIv, Sec_CipherAlgorithm wrappingAlgorithm, SEC_BYTE* output, + SEC_SIZE output_len, SEC_SIZE* written); + +/** + * @brief Extract wrapped key params from ASN1KC + */ +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1(Sec_Asn1KC* kc, SEC_BYTE* wrappedKey, SEC_SIZE wrappedKeyLen, + SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, SEC_BYTE* wrappingIv, + Sec_CipherAlgorithm* wrappingAlg); + +/** + * @brief Extract wrapped key params from ASN1KC buffer + */ +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1Buffer(SEC_BYTE* asn1, SEC_SIZE asn1_len, SEC_BYTE* wrappedKey, + SEC_SIZE wrappedKeyLen, SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, + SEC_BYTE* wrappingIv, Sec_CipherAlgorithm* wrappingAlg); + +/** + * @brief Generate an Asn1 key container for wrapped keys + */ +Sec_Result SecKey_GenerateWrappedKeyAsn1Off(SEC_BYTE* payload, SEC_SIZE payloadLen, Sec_KeyType wrappedKeyType, + SEC_OBJECTID wrappingKeyId, SEC_BYTE* wrappingIv, Sec_CipherAlgorithm wrappingAlgorithm, SEC_BYTE* output, + SEC_SIZE output_len, SEC_SIZE* written, SEC_SIZE key_offset); + +Sec_Result SecKey_GenerateWrappedKeyAsn1V3(SEC_BYTE* payload, SEC_SIZE payloadLen, Sec_KeyType wrappedKeyType, + SEC_BYTE* wrappingKey, SEC_SIZE wrappingKeyLen, SEC_BYTE* wrappingIv, Sec_CipherAlgorithm wrappingAlgorithm, + SEC_BYTE* output, SEC_SIZE output_len, SEC_SIZE* written, SEC_SIZE key_offset); +/** + * @brief Extract wrapped key params from ASN1KC + */ +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1Off(Sec_Asn1KC* kc, SEC_BYTE* payload, SEC_SIZE payloadLen, + SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, SEC_BYTE* wrappingIv, + Sec_CipherAlgorithm* wrappingAlg, SEC_SIZE* key_offset); + +/** + * @brief Extract wrapped key params from ASN1KC buffer + */ +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1BufferOff(SEC_BYTE* asn1, SEC_SIZE asn1_len, SEC_BYTE* payload, + SEC_SIZE payloadLen, SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, + SEC_BYTE* wrappingIv, Sec_CipherAlgorithm* wrappingAlg, SEC_SIZE* key_offset); + +/** + * @brief Extract wrapped key params from ASN1KC + */ +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1V3(Sec_Asn1KC* kc, SEC_BYTE* payload, SEC_SIZE payloadLen, + SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, SEC_BYTE* wrappingIv, + Sec_CipherAlgorithm* wrappingAlg, SEC_SIZE* key_offset, SEC_BYTE* wrappingKey, SEC_SIZE wrappingKeyLen, + SEC_SIZE* writtenWrappingKey); + +/** + * @brief Extract wrapped key params from ASN1KC buffer + */ +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1BufferV3(SEC_BYTE* asn1, SEC_SIZE asn1_len, SEC_BYTE* payload, + SEC_SIZE payloadLen, SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, + SEC_BYTE* wrappingIv, Sec_CipherAlgorithm* wrappingAlg, SEC_SIZE* key_offset, SEC_BYTE* wrappingKey, + SEC_SIZE wrappingKeyLen, SEC_SIZE* writtenWrappingKey); + +void SecKeyProperties_SetDefault(Sec_KeyProperties* props, Sec_KeyType type); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SEC_SECURITY_COMMON_H */ diff --git a/include/sec_security_datatype.h b/include/sec_security_datatype.h new file mode 100755 index 0000000..5aaaa79 --- /dev/null +++ b/include/sec_security_datatype.h @@ -0,0 +1,646 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_SECURITY_DATATYPE_H +#define SEC_SECURITY_DATATYPE_H + +#include + +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif + +#if !defined(BIT_32) && !defined(BIT_64) +#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN64) +#define BIT_64 +#else +#define BIT_32 +#endif +#elif __GNUC__ || defined(__APPLE__) +#if __x86_64__ || __ppc64__ +#define BIT_64 +#else +#define BIT_32 +#endif +#else +#error "Could not determine whether compiling for 32 bit or 64 bit system" +#endif +#endif + +/* enables debug prints */ +#define SEC_DEBUG + +/* macro to string */ +#define SEC_MTOS_(x) #x +#define SEC_MTOS(x) SEC_MTOS_(x) + +/* min */ +#ifndef SEC_MIN +#define SEC_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/* max */ +#ifndef SEC_MAX +#define SEC_MAX(a, b) (((a) < (b)) ? (b) : (a)) +#endif + +#define SEC_MAX_FILE_PATH_LEN MAXPATHLEN + +/* maximum length of a digest value (in bytes) */ +#define SEC_DIGEST_MAX_LEN 32 + +#define SEC_DH_3072_LEN 384 + +/* maximum length of a MAC value (in bytes) */ +#define SEC_MAC_MAX_LEN 32 + +/* maximum length of a MAC key (in bytes) */ +#define SEC_MAC_KEY_MAX_LEN 32 + +/* maximum length of an RSA key modulus (in bytes) */ +#define SEC_RSA_KEY_MAX_LEN 256 + +/* length of an NIST_P256 ECC key */ +#define SEC_ECC_NISTP256_KEY_LEN 32UL + +/* maximum length of an ECC point coordinate (in bytes) */ +#define SEC_EC_KEY_MAX_LEN 80 + +/* maximum length of a signature value (in bytes) */ +#define SEC_SIGNATURE_MAX_LEN SEC_RSA_KEY_MAX_LEN + +/* maximum length of an AES key (in bytes) */ +#define SEC_AES_KEY_MAX_LEN 32 + +/* aes block size (in bytes) */ +#define SEC_AES_BLOCK_SIZE 16 + +/* maximum length of a symetric key (AES or MAC) (in bytes) */ +#define SEC_SYMETRIC_KEY_MAX_LEN SEC_MAX(SEC_AES_KEY_MAX_LEN, SEC_MAC_KEY_MAX_LEN) + +/* maximum length of the IV value (in bytes) */ +#define SEC_CIPHER_IV_MAX_LEN SEC_AES_KEY_MAX_LEN + +/* the length of the device id (in bytes) */ +#define SEC_DEVICEID_LEN 8 + +/* the length of client nonce (in bytes) */ +#define SEC_NONCE_LEN 20 + +/* fixed reserved ids */ +#define SEC_OBJECTID_INVALID 0xffffffffffffffffULL +#define SEC_OBJECTID_BASE_KEY_AES 0xfffffffffffffffeULL +#define SEC_OBJECTID_BASE_KEY_MAC 0xfffffffffffffffdULL +#define SEC_OBJECTID_STORE_MACKEYGEN_KEY 0xfffffffffffffffcULL +#define SEC_OBJECTID_CERTSTORE_KEY 0xfffffffffffffffbULL +#define SEC_OBJECTID_STORE_AES_KEY 0xfffffffffffffffaULL +#define SEC_OBJECTID_SIG_FROM_CERT 0xfffffffffffffff9ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_8 0xfffffffffffffff8ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_7 0xfffffffffffffff7ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_6 0xfffffffffffffff6ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_5 0xfffffffffffffff5ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_4 0xfffffffffffffff4ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_3 0xfffffffffffffff3ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_2 0xfffffffffffffff2ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_1 0xfffffffffffffff1ULL +#define SEC_OBJECTID_RESERVEDPLATFORM_0 0xfffffffffffffff0ULL + +/* reserved key space */ +#define SEC_OBJECTID_RESERVED_TOP 0xfffffffffffffff0ULL +#define SEC_OBJECTID_RESERVED_BASE 0xffffffffffffff00ULL + +/* user key space */ +#define SEC_OBJECTID_USER_TOP 0xffffffffffffff00ULL +#define SEC_OBJECTID_USER_BASE 0xfffffffffffff000ULL + +#if defined(BIT_64) && !defined(__APPLE__) +#define SEC_OBJECTID_PATTERN "%016lx" +#define SEC_KEY_FILENAME_PATTERN "%s%016lx.key" +#define SEC_KEYINFO_FILENAME_PATTERN "%s%016lx.keyinfo" +#define SEC_CERT_FILENAME_PATTERN "%s%016lx.cert" +#define SEC_CERTINFO_FILENAME_PATTERN "%s%016lx.certinfo" +#define SEC_BUNDLE_FILENAME_PATTERN "%s%016lx.bin" +#define SEC_VERIFICATION_FILENAME_PATTERN "%s%016lx.sha" +#else +#define SEC_OBJECTID_PATTERN "%016llx" +#define SEC_KEY_FILENAME_PATTERN "%s%016llx.key" +#define SEC_KEYINFO_FILENAME_PATTERN "%s%016llx.keyinfo" +#define SEC_CERT_FILENAME_PATTERN "%s%016llx.cert" +#define SEC_CERTINFO_FILENAME_PATTERN "%s%016llx.certinfo" +#define SEC_BUNDLE_FILENAME_PATTERN "%s%016llx.bin" +#define SEC_VERIFICATION_FILENAME_PATTERN "%s%016llx.sha" +#endif + +#define SEC_KEY_FILENAME_EXT ".key" +#define SEC_CERT_FILENAME_EXT ".cert" +#define SEC_BUNDLE_FILENAME_EXT ".bin" + +#define SEC_KEYCONTAINER_MAX_LEN (1024UL * 6UL) +#define SEC_BUNDLE_MAX_LEN (1024 * 128) +#define SEC_CERT_MAX_DATA_LEN (1024 * 64) + +#define SEC_TRUE 1 +#define SEC_FALSE 0 + +/* ASN1KC format defines */ +#define SEC_ASN1KC_WRAPPEDKEY "WrappedKey" +#define SEC_ASN1KC_WRAPPEDKEYTYPEID "WrappedKeyTypeId" +#define SEC_ASN1KC_WRAPPINGKEYID "WrappingKeyId" +#define SEC_ASN1KC_WRAPPINGIV "WrappingIV" +#define SEC_ASN1KC_WRAPPINGALGORITHMID "WrappingAlgorithmId" +#define SEC_ASN1KC_WRAPPEDKEYOFFSET "WrappedKeyOffset" +#define SEC_ASN1KC_WRAPPINGKEY "WrappingKey" + +/***************************************************************************** + * EXPORTED TYPES + *****************************************************************************/ + +typedef uint8_t SEC_BYTE; +typedef uint8_t SEC_BOOL; +typedef uint32_t SEC_SIZE; +typedef uint64_t SEC_OBJECTID; + +// A general note for all the enums below: +// the ..._NUM value must be the last defined. It is returned to indicate +// an invalid value + +typedef enum { + SEC_KEYLADDERROOT_UNIQUE, + SEC_KEYLADDERROOT_SHARED, + SEC_KEYLADDERROOT_NUM +} Sec_KeyLadderRoot; + +/** + * @brief Cipher algorithms + * + */ +typedef enum { + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING = 0, + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, + SEC_CIPHERALGORITHM_AES_CTR, + SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING, + SEC_CIPHERALGORITHM_RSA_OAEP_PADDING, + SEC_CIPHERALGORITHM_ECC_ELGAMAL, + SEC_CIPHERALGORITHM_NUM +} Sec_CipherAlgorithm; + +/** + * @brief Key types + * + */ +typedef enum { + SEC_KEYTYPE_AES_128 = 0, + SEC_KEYTYPE_AES_256, + SEC_KEYTYPE_RSA_1024, + SEC_KEYTYPE_RSA_2048, + SEC_KEYTYPE_RSA_1024_PUBLIC, + SEC_KEYTYPE_RSA_2048_PUBLIC, + SEC_KEYTYPE_HMAC_128, + SEC_KEYTYPE_HMAC_160, + SEC_KEYTYPE_HMAC_256, + SEC_KEYTYPE_ECC_NISTP256, + SEC_KEYTYPE_ECC_NISTP256_PUBLIC, + SEC_KEYTYPE_RSA_3072, + SEC_KEYTYPE_RSA_3072_PUBLIC, + SEC_KEYTYPE_NUM +} Sec_KeyType; + +/** + * @brief Key container types + * + */ +typedef enum { + SEC_KEYCONTAINER_RAW_AES_128 = 0, + SEC_KEYCONTAINER_RAW_AES_256, + SEC_KEYCONTAINER_RAW_HMAC_128, + SEC_KEYCONTAINER_RAW_HMAC_160, + SEC_KEYCONTAINER_RAW_HMAC_256, + SEC_KEYCONTAINER_RAW_RSA_1024, + SEC_KEYCONTAINER_RAW_RSA_2048, + SEC_KEYCONTAINER_RAW_RSA_1024_PUBLIC, + SEC_KEYCONTAINER_RAW_RSA_2048_PUBLIC, + SEC_KEYCONTAINER_PEM_RSA_1024, + SEC_KEYCONTAINER_PEM_RSA_2048, + SEC_KEYCONTAINER_PEM_RSA_1024_PUBLIC, + SEC_KEYCONTAINER_PEM_RSA_2048_PUBLIC, + SEC_KEYCONTAINER_SOC, + SEC_KEYCONTAINER_SOC_INTERNAL_0, + SEC_KEYCONTAINER_SOC_INTERNAL_1, + SEC_KEYCONTAINER_SOC_INTERNAL_2, + SEC_KEYCONTAINER_SOC_INTERNAL_3, + SEC_KEYCONTAINER_SOC_INTERNAL_4, + SEC_KEYCONTAINER_SOC_INTERNAL_5, + SEC_KEYCONTAINER_SOC_INTERNAL_6, + SEC_KEYCONTAINER_SOC_INTERNAL_7, + SEC_KEYCONTAINER_STORE, + SEC_KEYCONTAINER_DER_RSA_1024, + SEC_KEYCONTAINER_DER_RSA_2048, + SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC, + SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC, + SEC_KEYCONTAINER_ASN1, + SEC_KEYCONTAINER_PEM_ECC_NISTP256, + SEC_KEYCONTAINER_PEM_ECC_NISTP256_PUBLIC, + SEC_KEYCONTAINER_RAW_ECC_NISTP256, + SEC_KEYCONTAINER_RAW_ECC_NISTP256_PUBLIC, + SEC_KEYCONTAINER_DER_ECC_NISTP256, + SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC, + SEC_KEYCONTAINER_SOC_INTERNAL_8, + SEC_KEYCONTAINER_SOC_INTERNAL_9, + SEC_KEYCONTAINER_SOC_INTERNAL_10, + SEC_KEYCONTAINER_SOC_INTERNAL_11, + SEC_KEYCONTAINER_RAW_ECC_PRIVONLY_NISTP256, + SEC_KEYCONTAINER_RAW_RSA_3072, + SEC_KEYCONTAINER_RAW_RSA_3072_PUBLIC, + SEC_KEYCONTAINER_PEM_RSA_3072, + SEC_KEYCONTAINER_PEM_RSA_3072_PUBLIC, + SEC_KEYCONTAINER_DER_RSA_3072, + SEC_KEYCONTAINER_DER_RSA_3072_PUBLIC, + SEC_KEYCONTAINER_JTYPE, + SEC_KEYCONTAINER_COMCAST = SEC_KEYCONTAINER_JTYPE, + SEC_KEYCONTAINER_EXPORTED, + SEC_KEYCONTAINER_SOC_INTERNAL_12, + SEC_KEYCONTAINER_SOC_INTERNAL_13, + SEC_KEYCONTAINER_SOC_INTERNAL_14, + SEC_KEYCONTAINER_SOC_INTERNAL_15, + SEC_KEYCONTAINER_NUM +} Sec_KeyContainer; + +/** + * @brief Certificate container types + * + */ +typedef enum { + SEC_CERTIFICATECONTAINER_X509_DER = 0, + SEC_CERTIFICATECONTAINER_X509_PEM, + SEC_CERTIFICATECONTAINER_SOC, + SEC_CERTIFICATECONTAINER_NUM +} Sec_CertificateContainer; + +/** + * @brief Storage locations + * + */ +typedef enum { + SEC_STORAGELOC_RAM = 0, + SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_STORAGELOC_FILE, + SEC_STORAGELOC_FILE_SOFT_WRAPPED, + SEC_STORAGELOC_OEM, + SEC_STORAGELOC_SOC = SEC_STORAGELOC_OEM, + SEC_STORAGELOC_NUM +} Sec_StorageLoc; + +/** + * @brief Cipher modes + * + */ +typedef enum { + SEC_CIPHERMODE_ENCRYPT = 0, + SEC_CIPHERMODE_DECRYPT, + SEC_CIPHERMODE_ENCRYPT_NATIVEMEM, + SEC_CIPHERMODE_DECRYPT_NATIVEMEM, + SEC_CIPHERMODE_NUM +} Sec_CipherMode; + +/** + * @brief Signature algorithms + * + */ +typedef enum { + SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS = 0, + SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS, + SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST, + SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST, + SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS, + SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS, + SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST, + SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST, + SEC_SIGNATUREALGORITHM_ECDSA_NISTP256, + SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST, + SEC_SIGNATUREALGORITHM_NUM +} Sec_SignatureAlgorithm; + +/** + * @brief Signature modes + * + */ +typedef enum { + SEC_SIGNATUREMODE_SIGN = 0, + SEC_SIGNATUREMODE_VERIFY, + SEC_SIGNATUREMODE_NUM +} Sec_SignatureMode; + +/** + * @brief MAC algorithms + * + */ +typedef enum { + SEC_MACALGORITHM_HMAC_SHA1 = 0, + SEC_MACALGORITHM_HMAC_SHA256, + SEC_MACALGORITHM_CMAC_AES_128, + SEC_MACALGORITHM_NUM +} Sec_MacAlgorithm; + +/** + * @brief Digest algorithms + * + */ +typedef enum { + SEC_DIGESTALGORITHM_SHA1 = 0, + SEC_DIGESTALGORITHM_SHA256, + SEC_DIGESTALGORITHM_NUM +} Sec_DigestAlgorithm; + +/** + * @brief Random algorithms + * + */ +typedef enum { + SEC_RANDOMALGORITHM_TRUE = 0, + SEC_RANDOMALGORITHM_PRNG, + SEC_RANDOMALGORITHM_NUM +} Sec_RandomAlgorithm; + +/** + * @brief Function return codes + * + */ +typedef enum { + SEC_RESULT_SUCCESS = 0, + SEC_RESULT_FAILURE, + SEC_RESULT_INVALID_PARAMETERS, + SEC_RESULT_NO_SUCH_ITEM, + SEC_RESULT_BUFFER_TOO_SMALL, + SEC_RESULT_INVALID_INPUT_SIZE, + SEC_RESULT_INVALID_HANDLE, + SEC_RESULT_INVALID_PADDING, + SEC_RESULT_UNIMPLEMENTED_FEATURE, + SEC_RESULT_ITEM_ALREADY_PROVISIONED, + SEC_RESULT_ITEM_NON_REMOVABLE, + SEC_RESULT_VERIFICATION_FAILED, + SEC_RESULT_NO_KEYSLOTS_AVAILABLE, + SEC_RESULT_SVP_NOT_ENGAGED, + SEC_RESULT_OPL_NOT_ENGAGED, + SEC_RESULT_INVALID_SVP_DATA, + SEC_RESULT_ALLOCATION_FAILED, + SEC_RESULT_NUM +} Sec_Result; + +/** + * @brief Key output protection rights + */ +typedef enum { + SEC_KEYOUTPUTRIGHT_NOT_SET = 0x00, + SEC_KEYOUTPUTRIGHT_SVP_REQUIRED = 0x01, + SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_DTCP_ALLOWED = 0x02, + SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED = 0x03, + SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED = 0x04, + SEC_KEYOUTPUTRIGHT_ANALOG_OUTPUT_ALLOWED = 0x05, + SEC_KEYOUTPUTRIGHT_TRANSCRIPTION_COPY_ALLOWED = 0x06, + SEC_KEYOUTPUTRIGHT_UNRESTRICTED_COPY_ALLOWED = 0x07, + SEC_KEYOUTPUTRIGHT_CGMSA_REQUIRED = 0x08, + SEC_KEYOUTPUTRIGHT_RESERVED_10 = 0x09, + SEC_KEYOUTPUTRIGHT_RESERVED_11 = 0x0a, + SEC_KEYOUTPUTRIGHT_RESERVED_12 = 0x0b, + SEC_KEYOUTPUTRIGHT_RESERVED_13 = 0x0c, + SEC_KEYOUTPUTRIGHT_RESERVED_14 = 0x0d, + SEC_KEYOUTPUTRIGHT_RESERVED_15 = 0x0e, + SEC_KEYOUTPUTRIGHT_RESERVED_16 = 0x0f, + SEC_KEYOUTPUTRIGHT_NUM +} Sec_KeyOutputRight; + +/** + * @brief Key usage values + */ +typedef enum { + SEC_KEYUSAGE_DATA_KEY = 0, + SEC_KEYUSAGE_DATA, + SEC_KEYUSAGE_KEY, + SEC_KEYUSAGE_NUM +} Sec_KeyUsage; + +typedef struct { + char keyId[40]; + SEC_BYTE rights[SEC_KEYOUTPUTRIGHT_NUM]; + char notBefore[24]; + char notOnOrAfter[24]; + SEC_SIZE keyLength; + Sec_KeyType keyType; + Sec_KeyUsage usage; + SEC_BYTE cacheable; +} Sec_KeyProperties; + +/** + * @brief Raw Private RSA key data + * + */ +typedef struct +{ + SEC_BYTE n[SEC_RSA_KEY_MAX_LEN]; + SEC_BYTE d[SEC_RSA_KEY_MAX_LEN]; + SEC_BYTE e[4]; + SEC_BYTE modulus_len_be[4]; + uint32_t padding[2]; +} Sec_RSARawPrivateKey; + +/** + * @brief Full Raw Private RSA key data + * + */ +typedef struct +{ + SEC_BYTE n[SEC_RSA_KEY_MAX_LEN]; + SEC_BYTE d[SEC_RSA_KEY_MAX_LEN]; + SEC_BYTE e[4]; + SEC_BYTE modulus_len_be[4]; + uint32_t padding[2]; + SEC_BYTE p[SEC_RSA_KEY_MAX_LEN]; + SEC_BYTE q[SEC_RSA_KEY_MAX_LEN]; +} Sec_RSARawPrivateFullKey; + +/** + * @brief Raw Public RSA key data + * + */ +typedef struct +{ + SEC_BYTE n[SEC_RSA_KEY_MAX_LEN]; + SEC_BYTE e[4]; + SEC_BYTE modulus_len_be[4]; +} Sec_RSARawPublicKey; + +/** + * @brief Raw Private EC key data + * + * Note: A prv value need not be on the curve. A prv value is simply + * an integer multiplier k that tells how many times to add the + * universal public point P (on the curve) to itself get the + * corresponding private point. An ECC private key for the NIST + * 256-curve would be 256-bits. For that curve, prv is simply a + * random 256-bit number. prv can be gotten by a call to a sound + * random number generator, e.g. genrandom(256) and anything that + * comes out is valid. + * + */ +typedef struct +{ + Sec_KeyType type; // curve parameters indicated by key type + SEC_BYTE x[SEC_EC_KEY_MAX_LEN]; + SEC_BYTE y[SEC_EC_KEY_MAX_LEN]; + SEC_BYTE prv[SEC_EC_KEY_MAX_LEN]; + SEC_BYTE key_len[4]; // length in bytes of x (same as y and prv) +} Sec_ECCRawPrivateKey; + +/** + * @brief Raw Public EC key data + * + */ +typedef struct +{ + Sec_KeyType type; // curve parameters indicated by key type + SEC_BYTE x[SEC_EC_KEY_MAX_LEN]; + SEC_BYTE y[SEC_EC_KEY_MAX_LEN]; + SEC_BYTE key_len[4]; // length in bytes of x (same as y and prv) +} Sec_ECCRawPublicKey; + +/** + * @brief Raw ONLY Private EC key data + * + * This contains just a 256-bit [32 byte] ECC private key. + * $$$ If we add more ECC key types, will need to modify this. + */ +typedef struct { + SEC_BYTE prv[SEC_ECC_NISTP256_KEY_LEN]; +} Sec_ECCRawOnlyPrivateKey; + +typedef struct { + SEC_BYTE p[SEC_DH_3072_LEN]; // Prime p. Big-endian format + SEC_SIZE pLen; // Length of p in bytes. Max value is 384. + SEC_BYTE g[SEC_DH_3072_LEN]; // Base g. Big-endian format + SEC_SIZE gLen; // Length of g in bytes +} Sec_DHParameters; + +typedef enum { + NISTP256 = 0 +} EC_PARAMETERS; + +typedef struct { + EC_PARAMETERS curve; +} Sec_ECDHParameters; + +typedef enum { + SEC_KEYEXCHANGE_DH = 0, + SEC_KEYEXCHANGE_ECDH, + SEC_KEYEXCHANGE_NUM +} Sec_KeyExchangeAlgorithm; + +typedef enum { + SEC_KDF_HKDF = 0, + SEC_KDF_CONCAT, + SEC_KDF_ANSI_X_9_63, + SEC_KDF_NUM +} Sec_Kdf; + +typedef struct { + SEC_BYTE version[256]; +} Sec_ProcessorInfo; + +/** + * @brief Opaque processor initialization parameters + * + */ +typedef struct Sec_ProcessorInitParams_struct Sec_ProcessorInitParams; + +/** + * @brief Opaque processor handle + * + */ +typedef struct Sec_ProcessorHandle_struct Sec_ProcessorHandle; + +/** + * @brief Opaque key handle + * + */ +typedef struct Sec_KeyHandle_struct Sec_KeyHandle; + +/** + * @brief Opaque bundle handle + * + */ +typedef struct Sec_BundleHandle_struct Sec_BundleHandle; + +/** + * @brief Opaque cipher handle + * + */ +typedef struct Sec_CipherHandle_struct Sec_CipherHandle; + +/** + * @brief Opaque digest handle + * + */ +typedef struct Sec_DigestHandle_struct Sec_DigestHandle; + +/** + * @brief Opaque mac handle + * + */ +typedef struct Sec_MacHandle_struct Sec_MacHandle; + +/** + * @brief Opaque signature handle + * + */ +typedef struct Sec_SignatureHandle_struct Sec_SignatureHandle; + +/** + * @brief Opaque random handle + * + */ +typedef struct Sec_RandomHandle_struct Sec_RandomHandle; + +/** + * @brief Opaque certificate handle + * + */ +typedef struct Sec_CertificateHandle_struct Sec_CertificateHandle; + +/** + * @brief Opaque key exchange handle + * + */ +typedef struct Sec_KeyExchangeHandle_struct Sec_KeyExchangeHandle; + +/** + * @brief Opaque buffer handle + */ +typedef struct Sec_OpaqueBufferHandle_struct Sec_OpaqueBufferHandle; + +typedef void Sec_ProtectedMemHandle; + +#ifdef __cplusplus +} +#endif + +#endif /* SEC_SECURITY_DATATYPE_H */ diff --git a/include/sec_version.h b/include/sec_version.h new file mode 100644 index 0000000..7828f1c --- /dev/null +++ b/include/sec_version.h @@ -0,0 +1,19 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define SEC_API_VERSION "2.3.2.4" diff --git a/src/sec_adapter_asn1kc.c b/src/sec_adapter_asn1kc.c new file mode 100644 index 0000000..4c4b47b --- /dev/null +++ b/src/sec_adapter_asn1kc.c @@ -0,0 +1,753 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_COMMON_17 + +#include "sec_security.h" +#include +#include + +// clang-format off +ASN1_CHOICE(Asn1KCAttribute_t_c) = { + ASN1_SIMPLE(Asn1KCAttribute_t_c, c.integer, ASN1_INTEGER), + ASN1_SIMPLE(Asn1KCAttribute_t_c, c.bitstring, ASN1_BIT_STRING), + ASN1_SIMPLE(Asn1KCAttribute_t_c, c.octetstring, ASN1_OCTET_STRING), + ASN1_SIMPLE(Asn1KCAttribute_t_c, c.null, ASN1_NULL), + ASN1_SIMPLE(Asn1KCAttribute_t_c, c.ia5string, ASN1_IA5STRING), + ASN1_SIMPLE(Asn1KCAttribute_t_c, c.utctime, ASN1_UTCTIME), +}ASN1_CHOICE_END(Asn1KCAttribute_t_c) + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(Asn1KCAttribute_t_c) +//Implements Asn1KCAttribute_t_c_new and Asn1KCAttribute_t_c_free + +ASN1_SEQUENCE(Asn1KCAttribute_t) = { + ASN1_SIMPLE(Asn1KCAttribute_t, name, ASN1_IA5STRING), + ASN1_OPT(Asn1KCAttribute_t, value, Asn1KCAttribute_t_c), +}ASN1_SEQUENCE_END(Asn1KCAttribute_t) + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(Asn1KCAttribute_t) +//Implements Asn1KCAttribute_t_new and Asn1KCAttribute_t_free + +ASN1_ITEM_TEMPLATE(Sec_Asn1KC) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, Sec_Asn1KC, Asn1KCAttribute_t)ASN1_ITEM_TEMPLATE_END(Sec_Asn1KC) + +IMPLEMENT_ASN1_FUNCTIONS(Sec_Asn1KC) + +IMPLEMENT_ASN1_PRINT_FUNCTION(Sec_Asn1KC) //PRINTF +//Implements Sec_Asn1KC_new, Sec_Asn1KC_free, d2i_Sec_Asn1KC i2d_Sec_Asn1KC + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +static Sec_Result getBE_ASN1_INTEGER(SEC_BYTE * res, const ASN1_INTEGER* ai, SEC_SIZE size, SEC_BOOL signd) { + // clang-format on + BIGNUM* bn = NULL; + int bn_size; + + if (ai == NULL || res == NULL) { + SEC_LOG_ERROR("Failed invalid input"); + return SEC_RESULT_FAILURE; + } + + bn = ASN1_INTEGER_to_BN(ai, NULL); + if (bn == NULL) { + SEC_LOG_ERROR("Failed ASN1_INTEGER_to_BN"); + return SEC_RESULT_FAILURE; + } + + bn_size = BN_num_bytes(bn); + memset(res, 0, size); + if (bn_size == 0) { + //Special case size == 0 means the integer value is 0; + BN_free(bn); + return SEC_RESULT_SUCCESS; + } + + SEC_SIZE offset = size - bn_size; + if (!BN_bn2bin(bn, (res + offset))) { + BN_free(bn); + SEC_LOG_ERROR("BN_bn2bin failed offset = %d, res = %p, size = %d", offset, res, size); + return SEC_RESULT_FAILURE; + } + + // If needed extend sign bits + if (signd == SEC_TRUE) { + if ((res[offset] & 0x80) == 0x80) + memset(res, 0xFF, offset); + } + + BN_free(bn); + return SEC_RESULT_SUCCESS; +} + +#endif + +static Sec_Result setBE_ASN1_INTEGER(ASN1_INTEGER* st, SEC_BYTE* be_value, SEC_SIZE size) { + BIGNUM* bn = BN_bin2bn(be_value, (int) size, NULL); + if (bn == NULL) { + SEC_LOG_ERROR("Failed BN_bin2bn"); + return SEC_RESULT_FAILURE; + } + + if (!BN_to_ASN1_INTEGER(bn, st)) { + SEC_LOG_ERROR("Failed BN_to_ASN1_INTEGER"); + BN_free(bn); + return SEC_RESULT_FAILURE; + } + + BN_free(bn); + + return SEC_RESULT_SUCCESS; +} + +typedef enum att_choic_e { + asn1_integer, + asn1_bit_string, + asn1_octet_string, + asn1_null, + asn1_ia5string, + asn1_utctime +} att_choice; + +static Asn1KCAttribute_t* SecAsn1KC_AllocAttr(att_choice c) { + Asn1KCAttribute_t* ptr = NULL; + + ptr = Asn1KCAttribute_t_new(); + if (ptr == NULL) { + return NULL; + } + + ptr->value = Asn1KCAttribute_t_c_new(); + if (ptr->value == NULL) { + Asn1KCAttribute_t_free(ptr); + return NULL; + } + + switch (c) { + case asn1_integer: + ptr->value->c.integer = ASN1_INTEGER_new(); + if (ptr->value->c.integer == NULL) { + SEC_LOG_ERROR("Failed ASN1_INTEGER_new"); + Asn1KCAttribute_t_free(ptr); + return NULL; + } + + ptr->value->type = ASN1KCATTRIBUTE_T_CHOICE_INTEGER; + break; + + case asn1_bit_string: + ptr->value->c.bitstring = ASN1_BIT_STRING_new(); + if (ptr->value->c.bitstring == NULL) { + SEC_LOG_ERROR("Failed ASN1_BIT_STRING_new"); + Asn1KCAttribute_t_free(ptr); + return NULL; + } + + ptr->value->type = ASN1KCATTRIBUTE_T_CHOICE_BITSTRING; + break; + + case asn1_octet_string: + ptr->value->c.octetstring = ASN1_OCTET_STRING_new(); + if (ptr->value->c.octetstring == NULL) { + SEC_LOG_ERROR("Failed ASN1_OCTET_STRING_new"); + Asn1KCAttribute_t_free(ptr); + return NULL; + } + + ptr->value->type = ASN1KCATTRIBUTE_T_CHOICE_OCTETSTRING; + break; + + case asn1_null: + ptr->value->c.null = ASN1_NULL_new(); + if (ptr->value->c.null == NULL) { + SEC_LOG_ERROR("Failed ASN1_NULL_new"); + Asn1KCAttribute_t_free(ptr); + return NULL; + } + + ptr->value->type = ASN1KCATTRIBUTE_T_CHOICE_NULL; + break; + + case asn1_ia5string: + ptr->value->c.ia5string = ASN1_IA5STRING_new(); + if (ptr->value->c.ia5string == NULL) { + SEC_LOG_ERROR("Failed ASN1_IA5STRING_new"); + Asn1KCAttribute_t_free(ptr); + return NULL; + } + + ptr->value->type = ASN1KCATTRIBUTE_T_CHOICE_IA5STRING; + break; + + case asn1_utctime: + ptr->value->c.utctime = ASN1_UTCTIME_new(); + if (ptr->value->c.utctime == NULL) { + SEC_LOG_ERROR("Failed ASN1_UTCTIME_new"); + Asn1KCAttribute_t_free(ptr); + return NULL; + } + + ptr->value->type = ASN1KCATTRIBUTE_T_CHOICE_UTCTIME; + break; + + default: + Asn1KCAttribute_t_free(ptr); + return NULL; + } + + return ptr; +} + +static Sec_Result SecAsn1KC_AddAttr(Sec_Asn1KC* kc, Asn1KCAttribute_t* attribute) { + if (sk_Asn1KCAttribute_t_push(kc, attribute) == 0) { + SEC_LOG_ERROR("Sk_Asn1KCAttribute_t_push failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Asn1KCAttribute_t* SecAsn1KC_GetAttr(Sec_Asn1KC* kc, const char* key) { + Asn1KCAttribute_t* at = NULL; + + for (int i = 0; i < sk_Asn1KCAttribute_t_num(kc); ++i) { + at = sk_Asn1KCAttribute_t_value(kc, i); + if (strlen(key) == ASN1_STRING_length(at->name) && +#if OPENSSL_VERSION_NUMBER < 0x10100000L + Sec_Memcmp(key, ASN1_STRING_data(at->name), ASN1_STRING_length(at->name)) == 0) +#else + Sec_Memcmp(key, ASN1_STRING_get0_data(at->name), ASN1_STRING_length(at->name)) == 0) +#endif + { + return at; + } + } + + return NULL; +} + +SEC_BOOL SecAsn1KC_HasAttr(Sec_Asn1KC* kc, const char* key) { + return SecAsn1KC_GetAttr(kc, key) != NULL; +} + +Sec_Result SecAsn1KC_GetAttrLong(Sec_Asn1KC* kc, const char* key, int64_t* val) { + Asn1KCAttribute_t* attr = NULL; + + attr = SecAsn1KC_GetAttr(kc, key); + if (attr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_GetAttr failed"); + return SEC_RESULT_FAILURE; + } + + if (attr->value->type != ASN1KCATTRIBUTE_T_CHOICE_INTEGER) { + SEC_LOG_ERROR("Invalid value type contained in the attribute: %d", + attr->value->c); + return SEC_RESULT_FAILURE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + // Openssl 1.0.9 has support for signed long types + // With Openssl 1.1.x new applications should use ASN1_INTEGER_get_int64() + // instead + *val = ASN1_INTEGER_get(attr->value->c.integer); +#else + if (ASN1_INTEGER_get_int64(val, attr->value->c.integer) != 1) { + SEC_LOG_ERROR("Failed to get Long value from asn1 struct"); + return SEC_RESULT_FAILURE; + } +#endif + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecAsn1KC_GetAttrInt64(Sec_Asn1KC* kc, const char* key, int64_t* val) { + Asn1KCAttribute_t* attr = NULL; +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SEC_BYTE val_buf[sizeof(int64_t)]; +#endif + + attr = SecAsn1KC_GetAttr(kc, key); + if (attr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_GetAttr failed invalid key"); + return SEC_RESULT_FAILURE; + } + + if (attr->value->type != ASN1KCATTRIBUTE_T_CHOICE_INTEGER) { + SEC_LOG_ERROR("Invalid value type contained in the attribute: %d", + attr->value->type); + return SEC_RESULT_FAILURE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + //With openssl 1.1.x support you can use ASN1_INTEGER_get_int64() in place + //of getBE_ASN1_INTEGER() + if (getBE_ASN1_INTEGER(val_buf, attr->value->c.integer, sizeof(val), + SEC_TRUE) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("GetBE_ASN1_INTEGER failed"); + return SEC_RESULT_FAILURE; + } + + //val_buf is an 8 byte buffer that has sign bits extended if needed. + *val = (int64_t) Sec_BEBytesToUint64(val_buf); +#else + if (ASN1_INTEGER_get_int64(val, attr->value->c.integer) != 1) { + SEC_LOG_ERROR("Failed to get Long value from asn1 struct"); + return SEC_RESULT_FAILURE; + } +#endif + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecAsn1KC_GetAttrUlong(Sec_Asn1KC* kc, const char* key, uint64_t* val) { + Asn1KCAttribute_t* attr = NULL; +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SEC_BYTE val_buf[sizeof(unsigned long)]; +#endif + + attr = SecAsn1KC_GetAttr(kc, key); + if (attr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_GetAttr failed invalid key"); + return SEC_RESULT_FAILURE; + } + + if (attr->value->type != ASN1KCATTRIBUTE_T_CHOICE_INTEGER) { + SEC_LOG_ERROR("Invalid value type contained in the attribute: %d", attr->value->c); + return SEC_RESULT_FAILURE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + //With openssl 1.1.x support you can use ASN1_INTEGER_get_uint64() in place + //of getBE_ASN1_INTEGER() + if (getBE_ASN1_INTEGER(val_buf, attr->value->c.integer, sizeof(val), + SEC_FALSE) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("GetBE_ASN1_INTEGER failed"); + return SEC_RESULT_FAILURE; + } + + if (sizeof(unsigned long) < sizeof(uint64_t)) { // NOLINT + *val = Sec_BEBytesToUint32(val_buf); + } else { + *val = Sec_BEBytesToUint64(val_buf); + } + +#else + if (ASN1_INTEGER_get_uint64(val, attr->value->c.integer) != 1) { + SEC_LOG_ERROR("Failed to get Long value from asn1 struct"); + return SEC_RESULT_FAILURE; + } + +#endif + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecAsn1KC_GetAttrUint64(Sec_Asn1KC* kc, const char* key, uint64_t* val) { + Asn1KCAttribute_t* attr = NULL; +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SEC_BYTE val_buf[sizeof(uint64_t)]; +#endif + + attr = SecAsn1KC_GetAttr(kc, key); + if (attr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_GetAttr failed invalid key"); + return SEC_RESULT_FAILURE; + } + + if (attr->value->type != ASN1KCATTRIBUTE_T_CHOICE_INTEGER) { + SEC_LOG_ERROR("Invalid value type contained in the attribute: %d", attr->value->c); + return SEC_RESULT_FAILURE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + //With openssl 1.1.x support you can use ASN1_INTEGER_get_uint64() in place + //of getBE_ASN1_INTEGER() + if (getBE_ASN1_INTEGER(val_buf, attr->value->c.integer, sizeof(uint64_t), + SEC_FALSE) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("GetBE_ASN1_INTEGER failed"); + return SEC_RESULT_FAILURE; + } + + *val = Sec_BEBytesToUint64(val_buf); +#else + if (ASN1_INTEGER_get_uint64(val, attr->value->c.integer) != 1) { + SEC_LOG_ERROR("Failed to get Long value from asn1 struct"); + return SEC_RESULT_FAILURE; + } +#endif + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecAsn1KC_GetAttrBuffer(Sec_Asn1KC* kc, const char* key, SEC_BYTE* buffer, SEC_SIZE buffer_len, + SEC_SIZE* written) { + Asn1KCAttribute_t* attr = NULL; + + attr = SecAsn1KC_GetAttr(kc, key); + if (attr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_GetAttr failed."); + return SEC_RESULT_FAILURE; + } + + if (attr->value->type != ASN1KCATTRIBUTE_T_CHOICE_OCTETSTRING) { + SEC_LOG_ERROR("Invalid value type contained in the attribute: %d", + attr->value->type); + return SEC_RESULT_FAILURE; + } + + *written = ASN1_STRING_length(attr->value->c.octetstring); + if (buffer != NULL) { + if (*written > buffer_len) { + SEC_LOG_ERROR("Output buffer is too small. Needed %d", *written); + return SEC_RESULT_FAILURE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + memcpy(buffer, ASN1_STRING_data(attr->value->c.octetstring), *written); +#else + memcpy(buffer, ASN1_STRING_get0_data(attr->value->c.octetstring), *written); +#endif + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecAsn1KC_GetAttrString(Sec_Asn1KC* kc, const char* key, char* buffer, SEC_SIZE buffer_len, + SEC_SIZE* written) { + Asn1KCAttribute_t* attr = NULL; + + attr = SecAsn1KC_GetAttr(kc, key); + if (attr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_GetAttr failed"); + return SEC_RESULT_FAILURE; + } + + if (attr->value->type != ASN1KCATTRIBUTE_T_CHOICE_IA5STRING) { + SEC_LOG_ERROR("Invalid value type contained in the attribute: %d", attr->value->type); + return SEC_RESULT_FAILURE; + } + + *written = ASN1_STRING_length(attr->value->c.ia5string); + if (buffer != NULL) { + if (*written >= buffer_len) { + SEC_LOG_ERROR("Output buffer is too small. Needed %d", *written); + return SEC_RESULT_FAILURE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + memcpy(buffer, ASN1_STRING_data(attr->value->c.octetstring), *written); +#else + memcpy(buffer, ASN1_STRING_get0_data(attr->value->c.octetstring), *written); +#endif + buffer[*written] = '\0'; + } + + *written += 1; + + return SEC_RESULT_SUCCESS; +} + +Sec_Asn1KC* SecAsn1KC_Alloc() { + Sec_Asn1KC* ptr = NULL; + + ptr = Sec_Asn1KC_new(); + if (ptr == NULL) { + SEC_LOG_ERROR("Sec_Asn1KC_new failed"); + return ptr; + } + + return ptr; +} + +void SecAsn1KC_Free(Sec_Asn1KC* kc) { + if (kc != NULL) { + Sec_Asn1KC_free(kc); + } +} + +Sec_Result SecAsn1KC_AddAttrLong(Sec_Asn1KC* kc, const char* key, int64_t val) { + Sec_Result result = SEC_RESULT_FAILURE; + Asn1KCAttribute_t* ptr = SecAsn1KC_AllocAttr(asn1_integer); + + do { + if (ptr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_AllocAttr failed"); + break; + } + + if (!ASN1_STRING_set(ptr->name, key, -1)) { + SEC_LOG_ERROR("ASN1_STRING_set failed"); + break; + } + + if (ASN1_INTEGER_set(ptr->value->c.integer, val) == 0) { + SEC_LOG_ERROR("ASN1_INTEGER_set failed"); + break; + } + + if (SecAsn1KC_AddAttr(kc, ptr) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttr failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (result != SEC_RESULT_SUCCESS) { + if (ptr != NULL) + Asn1KCAttribute_t_free(ptr); + } + return result; +} + +Sec_Result SecAsn1KC_AddAttrInt64(Sec_Asn1KC* kc, const char* key, int64_t val) { + Sec_Result result = SEC_RESULT_FAILURE; + Asn1KCAttribute_t* ptr = SecAsn1KC_AllocAttr(asn1_integer); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SEC_BYTE be_val[sizeof(val)]; +#endif + + do { + if (ptr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_AllocAttr failed"); + break; + } + + if (!ASN1_STRING_set(ptr->name, key, -1)) { + SEC_LOG_ERROR("ASN1_STRING_set failed"); + break; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + Sec_Uint64ToBEBytes((uint64_t) val, be_val); + if (setBE_ASN1_INTEGER(ptr->value->c.integer, be_val, sizeof(val)) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SetBE_ASN1_INTEGER failed"); + break; + } +#else + if (ASN1_INTEGER_set_int64(ptr->value->c.integer, val) == 0) { + SEC_LOG_ERROR("ASN1_INTEGER_set_int64 failed"); + break; + } +#endif + + if (SecAsn1KC_AddAttr(kc, ptr) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttr failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (result != SEC_RESULT_SUCCESS) { + if (ptr != NULL) + Asn1KCAttribute_t_free(ptr); + } + return result; +} + +Sec_Result SecAsn1KC_AddAttrUlong(Sec_Asn1KC* kc, const char* key, uint64_t val) { + Sec_Result result = SEC_RESULT_FAILURE; + Asn1KCAttribute_t* ptr = SecAsn1KC_AllocAttr(asn1_integer); + SEC_BYTE be_val[sizeof(val)]; + + do { + if (ptr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_AllocAttr failed"); + break; + } + + if (!ASN1_STRING_set(ptr->name, key, -1)) { + SEC_LOG_ERROR("ASN1_STRING_set failed"); + break; + } + + if (sizeof(unsigned long) < sizeof(uint64_t)) { // NOLINT + Sec_Uint32ToBEBytes((uint32_t) val, be_val); + } else { + Sec_Uint64ToBEBytes(val, be_val); + } + + if (setBE_ASN1_INTEGER(ptr->value->c.integer, be_val, sizeof(unsigned long)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SetBE_ASN1_INTEGER failed"); + break; + } + + if (SecAsn1KC_AddAttr(kc, ptr) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttr failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (result != SEC_RESULT_SUCCESS) { + if (ptr != NULL) + Asn1KCAttribute_t_free(ptr); + } + return result; +} + +Sec_Result SecAsn1KC_AddAttrUint64(Sec_Asn1KC* kc, const char* key, uint64_t val) { + Sec_Result result = SEC_RESULT_FAILURE; + Asn1KCAttribute_t* ptr = SecAsn1KC_AllocAttr(asn1_integer); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SEC_BYTE be_val[sizeof(val)]; +#endif + + do { + if (ptr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_AllocAttr failed"); + break; + } + + if (!ASN1_STRING_set(ptr->name, key, -1)) { + SEC_LOG_ERROR("ASN1_STRING_set failed"); + break; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + Sec_Uint64ToBEBytes(val, be_val); + if (setBE_ASN1_INTEGER(ptr->value->c.integer, be_val, sizeof(val)) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SetBE_ASN1_INTEGER failed"); + break; + } +#else + if (ASN1_INTEGER_set_uint64(ptr->value->c.integer, val) == 0) { + SEC_LOG_ERROR("ASN1_INTEGER_set_uint64 failed"); + break; + } +#endif + + if (SecAsn1KC_AddAttr(kc, ptr) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttr failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (result != SEC_RESULT_SUCCESS) { + if (ptr != NULL) + Asn1KCAttribute_t_free(ptr); + } + return result; +} + +Sec_Result SecAsn1KC_AddAttrString(Sec_Asn1KC* kc, const char* key, const char* val) { + Sec_Result result = SEC_RESULT_FAILURE; + Asn1KCAttribute_t* ptr = SecAsn1KC_AllocAttr(asn1_ia5string); + + do { + if (ptr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_AllocAttr failed"); + break; + } + + if (!ASN1_STRING_set(ptr->name, key, -1)) { + SEC_LOG_ERROR("Failed to set attribute name"); + break; + } + + if (!ASN1_STRING_set(ptr->value->c.ia5string, val, (int) strlen(val))) { + SEC_LOG_ERROR("Failed to set ia5string"); + break; + } + + if (SecAsn1KC_AddAttr(kc, ptr) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttr failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (result != SEC_RESULT_SUCCESS) { + if (ptr != NULL) + Asn1KCAttribute_t_free(ptr); + } + return result; +} + +Sec_Result SecAsn1KC_AddAttrBuffer(Sec_Asn1KC* kc, const char* key, void* buf, SEC_SIZE buf_len) { + Sec_Result result = SEC_RESULT_FAILURE; + Asn1KCAttribute_t* ptr = SecAsn1KC_AllocAttr(asn1_octet_string); + + do { + if (ptr == NULL) { + SEC_LOG_ERROR("SecAsn1KC_AllocAttr failed"); + break; + } + + if (!ASN1_STRING_set(ptr->name, key, -1)) { + SEC_LOG_ERROR("Failed to set attribute name"); + break; + } + + if (!ASN1_STRING_set(ptr->value->c.octetstring, buf, (int) buf_len)) { + SEC_LOG_ERROR("Failed to set octetstring"); + break; + } + + if (SecAsn1KC_AddAttr(kc, ptr) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttr failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (result != SEC_RESULT_SUCCESS) { + free(ptr); + } + return result; +} + +Sec_Result SecAsn1KC_Encode(Sec_Asn1KC* kc, SEC_BYTE* buf, SEC_SIZE buf_len, SEC_SIZE* written) { + int der_len = i2d_Sec_Asn1KC(kc, NULL); + + if (buf == NULL) { + *written = der_len; + } else if (der_len > buf_len) { + SEC_LOG_ERROR("Der_encode_to_buffer invalid buffer length, der_len = %d, buf_len = %d", der_len, buf_len); + return SEC_RESULT_FAILURE; + } else { + *written = i2d_Sec_Asn1KC(kc, &buf); + } + + if (*written < 0) { + SEC_LOG_ERROR("Der_encode_to_buffer failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Asn1KC* SecAsn1KC_Decode(const SEC_BYTE* buf, SEC_SIZE buf_len) { + const unsigned char* c_buf = buf; + Sec_Asn1KC* ret = NULL; + + if (buf_len > UINT_MAX) { + SEC_LOG_ERROR("Buf length rollover"); + return NULL; + } + ret = d2i_Sec_Asn1KC(NULL, &c_buf, (long) buf_len); + return ret; +} + +#endif diff --git a/src/sec_adapter_buffer.c b/src/sec_adapter_buffer.c new file mode 100644 index 0000000..9d4b102 --- /dev/null +++ b/src/sec_adapter_buffer.c @@ -0,0 +1,65 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_security.h" +#include + +/** + * @brief initialize the Sec_Buffer structure. + * + * @param buffer Sec_Buffer structure to initialize. + * @param mem memory buffer to use. + * @param len size of the memory buffer. + */ +void SecBuffer_Init(Sec_Buffer* buffer, void* mem, SEC_SIZE len) { + buffer->base = (SEC_BYTE*) mem; + buffer->size = len; + buffer->written = 0; +} + +/** + * @brief reset the buffer. + * + * @param buffer Sec_Buffer structure to initialize. + */ +void SecBuffer_Reset(Sec_Buffer* buffer) { + buffer->written = 0; +} + +/** + * @brief Write data to a buffer. + * + * @param buffer pointer to a Sec_Buffer structure to use. + * @param data input data to write. + * @param len length of input data. + * + * @return Status of the operation. Error status will be returned if there + * is not enough space left in the output buffer. + * @return The status of the operation. + */ +Sec_Result SecBuffer_Write(Sec_Buffer* buffer, void* data, SEC_SIZE len) { + SEC_SIZE space_left = buffer->size - buffer->written; + + if (space_left < 0 || space_left < len) + return SEC_RESULT_BUFFER_TOO_SMALL; + + memcpy(buffer->base + buffer->written, data, len); + buffer->written += len; + + return SEC_RESULT_SUCCESS; +} diff --git a/src/sec_adapter_bundle.c b/src/sec_adapter_bundle.c new file mode 100644 index 0000000..047cbd5 --- /dev/null +++ b/src/sec_adapter_bundle.c @@ -0,0 +1,374 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_bundle.h" + +struct Sec_BundleHandle_struct { + Sec_ProcessorHandle* processorHandle; + SEC_OBJECTID object_id; + Sec_StorageLoc location; + Sec_BundleData bundle_data; +}; + +void Sec_FindRAMBundleData(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_RAMBundleData** data, + Sec_RAMBundleData** parent) { + *parent = NULL; + *data = processorHandle->ram_bundles; + + while ((*data) != NULL) { + if (object_id == (*data)->object_id) + return; + + *parent = (*data); + *data = (*data)->next; + } + + *parent = NULL; +} + +static Sec_Result Sec_RetrieveBundleData(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_StorageLoc* location, Sec_BundleData* bundleData) { + char file_name_bundle[SEC_MAX_FILE_PATH_LEN]; + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + Sec_RAMBundleData* ram_bundle = NULL; + Sec_RAMBundleData* ram_bundle_parent = NULL; + + CHECK_PROCHANDLE(processorHandle) + + /* check in RAM */ + Sec_FindRAMBundleData(processorHandle, object_id, &ram_bundle, &ram_bundle_parent); + if (ram_bundle != NULL) { + memcpy(bundleData, &(ram_bundle->bundle_data), sizeof(Sec_BundleData)); + *location = SEC_STORAGELOC_RAM; + return SEC_RESULT_SUCCESS; + } + + /* check in app folder */ + char* sec_dirs[] = {processorHandle->app_dir, processorHandle->global_dir}; + for (int i = 0; i < 2; i++) { + if (sec_dirs[i] != NULL) { + snprintf(file_name_bundle, sizeof(file_name_bundle), SEC_BUNDLE_FILENAME_PATTERN, sec_dirs[i], + object_id); + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + sec_dirs[i], object_id); + if (SecUtils_FileExists(file_name_bundle)) { + if (SecUtils_ReadFile(file_name_bundle, bundleData->bundle, sizeof(bundleData->bundle), + &bundleData->bundle_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not read one of the bundle files"); + return SEC_RESULT_FAILURE; + } + + if (SecUtils_FileExists(file_name_verification)) { + if (verify_verification_file(processorHandle, file_name_verification, bundleData->bundle, + bundleData->bundle_len, NULL, 0) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Bundle verification failed"); + return SEC_RESULT_FAILURE; + } + } else { + // If sha file doesn't exist, the bundle file was created by an old SecApi. Just create the + // verification file. + if (write_verification_file(processorHandle, file_name_verification, bundleData->bundle, + bundleData->bundle_len, NULL, 0) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not write SHA file"); + } + } + + *location = SEC_STORAGELOC_FILE; + return SEC_RESULT_SUCCESS; + } + } + } + + return SEC_RESULT_NO_SUCH_ITEM; +} + +static Sec_Result Sec_StoreBundleData(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_StorageLoc location, Sec_BundleData* bundleData) { + Sec_RAMBundleData* ram_bundle; + + if (location == SEC_STORAGELOC_RAM) { + SecBundle_Delete(processorHandle, object_id); + + ram_bundle = calloc(1, sizeof(Sec_RAMBundleData)); + if (ram_bundle == NULL) { + SEC_LOG_ERROR("Malloc failed"); + return SEC_RESULT_FAILURE; + } + ram_bundle->object_id = object_id; + memcpy(&(ram_bundle->bundle_data), bundleData, sizeof(Sec_BundleData)); + ram_bundle->next = processorHandle->ram_bundles; + processorHandle->ram_bundles = ram_bundle; + + return SEC_RESULT_SUCCESS; + } + + if (location == SEC_STORAGELOC_FILE) { + if (processorHandle->app_dir == NULL) { + SEC_LOG_ERROR("Cannot write file because app_dir is NULL"); + return SEC_RESULT_FAILURE; + } + + SecBundle_Delete(processorHandle, object_id); + + char file_name_bundle[SEC_MAX_FILE_PATH_LEN]; + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_bundle, sizeof(file_name_bundle), SEC_BUNDLE_FILENAME_PATTERN, processorHandle->app_dir, + object_id); + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + processorHandle->app_dir, object_id); + + if (SecUtils_WriteFile(file_name_bundle, bundleData->bundle, bundleData->bundle_len) != SEC_RESULT_SUCCESS || + write_verification_file(processorHandle, file_name_verification, bundleData->bundle, + bundleData->bundle_len, NULL, 0) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not write one of the bundle files"); + SecUtils_RmFile(file_name_bundle); + SecUtils_RmFile(file_name_verification); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + } + + SEC_LOG_ERROR("Unimplemented location type"); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +/** + * @brief Obtain a handle to a provisioned bundle. + * + * @param processorHandle secure processor handle. + * @param object_id id of the provisioned bundle that we are attempting to obtain. + * @param bundleHandle pointer to the output key handle. + * + * @return The status of the operation. + */ +Sec_Result SecBundle_GetInstance(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_BundleHandle** bundleHandle) { + Sec_Result result; + Sec_StorageLoc location; + Sec_BundleData bundle_data; + + *bundleHandle = NULL; + + CHECK_PROCHANDLE(processorHandle) + + if (object_id == SEC_OBJECTID_INVALID) + return SEC_RESULT_INVALID_PARAMETERS; + + result = Sec_RetrieveBundleData(processorHandle, object_id, &location, &bundle_data); + if (result != SEC_RESULT_SUCCESS) + return result; + + *bundleHandle = calloc(1, sizeof(Sec_BundleHandle)); + if (*bundleHandle == NULL) { + SEC_LOG_ERROR("Malloc failed"); + return SEC_RESULT_FAILURE; + } + (*bundleHandle)->object_id = object_id; + memcpy(&((*bundleHandle)->bundle_data), &bundle_data, sizeof(Sec_BundleData)); + (*bundleHandle)->location = location; + (*bundleHandle)->processorHandle = processorHandle; + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Provision a bundle. + * + * @param processorHandle secure processor handle. + * @param object_id id of the bundle to provision. + * @param location storage location where the bundle should be provisioned. + * @param data pointer to the input key container. + * @param data_len the size of the input key container. + * + * @return The status of the operation. + */ +Sec_Result SecBundle_Provision(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_StorageLoc location, + SEC_BYTE* data, SEC_SIZE data_len) { + Sec_BundleData bundle_data; + + CHECK_PROCHANDLE(processorHandle) + + if (object_id == SEC_OBJECTID_INVALID) { + SEC_LOG_ERROR("Cannot provision object with SEC_OBJECTID_INVALID"); + return SEC_RESULT_FAILURE; + } + + if (data_len > SEC_BUNDLE_MAX_LEN) { + SEC_LOG_ERROR("Input bundle is too large"); + return SEC_RESULT_FAILURE; + } + + memcpy(bundle_data.bundle, data, data_len); + bundle_data.bundle_len = data_len; + + if (Sec_StoreBundleData(processorHandle, object_id, location, &bundle_data) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_StoreBundleData failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Delete a provisioned bundle. + * + * @param processorHandle secure processor handle. + * @param object_id id of the key to delete. + * + * @return The status of the operation. + */ +Sec_Result SecBundle_Delete(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id) { + Sec_RAMBundleData* ram_bundle = NULL; + Sec_RAMBundleData* ram_bundle_parent = NULL; + SEC_SIZE bundles_found = 0; + SEC_SIZE bundles_deleted = 0; + + CHECK_PROCHANDLE(processorHandle) + + /* ram */ + Sec_FindRAMBundleData(processorHandle, object_id, &ram_bundle, &ram_bundle_parent); + if (ram_bundle != NULL) { + if (ram_bundle_parent == NULL) + processorHandle->ram_bundles = ram_bundle->next; + else + ram_bundle_parent->next = ram_bundle->next; + + Sec_Memset(ram_bundle, 0, sizeof(Sec_RAMBundleData)); + + SEC_FREE(ram_bundle); + + ++bundles_found; + ++bundles_deleted; + } + + /* file system */ + if (processorHandle->app_dir != NULL) { + char file_name_bundle[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_bundle, sizeof(file_name_bundle), SEC_BUNDLE_FILENAME_PATTERN, processorHandle->app_dir, + object_id); + if (SecUtils_FileExists(file_name_bundle)) { + SecUtils_RmFile(file_name_bundle); + ++bundles_found; + + if (!SecUtils_FileExists(file_name_bundle)) + ++bundles_deleted; + } + + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + processorHandle->app_dir, object_id); + if (!SecUtils_FileExists(file_name_bundle) && SecUtils_FileExists(file_name_verification)) + SecUtils_RmFile(file_name_verification); + } + + if (bundles_found == 0) + return SEC_RESULT_NO_SUCH_ITEM; + + if (bundles_found != bundles_deleted) { + SEC_LOG_ERROR("Could not delete the specified bundle. It is stored in a non-removable location."); + return SEC_RESULT_ITEM_NON_REMOVABLE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Release the bundle object. + * + * @param bundleHandle bundle handle to release. + * + * @return The status of the operation. + */ +Sec_Result SecBundle_Release(Sec_BundleHandle* bundleHandle) { + CHECK_HANDLE(bundleHandle) + + SEC_FREE(bundleHandle); + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Obtain the bundle data. + * + * @param bundleHandle bundle handle. + * @param buffer pointer to the output buffer that will be filled with bundle data. + * @param buffer_len the length of the output buffer. + * @param written pointer to the output value specifying the number of bytes written to the + * output buffer. + * + * @return The status of the operation. + */ +Sec_Result SecBundle_Export(Sec_BundleHandle* bundleHandle, SEC_BYTE* buffer, SEC_SIZE buffer_len, SEC_SIZE* written) { + CHECK_HANDLE(bundleHandle) + + if (buffer == NULL) { + *written = bundleHandle->bundle_data.bundle_len; + return SEC_RESULT_SUCCESS; + } + + if (buffer_len < bundleHandle->bundle_data.bundle_len) + return SEC_RESULT_BUFFER_TOO_SMALL; + + memcpy(buffer, bundleHandle->bundle_data.bundle, bundleHandle->bundle_data.bundle_len); + *written = bundleHandle->bundle_data.bundle_len; + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Find if the bundle with a specific id has been provisioned. + * + * @param processorHandle secure processor handle. + * @param object_id id of the certificate. + * + * @return 1 if an object has been provisioned, 0 if it has not been. + */ +SEC_BOOL SecBundle_IsProvisioned(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id) { + Sec_BundleHandle* bundleHandle; + + if (SecBundle_GetInstance(processorHandle, object_id, &bundleHandle) != SEC_RESULT_SUCCESS) { + return SEC_FALSE; + } + + SecBundle_Release(bundleHandle); + return SEC_TRUE; +} + +/** + * @brief finds the first available bundle id in the range passed in. + * + * @param proc secure processor. + * @param base bottom of the range to search. + * @param top top of the range to search. + * @return + */ +SEC_OBJECTID SecBundle_ObtainFreeObjectId(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID base, SEC_OBJECTID top) { + SEC_OBJECTID id; + Sec_BundleHandle* bundleHandle; + Sec_Result result; + + for (id = base; id < top; ++id) { + result = SecBundle_GetInstance(processorHandle, id, &bundleHandle); + if (result == SEC_RESULT_SUCCESS) + SecBundle_Release(bundleHandle); + else + return id; + } + + return SEC_OBJECTID_INVALID; +} diff --git a/src/sec_adapter_bundle.h b/src/sec_adapter_bundle.h new file mode 100644 index 0000000..8e7fe31 --- /dev/null +++ b/src/sec_adapter_bundle.h @@ -0,0 +1,29 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_BUNDLE_H +#define SEC_ADAPTER_BUNDLE_H + +#include "sec_adapter_processor.h" +#include "sec_adapter_utils.h" +#include + +void Sec_FindRAMBundleData(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_RAMBundleData** data, + Sec_RAMBundleData** parent); + +#endif // SEC_ADAPTER_BUNDLE_H diff --git a/src/sec_adapter_certificate.c b/src/sec_adapter_certificate.c new file mode 100644 index 0000000..d0c6156 --- /dev/null +++ b/src/sec_adapter_certificate.c @@ -0,0 +1,734 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_processor.h" +#include "sec_adapter_pubops.h" +#include "sec_adapter_utils.h" +#include +#include +#include + +#define CERTIFICATE_BUFFER_SIZE (1024 * 64) + +struct Sec_CertificateHandle_struct { + Sec_ProcessorHandle* processorHandle; + SEC_OBJECTID object_id; + Sec_StorageLoc location; + Sec_CertificateData cert_data; +}; + +static void Sec_FindRAMCertificateData(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_RAMCertificateData** data, Sec_RAMCertificateData** parent) { + *parent = NULL; + *data = processorHandle->ram_certs; + + while ((*data) != NULL) { + if (object_id == (*data)->object_id) + return; + + *parent = (*data); + *data = (*data)->next; + } + + *parent = NULL; +} + +static Sec_Result Sec_RetrieveCertificateData(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_StorageLoc* location, Sec_CertificateData* certData) { + char file_name_cert[SEC_MAX_FILE_PATH_LEN]; + char file_name_info[SEC_MAX_FILE_PATH_LEN]; + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + Sec_RAMCertificateData* ram_cert = NULL; + Sec_RAMCertificateData* ram_cert_parent = NULL; + SEC_SIZE data_read; + + CHECK_PROCHANDLE(processorHandle) + + /* check in RAM */ + Sec_FindRAMCertificateData(processorHandle, object_id, &ram_cert, &ram_cert_parent); + if (ram_cert != NULL) { + memcpy(certData, &(ram_cert->cert_data), sizeof(Sec_CertificateData)); + *location = SEC_STORAGELOC_RAM; + return SEC_RESULT_SUCCESS; + } + + /* check in app dir */ + char* sec_dirs[] = {processorHandle->app_dir, processorHandle->global_dir}; + for (int i = 0; i < 2; i++) { + if (sec_dirs[i] != NULL) { + snprintf(file_name_cert, sizeof(file_name_cert), SEC_CERT_FILENAME_PATTERN, sec_dirs[i], + object_id); + snprintf(file_name_info, sizeof(file_name_info), SEC_CERTINFO_FILENAME_PATTERN, sec_dirs[i], + object_id); + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + sec_dirs[i], object_id); + if (SecUtils_FileExists(file_name_cert) && SecUtils_FileExists(file_name_info)) { + if (SecUtils_ReadFile(file_name_cert, certData->cert, sizeof(certData->cert), &certData->cert_len) != + SEC_RESULT_SUCCESS || + SecUtils_ReadFile(file_name_info, certData->mac, sizeof(certData->mac), &data_read) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not read one of the certificate files"); + return SEC_RESULT_FAILURE; + } + + if (data_read != sizeof(certData->mac)) { + SEC_LOG_ERROR("File is not of the correct size"); + return SEC_RESULT_FAILURE; + } + + if (SecUtils_FileExists(file_name_verification)) { + if (verify_verification_file(processorHandle, file_name_verification, certData->cert, + certData->cert_len, certData->mac, sizeof(certData->mac)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Certificate verification failed"); + return SEC_RESULT_FAILURE; + } + } else { + // If sha file doesn't exist, the bundle file was created by an old SecApi. Just create the + // verification file. + if (write_verification_file(processorHandle, file_name_verification, certData->cert, + certData->cert_len, certData->mac, sizeof(certData->mac)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not write SHA file"); + } + } + + *location = SEC_STORAGELOC_FILE; + return SEC_RESULT_SUCCESS; + } + } + } + + return SEC_RESULT_NO_SUCH_ITEM; +} + +static Sec_Result Sec_SignCertificateData(Sec_ProcessorHandle* processorHandle, Sec_CertificateData* cert_store) { + SEC_SIZE mac_size; + + CHECK_PROCHANDLE(processorHandle) + + if (SecMac_SingleInputId(processorHandle, SEC_MACALGORITHM_HMAC_SHA256, SEC_OBJECTID_CERTSTORE_KEY, + cert_store->cert, cert_store->cert_len, cert_store->mac, &mac_size) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result Sec_ValidateCertificateData(Sec_ProcessorHandle* processorHandle, Sec_CertificateData* cert_store) { + SEC_BYTE mac_buffer[SEC_MAC_MAX_LEN]; + SEC_SIZE mac_size = 0; + + CHECK_PROCHANDLE(processorHandle) + + if (SecMac_SingleInputId(processorHandle, SEC_MACALGORITHM_HMAC_SHA256, SEC_OBJECTID_CERTSTORE_KEY, + cert_store->cert, cert_store->cert_len, mac_buffer, &mac_size) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + if (Sec_Memcmp(mac_buffer, cert_store->mac, mac_size) != 0) { + SEC_LOG_ERROR("Certificate mac does not match the expected value"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result Sec_ProcessCertificateContainer(Sec_ProcessorHandle* processorHandle, Sec_CertificateData* cert_data, + Sec_CertificateContainer data_type, void* data, SEC_SIZE data_len) { + BIO* bio = NULL; + X509* x509 = NULL; + + if (data_type == SEC_CERTIFICATECONTAINER_X509_DER) { + Sec_RSARawPublicKey pub_rsa; + Sec_ECCRawPublicKey pub_ecc; + if (Pubops_ExtractRSAPubFromX509Der(data, data_len, &pub_rsa) != SEC_RESULT_SUCCESS && + Pubops_ExtractECCPubFromX509Der(data, data_len, &pub_ecc) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Pubops_ExtractECCPubFromX509Der failed"); + return SEC_RESULT_FAILURE; + } + + memset(cert_data, 0, sizeof(Sec_CertificateData)); + memcpy(cert_data->cert, data, data_len); + cert_data->cert_len = data_len; + return Sec_SignCertificateData(processorHandle, cert_data); + } + + if (data_type == SEC_CERTIFICATECONTAINER_X509_PEM) { + bio = BIO_new_mem_buf(data, (int) data_len); + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + SEC_BIO_FREE(bio); + bio = NULL; + + if (x509 == NULL) { + SEC_X509_FREE(x509); + SEC_LOG_ERROR("Invalid X509 key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + memset(cert_data, 0, sizeof(Sec_CertificateData)); + cert_data->cert_len = SecUtils_X509ToDerLen(x509, cert_data->cert, sizeof(cert_data->cert)); + if (cert_data->cert_len == 0) { + SEC_X509_FREE(x509); + SEC_LOG_ERROR("Certificate is too large"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + SEC_X509_FREE(x509); + return Sec_SignCertificateData(processorHandle, cert_data); + } + + SEC_LOG_ERROR("Unimplemented certificate container type"); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +static Sec_Result Sec_StoreCertificateData(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_StorageLoc location, Sec_CertificateData* certData) { + Sec_RAMCertificateData* ram_cert; + + if (location == SEC_STORAGELOC_RAM) { + SecCertificate_Delete(processorHandle, object_id); + + ram_cert = calloc(1, sizeof(Sec_RAMCertificateData)); + if (ram_cert == NULL) { + SEC_LOG_ERROR("Malloc failed"); + return SEC_RESULT_FAILURE; + } + ram_cert->object_id = object_id; + memcpy(&(ram_cert->cert_data), certData, sizeof(Sec_CertificateData)); + ram_cert->next = processorHandle->ram_certs; + processorHandle->ram_certs = ram_cert; + + return SEC_RESULT_SUCCESS; + } + + if (location == SEC_STORAGELOC_FILE) { + if (processorHandle->app_dir == NULL) { + SEC_LOG_ERROR("Cannot write file because app_dir is NULL"); + return SEC_RESULT_FAILURE; + } + + SecCertificate_Delete(processorHandle, object_id); + + char file_name_cert[SEC_MAX_FILE_PATH_LEN]; + char file_name_info[SEC_MAX_FILE_PATH_LEN]; + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_cert, sizeof(file_name_cert), SEC_CERT_FILENAME_PATTERN, processorHandle->app_dir, + object_id); + snprintf(file_name_info, sizeof(file_name_info), SEC_CERTINFO_FILENAME_PATTERN, processorHandle->app_dir, + object_id); + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + processorHandle->app_dir, object_id); + + if (SecUtils_WriteFile(file_name_cert, certData->cert, certData->cert_len) != SEC_RESULT_SUCCESS || + SecUtils_WriteFile(file_name_info, certData->mac, sizeof(certData->mac)) != SEC_RESULT_SUCCESS || + write_verification_file(processorHandle, file_name_verification, certData->cert, certData->cert_len, + certData->mac, sizeof(certData->mac)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not write one of the cert files"); + SecUtils_RmFile(file_name_cert); + SecUtils_RmFile(file_name_info); + SecUtils_RmFile(file_name_verification); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + } + + SEC_LOG_ERROR("Unimplemented location type"); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +/** + * @brief Obtain a handle to the provisioned certificate. + * + * @param processorHandle secure processor handle. + * @param object_id id of the certificate. + * @param certHandle output certificate handle. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_GetInstance(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_CertificateHandle** certHandle) { + Sec_Result result; + Sec_CertificateData cert_data; + Sec_StorageLoc location; + + CHECK_PROCHANDLE(processorHandle) + + if (object_id == SEC_OBJECTID_INVALID) { + SEC_LOG_ERROR("Invalid object_id"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + result = Sec_RetrieveCertificateData(processorHandle, object_id, &location, &cert_data); + if (result != SEC_RESULT_SUCCESS) { + return result; + } + + result = Sec_ValidateCertificateData(processorHandle, &cert_data); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_Sec_ValidateCertificateData failed"); + return SEC_RESULT_VERIFICATION_FAILED; + } + + *certHandle = calloc(1, sizeof(Sec_CertificateHandle)); + if (*certHandle == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + (*certHandle)->object_id = object_id; + memcpy(&((*certHandle)->cert_data), &cert_data, sizeof(Sec_CertificateData)); + (*certHandle)->location = location; + (*certHandle)->processorHandle = processorHandle; + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Provision a certificate onto the system. + * + * @param processorHandle secure processor handle. + * @param object_id id of the certificate to provision. + * @param location location where the certificate should be provisioned to. + * @param data_type container type for the input certificate data. + * @param data pointer to certificate container data. + * @param data_len certificate container data length. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_Provision(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_StorageLoc location, Sec_CertificateContainer data_type, SEC_BYTE* data, SEC_SIZE data_len) { + Sec_CertificateData cert_data; + Sec_Result result; + + CHECK_PROCHANDLE(processorHandle) + + if (object_id == SEC_OBJECTID_INVALID) { + SEC_LOG_ERROR("Cannot provision object with SEC_OBJECTID_INVALID"); + return SEC_RESULT_FAILURE; + } + + result = Sec_ProcessCertificateContainer(processorHandle, &cert_data, data_type, data, data_len); + if (result != SEC_RESULT_SUCCESS) + return result; + + return Sec_StoreCertificateData(processorHandle, object_id, location, &cert_data); +} + +/** + * @brief Delete the specified certificate from the system. + * + * @param processorHandle secure processor handle. + * @param object_id id of the certificate to delete. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_Delete(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id) { + Sec_RAMCertificateData* ram_cert = NULL; + Sec_RAMCertificateData* ram_cert_parent = NULL; + SEC_SIZE certs_found = 0; + SEC_SIZE certs_deleted = 0; + + CHECK_PROCHANDLE(processorHandle) + + /* ram */ + Sec_FindRAMCertificateData(processorHandle, object_id, &ram_cert, &ram_cert_parent); + if (ram_cert != NULL) { + if (ram_cert_parent == NULL) + processorHandle->ram_certs = ram_cert->next; + else + ram_cert_parent->next = ram_cert->next; + + Sec_Memset(ram_cert, 0, sizeof(Sec_RAMCertificateData)); + + SEC_FREE(ram_cert); + + ++certs_found; + ++certs_deleted; + } + + /* app_dir */ + if (processorHandle->app_dir != NULL) { + char file_name[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name, sizeof(file_name), SEC_CERT_FILENAME_PATTERN, processorHandle->app_dir, object_id); + if (SecUtils_FileExists(file_name)) { + SecUtils_RmFile(file_name); + ++certs_found; + + if (!SecUtils_FileExists(file_name)) + ++certs_deleted; + } + + char file_name_info[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_info, sizeof(file_name_info), SEC_CERTINFO_FILENAME_PATTERN, processorHandle->app_dir, + object_id); + if (!SecUtils_FileExists(file_name) && SecUtils_FileExists(file_name_info)) { + SecUtils_RmFile(file_name_info); + } + + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + processorHandle->app_dir, object_id); + if (!SecUtils_FileExists(file_name) && SecUtils_FileExists(file_name_verification)) + SecUtils_RmFile(file_name_verification); + } + + if (certs_found == 0) + return SEC_RESULT_NO_SUCH_ITEM; + + if (certs_found != certs_deleted) + return SEC_RESULT_ITEM_NON_REMOVABLE; + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Extract the RSA public key information from the certificate. + * + * @param certificateHandle certificate handle. + * @param public_key pointer to the output structure that will be filled with + * public key data. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_ExtractRSAPublicKey(Sec_CertificateHandle* certificateHandle, + Sec_RSARawPublicKey* public_key) { + CHECK_HANDLE(certificateHandle) + + if (Pubops_ExtractRSAPubFromX509Der(certificateHandle->cert_data.cert, certificateHandle->cert_data.cert_len, + public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_ExtractRSAPubFromX509Der failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Extract the ECC public key information from the certificate. + * + * @param certificateHandle certificate handle. + * @param public_key pointer to the output structure that will be filled with + * public key data. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_ExtractECCPublicKey(Sec_CertificateHandle* certificateHandle, + Sec_ECCRawPublicKey* public_key) { + CHECK_HANDLE(certificateHandle) + + if (Pubops_ExtractECCPubFromX509Der(certificateHandle->cert_data.cert, certificateHandle->cert_data.cert_len, + public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_ExtractECCPubFromX509Der failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Verify certificate signature. + * + * @param certificateHandle certificate handle. + * @param keyHandle handle of the private key used for signing or it's corresponding + * public key. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_Verify(Sec_CertificateHandle* certificateHandle, Sec_KeyHandle* keyHandle) { + Sec_RSARawPublicKey rsa_public_key; + Sec_ECCRawPublicKey ecc_public_key; + Sec_Result result = SEC_RESULT_FAILURE; + + CHECK_HANDLE(certificateHandle) + CHECK_HANDLE(keyHandle) + + switch (SecKey_GetKeyType(keyHandle)) { + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + if (SecKey_ExtractRSAPublicKey(keyHandle, &rsa_public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractRSAPublicKey failed"); + break; + } + + result = SecCertificate_VerifyWithRawRSAPublicKey(certificateHandle, &rsa_public_key); + break; + + case SEC_KEYTYPE_ECC_NISTP256: + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + if (SecKey_ExtractECCPublicKey(keyHandle, &ecc_public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractECCPublicKey failed"); + break; + } + + result = SecCertificate_VerifyWithRawECCPublicKey(certificateHandle, &ecc_public_key); + break; + + default: + break; // defaults to FAILURE + } + + return result; +} + +/** + * @brief Verify certificate signature. + * + * @param certificateHandle certificate handle. + * @param public_key structure holding the public key information. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_VerifyWithRawRSAPublicKey(Sec_CertificateHandle* certificateHandle, + Sec_RSARawPublicKey* public_key) { + CHECK_HANDLE(certificateHandle) + if (public_key == NULL) { + SEC_LOG_ERROR("NULL public_key"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (Pubops_VerifyX509WithPubRsa(certificateHandle->cert_data.cert, certificateHandle->cert_data.cert_len, + public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Pubops_VerifyX509WithPubRsa failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Verify certificate signature - ECC. + * + * @param certificateHandle certificate handle. + * @param public_key structure holding the public key information. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_VerifyWithRawECCPublicKey(Sec_CertificateHandle* certificateHandle, + Sec_ECCRawPublicKey* public_key) { + CHECK_HANDLE(certificateHandle) + if (public_key == NULL) { + SEC_LOG_ERROR("NULL public_key"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (Pubops_VerifyX509WithPubEcc(certificateHandle->cert_data.cert, certificateHandle->cert_data.cert_len, + public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Pubops_VerifyX509WithPubEcc failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Obtain the certificate data in clear text DER format. + * + * @param certificateHandle certificate handle. + * @param buffer pointer to the output buffer that will be filled with certificate data. + * @param buffer_len the length of the output buffer. + * @param written pointer to the output value specifying the number of bytes written to the + * output buffer. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_Export(Sec_CertificateHandle* certificateHandle, SEC_BYTE* buffer, SEC_SIZE buffer_len, + SEC_SIZE* written) { + CHECK_HANDLE(certificateHandle) + + if (buffer == NULL) { + *written = certificateHandle->cert_data.cert_len; + return SEC_RESULT_SUCCESS; + } + + if (buffer_len < certificateHandle->cert_data.cert_len) + return SEC_RESULT_BUFFER_TOO_SMALL; + + memcpy(buffer, certificateHandle->cert_data.cert, certificateHandle->cert_data.cert_len); + *written = certificateHandle->cert_data.cert_len; + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Release the certificate object. + * + * @param certificateHandle certificate handle. + * + * @return The status of the operation. + */ +Sec_Result SecCertificate_Release(Sec_CertificateHandle* certificateHandle) { + CHECK_HANDLE(certificateHandle) + SEC_FREE(certificateHandle); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Obtain a list of all provisioned items. At most maxNumItems will be written to the output buffer. + * + * @param proc Secure processor handle. + * @param items buffer that the found item ids will be stored in. + * @param maxNumItems maximum number of items that can be written to the output buffer. + * + * @return number of items written. + */ +SEC_SIZE SecCertificate_List(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID* items, SEC_SIZE maxNumItems) { + Sec_RAMCertificateData* cert; + SEC_SIZE num_items = 0; + + CHECK_PROCHANDLE(processorHandle) + + /* look in RAM */ + cert = processorHandle->ram_certs; + while (cert != NULL) { + num_items = SecUtils_UpdateItemList(items, maxNumItems, num_items, cert->object_id); + cert = cert->next; + } + + /* look in file system */ + if (processorHandle->global_dir != NULL) { + num_items = SecUtils_UpdateItemListFromDir(items, maxNumItems, num_items, processorHandle->global_dir, + SEC_CERT_FILENAME_EXT); + } + + if (processorHandle->app_dir != NULL) { + num_items = SecUtils_UpdateItemListFromDir(items, maxNumItems, num_items, processorHandle->app_dir, + SEC_CERT_FILENAME_EXT); + } + + return num_items; +} + +X509* SecCertificate_DerToX509(void* mem, SEC_SIZE len) { + X509* x509 = NULL; + const SEC_BYTE* ptr = (const SEC_BYTE*) mem; + x509 = d2i_X509(&x509, &ptr, len); + return x509; +} + +Sec_KeyType SecCertificate_GetKeyType(Sec_CertificateHandle* certificateHandle) { + Sec_RSARawPublicKey pub_rsa; + if (Pubops_ExtractRSAPubFromX509Der(certificateHandle->cert_data.cert, certificateHandle->cert_data.cert_len, + &pub_rsa) == SEC_RESULT_SUCCESS) { + switch (Sec_BEBytesToUint32(pub_rsa.modulus_len_be)) { + case 128: + return SEC_KEYTYPE_RSA_1024_PUBLIC; + + case 256: + return SEC_KEYTYPE_RSA_2048_PUBLIC; + + case 384: + return SEC_KEYTYPE_RSA_3072_PUBLIC; + + default: + SEC_LOG_ERROR("Invalid RSA modulus size encountered: %d", Sec_BEBytesToUint32(pub_rsa.modulus_len_be)); + return SEC_KEYTYPE_NUM; + } + } + + Sec_ECCRawPublicKey pub_ecc; + if (Pubops_ExtractECCPubFromX509Der(certificateHandle->cert_data.cert, certificateHandle->cert_data.cert_len, + &pub_ecc) == SEC_RESULT_SUCCESS) { + return SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + } + + SEC_LOG_ERROR("Could not find valid pub key in the certificate"); + return SEC_KEYTYPE_NUM; +} + +/** + * @brief Obtain an OpenSSL X509 certificate from the Security API cert handle. + */ +X509* SecCertificate_ToX509(Sec_CertificateHandle* certificateHandle) { + SEC_BYTE exported_cert[CERTIFICATE_BUFFER_SIZE]; + SEC_SIZE exported_cert_len; + + if (SecCertificate_Export(certificateHandle, exported_cert, sizeof(exported_cert), &exported_cert_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_Export failed"); + return NULL; + } + + return SecCertificate_DerToX509(exported_cert, exported_cert_len); +} + +/** + * @brief Find if the certificate with a specific id has been provisioned. + * + * @param processorHandle secure processor handle. + * @param object_id id of the certificate. + * + * @return 1 if an object has been provisioned, 0 if it has not been. + */ +SEC_BOOL SecCertificate_IsProvisioned(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id) { + Sec_CertificateHandle* certificateHandle; + + if (SecCertificate_GetInstance(processorHandle, object_id, &certificateHandle) != SEC_RESULT_SUCCESS) { + return SEC_FALSE; + } + + SecCertificate_Release(certificateHandle); + return SEC_TRUE; +} + +/** + * @brief Obtain the size of the certificate in DER format. + * + * @param certificateHandle certificate whose size we want to obtain. + */ +SEC_SIZE SecCertificate_GetSize(Sec_CertificateHandle* certificateHandle) { + SEC_BYTE buffer[SEC_CERT_MAX_DATA_LEN]; + SEC_SIZE written; + + if (SecCertificate_Export(certificateHandle, buffer, sizeof(buffer), &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_Export failed"); + return 0; + } + + return written; +} + +/** + * @brief finds the first available certificate id in the range passed in. + * + * @param proc secure processor. + * @param base bottom of the range to search. + * @param top top of the range to search. + * @return + */ +SEC_OBJECTID SecCertificate_ObtainFreeObjectId(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID base, + SEC_OBJECTID top) { + SEC_OBJECTID id; + Sec_CertificateHandle* certificateHandle; + Sec_Result result; + + for (id = base; id < top; ++id) { + result = SecCertificate_GetInstance(processorHandle, id, &certificateHandle); + + if (result == SEC_RESULT_SUCCESS) + SecCertificate_Release(certificateHandle); + else + return id; + } + + return SEC_OBJECTID_INVALID; +} diff --git a/src/sec_adapter_cipher.c b/src/sec_adapter_cipher.c new file mode 100644 index 0000000..7921220 --- /dev/null +++ b/src/sec_adapter_cipher.c @@ -0,0 +1,1169 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_cipher.h" +#include + +#define RSA_OAEP_PADDING_SIZE 42 + +struct Sec_CipherHandle_struct { + Sec_ProcessorHandle* processorHandle; + union { + sa_crypto_cipher_context context; + RSA* rsa; + EC_KEY* ec; + } cipher; + + Sec_CipherAlgorithm algorithm; + Sec_CipherMode mode; + SEC_BOOL last; + SEC_BOOL svp_required; + Sec_KeyHandle* keyHandle; +}; + +static sa_cipher_mode get_cipher_mode(Sec_CipherMode mode); + +static SEC_BOOL rsa_encrypt_pkcs1v15(void* out, size_t* out_length, const RSA* rsa, const void* in, size_t in_length); + +static SEC_BOOL rsa_encrypt_oaep(void* out, size_t* out_length, const RSA* rsa, const void* in, size_t in_length); + +static SEC_BOOL is_svp_required(Sec_KeyProperties* props); + +/** + * @brief Initialize cipher object. + * + * @param processorHandle secure processor handle. + * @param algorithm cipher algorithm to use. + * @param mode cipher mode to use. + * @param keyHandle handle to use. + * @param iv initialization vector value. Can be set to NULL is the cipher + * algorithm chosen does not require it. + * @param cipherHandle pointer to a cipher handle that will be set once + * the cipher object is constructed. + * + * @return The status of the operation. + */ +Sec_Result SecCipher_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_CipherAlgorithm algorithm, + Sec_CipherMode mode, Sec_KeyHandle* keyHandle, SEC_BYTE* iv, Sec_CipherHandle** cipherHandle) { + CHECK_PROCHANDLE(processorHandle) + CHECK_HANDLE(keyHandle) + Sec_Result result; + Sec_KeyProperties key_properties; + + result = SecKey_GetProperties(keyHandle, &key_properties); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetProperties failed"); + return result; + } + + SEC_BOOL svp_required = is_svp_required(&key_properties); + result = SecCipher_IsValidKey(key_properties.keyType, algorithm, mode, iv); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Invalid key used for specified algorithm"); + return result; + } + + // Output Protection tests are delegated to SecApi 3.0, so removed from here. + Sec_KeyType key_type = SecKey_GetKeyType(keyHandle); + const Sec_Key* key = get_key(keyHandle); + switch (key_type) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + case SEC_KEYTYPE_ECC_NISTP256: + case SEC_KEYTYPE_RSA_3072: { + sa_cipher_algorithm cipher_algorithm; + void* parameters; + result = get_cipher_algorithm(algorithm, SEC_FALSE, &cipher_algorithm, ¶meters, iv, 0, 0); + if (result != SEC_RESULT_SUCCESS) + return result; + + sa_cipher_mode cipher_mode = get_cipher_mode(mode); + sa_crypto_cipher_context context; + + sa_status status; + status = sa_crypto_cipher_init(&context, cipher_algorithm, cipher_mode, key->handle, parameters); + SEC_FREE(parameters); + CHECK_STATUS(status) + + *cipherHandle = calloc(1, sizeof(Sec_CipherHandle)); + (*cipherHandle)->cipher.context = context; + break; + } + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: { + if (algorithm != SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING && + algorithm != SEC_CIPHERALGORITHM_RSA_OAEP_PADDING) { + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (mode != SEC_CIPHERMODE_ENCRYPT && mode != SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) { + return SEC_RESULT_INVALID_PARAMETERS; + } + + *cipherHandle = calloc(1, sizeof(Sec_CipherHandle)); + (*cipherHandle)->cipher.rsa = key->rsa; + break; + } + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: { + if (algorithm != SEC_CIPHERALGORITHM_ECC_ELGAMAL) { + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (mode != SEC_CIPHERMODE_ENCRYPT && mode != SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) { + return SEC_RESULT_INVALID_PARAMETERS; + } + + *cipherHandle = calloc(1, sizeof(Sec_CipherHandle)); + (*cipherHandle)->cipher.ec = key->ec_key; + break; + } + default: + SEC_LOG_ERROR("unsupported key type %u", key_type); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + (*cipherHandle)->keyHandle = keyHandle; + (*cipherHandle)->processorHandle = processorHandle; + (*cipherHandle)->algorithm = algorithm; + (*cipherHandle)->mode = mode; + (*cipherHandle)->svp_required = svp_required; + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Update the IV on the cipher handle. + */ +Sec_Result SecCipher_UpdateIV(Sec_CipherHandle* cipherHandle, SEC_BYTE* iv) { + CHECK_HANDLE(cipherHandle) + + // Update IV unimplemented for RSA and EC keys. + Sec_KeyType key_type = SecKey_GetKeyType(cipherHandle->keyHandle); + sa_status status; + if (key_type == SEC_KEYTYPE_AES_128 || key_type == SEC_KEYTYPE_AES_256) { + status = sa_crypto_cipher_update_iv(cipherHandle->cipher.context, iv, SEC_AES_BLOCK_SIZE); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; + } + + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +/** + * @brief En/De-cipher specified input data into and output buffer. + * + * @param cipherHandle cipher handle. + * @param input pointer to input data. + * @param inputSize the length of input data in bytes. + * @param lastInput SEC_BOOLean value specifying whether this is the last chunk + * of input that will be processed. + * @param output pointer to output data buffer. + * @param outputSize the size of the output buffer. + * @param bytesWritten pointer to a value that will be set to number + * of bytes written to the output buffer. + * + * @return The status of the operation. + */ +Sec_Result SecCipher_Process(Sec_CipherHandle* cipherHandle, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BOOL lastInput, + SEC_BYTE* output, SEC_SIZE outputSize, SEC_SIZE* bytesWritten) { + CHECK_HANDLE(cipherHandle) + SEC_SIZE output_size_needed = 0; + + if (cipherHandle->svp_required) { + SEC_LOG_ERROR("An opaque buffer must be used for cipher processing when SVP is required."); + return SEC_RESULT_FAILURE; + } + + if (cipherHandle->last != 0) { + SEC_LOG_ERROR("Last block has already been processed"); + return SEC_RESULT_FAILURE; + } + + cipherHandle->last = lastInput; + if (SecCipher_GetRequiredOutputSize(cipherHandle->algorithm, cipherHandle->mode, + SecKey_GetKeyType(cipherHandle->keyHandle), inputSize, &output_size_needed, lastInput) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetRequiredOutputSize failed"); + return SEC_RESULT_FAILURE; + } + + if (output == NULL) { + *bytesWritten = output_size_needed; + return SEC_RESULT_SUCCESS; + } + + if (output_size_needed > outputSize) { + SEC_LOG_ERROR("Output buffer is too small"); + return SEC_RESULT_FAILURE; + } + + size_t output_count = outputSize; + Sec_KeyType key_type = SecKey_GetKeyType(cipherHandle->keyHandle); + switch (key_type) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + case SEC_KEYTYPE_ECC_NISTP256: + case SEC_KEYTYPE_RSA_3072: { + sa_buffer out_buffer; + out_buffer.buffer_type = SA_BUFFER_TYPE_CLEAR; + out_buffer.context.clear.buffer = output; + out_buffer.context.clear.length = outputSize; + out_buffer.context.clear.offset = 0; + + sa_buffer in_buffer; + in_buffer.buffer_type = SA_BUFFER_TYPE_CLEAR; + in_buffer.context.clear.buffer = input; + in_buffer.context.clear.length = inputSize; + in_buffer.context.clear.offset = 0; + + bool pkcs7 = cipherHandle->algorithm == SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING || + cipherHandle->algorithm == SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING; + if (lastInput && pkcs7) { + *bytesWritten = 0; + + // In encrypt mode, if the last block is complete add a padding block. In decrypt mode, + // the last block is the padding block. + size_t bytes_to_process = cipherHandle->mode == SEC_CIPHERMODE_DECRYPT ? + ((inputSize / SEC_AES_BLOCK_SIZE) - 1) * SEC_AES_BLOCK_SIZE : + (inputSize / SEC_AES_BLOCK_SIZE) * SEC_AES_BLOCK_SIZE; + size_t bytes_left = inputSize - bytes_to_process; + sa_status status = sa_crypto_cipher_process(&out_buffer, cipherHandle->cipher.context, &in_buffer, + &bytes_to_process); + CHECK_STATUS(status) + *bytesWritten += bytes_to_process; + + status = sa_crypto_cipher_process_last(&out_buffer, cipherHandle->cipher.context, &in_buffer, + &bytes_left, NULL); + CHECK_STATUS(status) + *bytesWritten += bytes_left; + } else { + size_t bytes_to_process = inputSize; + sa_status status = sa_crypto_cipher_process(&out_buffer, cipherHandle->cipher.context, &in_buffer, + &bytes_to_process); + CHECK_STATUS(status) + *bytesWritten = bytes_to_process; + } + + break; + } + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + if (cipherHandle->algorithm == SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING) { + if (rsa_encrypt_pkcs1v15(output, &output_count, cipherHandle->cipher.rsa, input, inputSize) == + SEC_FALSE) + return SEC_RESULT_FAILURE; + } else if (cipherHandle->algorithm == SEC_CIPHERALGORITHM_RSA_OAEP_PADDING) { + if (rsa_encrypt_oaep(output, &output_count, cipherHandle->cipher.rsa, input, inputSize) == SEC_FALSE) + return SEC_RESULT_FAILURE; + } else + return SEC_RESULT_FAILURE; + + *bytesWritten = output_count; + break; + + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + *bytesWritten = SecUtils_ElGamal_Encrypt(cipherHandle->cipher.ec, input, inputSize, output, outputSize); + if (*bytesWritten == -1) { + *bytesWritten = 0; + return SEC_RESULT_FAILURE; + } + + break; + + default: + SEC_LOG_ERROR("unsupported key type %u", key_type); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief En/De-cipher specified fragmented input data into and output buffer. + * + * @param cipherHandle cipher handle. + * @param input pointer to input data. + * @param inputSize the length of input data in bytes. + * @param lastInput SEC_BOOLean value specifying whether this is the last chunk + * of input that will be processed. + * @param output pointer to output data buffer. + * @param outputSize the size of the output buffer. + * @param bytesWritten pointer to a value that will be set to number + * of bytes written to the output buffer. + * @param fragmentOffset offset in bytes of the fragment data within larger packet. + * @param fragmentSize length in bytes of the data fragment. + * @param fragmentPeriod the length in bytes of the packet containing the fragment. + * + * @return The status of the operation. + */ +Sec_Result SecCipher_ProcessFragmented(Sec_CipherHandle* cipherHandle, SEC_BYTE* input, SEC_SIZE inputSize, + SEC_BOOL lastInput, SEC_BYTE* output, SEC_SIZE outputSize, SEC_SIZE* bytesWritten, SEC_SIZE fragmentOffset, + SEC_SIZE fragmentSize, SEC_SIZE fragmentPeriod) { + SEC_SIZE lbw; + SEC_SIZE output_size_required = 0; + Sec_Result result = SEC_RESULT_FAILURE; + + CHECK_HANDLE(cipherHandle) + + *bytesWritten = 0; + + if (SecCipher_GetRequiredOutputSizeFragmented(cipherHandle->algorithm, cipherHandle->mode, + SecKey_GetKeyType(cipherHandle->keyHandle), inputSize, &output_size_required, lastInput, + fragmentOffset, fragmentSize, fragmentPeriod) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetRequiredOutputSizeFragmented failed"); + return result; + } + + if (output == NULL) { + *bytesWritten = output_size_required; + result = SEC_RESULT_SUCCESS; + return result; + } + + if (output_size_required > outputSize) { + SEC_LOG_ERROR("Output buffer is too small"); + result = SEC_RESULT_INVALID_INPUT_SIZE; + return result; + } + + switch (cipherHandle->algorithm) { + case SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING: + case SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING: + case SEC_CIPHERALGORITHM_AES_CTR: + if (input != output) { + memcpy(output, input, inputSize); + } + + *bytesWritten = inputSize; + while (inputSize > 0) { + if (SecCipher_Process(cipherHandle, output + fragmentOffset, fragmentSize, + lastInput && (inputSize == fragmentPeriod), output + fragmentOffset, fragmentSize, + &lbw) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return result; + } + + output += fragmentPeriod; + inputSize -= fragmentPeriod; + } + + break; + + default: + SEC_LOG_ERROR("Unimplemented cipher algorithm"); + return result; + } + + result = SEC_RESULT_SUCCESS; + return result; +} + +/** + * @brief Process the opaque buffers that were obtained with Sec_OpaqueBufferMalloc. + * + * @param cipherHandle cipher handle. + * @param inputHandle opaque buffer containing input. + * @param outputHandle opaque buffer for writing output. + * @param inputSize the length of input to process. + * @param lastInput SEC_BOOLean value specifying whether this is the last chunk + * of input that will be processed. + * @param bytesWritten pointer to a value that will be set to number. + * of bytes written to the output buffer. + */ +Sec_Result SecCipher_ProcessOpaque(Sec_CipherHandle* cipherHandle, Sec_OpaqueBufferHandle* inOpaqueBufferHandle, + Sec_OpaqueBufferHandle* outOpaqueBufferHandle, SEC_SIZE inputSize, SEC_BOOL lastInput, SEC_SIZE* bytesWritten) { + CHECK_HANDLE(cipherHandle) + if (inOpaqueBufferHandle == NULL) { + SEC_LOG_ERROR("Invalid inputHandle"); + return SEC_RESULT_INVALID_HANDLE; + } + + if (outOpaqueBufferHandle == NULL) { + SEC_LOG_ERROR("Invalid outputHandle"); + return SEC_RESULT_INVALID_HANDLE; + } + + SEC_SIZE output_size_needed = 0; + + if (cipherHandle->last != 0) { + SEC_LOG_ERROR("Last block has already been processed"); + return SEC_RESULT_FAILURE; + } + + cipherHandle->last = lastInput; + if (SecCipher_GetRequiredOutputSize(cipherHandle->algorithm, cipherHandle->mode, + SecKey_GetKeyType(cipherHandle->keyHandle), inputSize, &output_size_needed, + lastInput) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetRequiredOutputSize failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType key_type = SecKey_GetKeyType(cipherHandle->keyHandle); + switch (key_type) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: { + sa_buffer out_buffer; + out_buffer.buffer_type = SA_BUFFER_TYPE_SVP; + out_buffer.context.svp.buffer = outOpaqueBufferHandle->svp_buffer; + out_buffer.context.svp.offset = 0; + + sa_buffer in_buffer; + in_buffer.buffer_type = SA_BUFFER_TYPE_SVP; + in_buffer.context.svp.buffer = inOpaqueBufferHandle->svp_buffer; + in_buffer.context.svp.offset = 0; + + size_t bytes_to_process = inputSize; + bool pkcs7 = cipherHandle->algorithm == SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING || + cipherHandle->algorithm == SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING; + if (lastInput && pkcs7) { + sa_status status = sa_crypto_cipher_process_last(&out_buffer, cipherHandle->cipher.context, &in_buffer, + &bytes_to_process, NULL); + CHECK_STATUS(status) + } else { + sa_status status = sa_crypto_cipher_process(&out_buffer, cipherHandle->cipher.context, &in_buffer, + &bytes_to_process); + CHECK_STATUS(status) + } + + *bytesWritten = bytes_to_process; + break; + } + default: + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecCipher_ProcessCtrWithOpaqueDataShift(Sec_CipherHandle* cipherHandle, + Sec_OpaqueBufferHandle* inOpaqueBufferHandle, Sec_OpaqueBufferHandle* outOpaqueBufferHandle, SEC_SIZE inputSize, + SEC_SIZE* bytesWritten, SEC_SIZE dataShift) { + // Original implementation never worked right and function has not been implemented by any vendor. + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +/** + * @brief Perform cipher operation on the opaque input handle and check the output against the expected value. + * + * @param cipherHandle pointer to Sec_CipherHandle. + * @param void inputHandle pointer to opaque buffer containing input. + * @param SEC_SIZE checkLength number of bytes used for comparison. + * @param SEC_BYTE expected expected value used for comparison. + */ +Sec_Result SecCipher_KeyCheckOpaque(Sec_CipherHandle* cipherHandle, Sec_OpaqueBufferHandle* opaqueBufferHandle, + SEC_SIZE checkLength, SEC_BYTE* expected) { + if (opaqueBufferHandle == NULL) { + SEC_LOG_ERROR("Null inputHandle"); + return SEC_RESULT_FAILURE; + } + + if (checkLength < 8 || checkLength > SEC_AES_BLOCK_SIZE) { + SEC_LOG_ERROR("Length must be >=8 and <=16"); + return SEC_RESULT_FAILURE; + } + + if (cipherHandle == NULL) { + SEC_LOG_ERROR("Null cipherHandle"); + return SEC_RESULT_FAILURE; + } + + sa_status status; + sa_buffer in_buffer; + in_buffer.buffer_type = SA_BUFFER_TYPE_SVP; + in_buffer.context.svp.buffer = opaqueBufferHandle->svp_buffer; + in_buffer.context.svp.offset = 0; + if (cipherHandle->mode == SEC_CIPHERMODE_ENCRYPT) + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + + const Sec_Key* key = get_key(cipherHandle->keyHandle); + status = sa_svp_key_check(key->handle, &in_buffer, SEC_AES_BLOCK_SIZE, expected, SEC_AES_BLOCK_SIZE); + + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Release the cipher object. + * + * @param cipherHandle cipher handle. + * + * @return The status of the operation. + */ +Sec_Result SecCipher_Release(Sec_CipherHandle* cipherHandle) { + CHECK_HANDLE(cipherHandle) + + Sec_KeyType key_type = SecKey_GetKeyType(cipherHandle->keyHandle); + switch (key_type) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + case SEC_KEYTYPE_ECC_NISTP256: + case SEC_KEYTYPE_RSA_3072: + sa_crypto_cipher_release(cipherHandle->cipher.context); + break; + + default: + break; + } + + SEC_FREE(cipherHandle); + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecCipher_ProcessCtrWithDataShift(Sec_CipherHandle* cipherHandle, SEC_BYTE* input, SEC_SIZE inputSize, + SEC_BYTE* output, SEC_SIZE outputSize, SEC_SIZE* bytesWritten, SEC_SIZE dataShift) { + // Original implementation never worked right and function has not been implemented by any vendor. + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +int SecCipher_IsModeEncrypt(Sec_CipherMode mode) { + return mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM; +} + +int SecCipher_IsModeDecrypt(Sec_CipherMode mode) { + return mode == SEC_CIPHERMODE_DECRYPT || mode == SEC_CIPHERMODE_DECRYPT_NATIVEMEM; +} + +/** + * @brief Check whether the supplied key and iv are valid for the chosen cipher algorithm. + * + * @param key_type key type. + * @param algorithm cipher algorithm. + * @param mode cipher mode. + * @param iv initialization vector. + * + * @return status of the call. + */ +Sec_Result SecCipher_IsValidKey(Sec_KeyType key_type, Sec_CipherAlgorithm alg, Sec_CipherMode mode, + const SEC_BYTE* iv) { + switch (alg) { + case SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING: + case SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING: + case SEC_CIPHERALGORITHM_AES_CTR: + if (SecKey_IsAES(key_type)) { + if (iv == NULL && alg != SEC_CIPHERALGORITHM_AES_CTR && alg != SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING && + alg != SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING) { + SEC_LOG_ERROR("IV cannot be null in CBC and CTR modes."); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + } else { + SEC_LOG_ERROR("Not an AES key: %d", key_type); + return SEC_RESULT_FAILURE; + } + + case SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING: + case SEC_CIPHERALGORITHM_RSA_OAEP_PADDING: + if (SecCipher_IsModeEncrypt(mode)) { + if (!SecKey_IsRsa(key_type)) { + SEC_LOG_ERROR("Not an RSA key"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + } else if (SecCipher_IsModeDecrypt(mode)) { + if (!SecKey_IsPrivRsa(key_type)) { + SEC_LOG_ERROR("Not an RSA key"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + } else { + SEC_LOG_ERROR("Unknown cipher mode encountered: %d", mode); + return SEC_RESULT_FAILURE; + } + + case SEC_CIPHERALGORITHM_ECC_ELGAMAL: + if (SecCipher_IsModeEncrypt(mode)) { + if (!SecKey_IsEcc(key_type)) { + SEC_LOG_ERROR("Not an ECC key"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + } else if (SecCipher_IsModeDecrypt(mode)) { + if (!SecKey_IsPrivEcc(key_type)) { + SEC_LOG_ERROR("Not an ECC key"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + } else { + SEC_LOG_ERROR("Unknown cipher mode encountered: %d", mode); + return SEC_RESULT_FAILURE; + } + + default: + break; + } + + SEC_LOG_ERROR("Unimplemented algorithm: %d", alg); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +SEC_BOOL SecCipher_IsCBC(Sec_CipherAlgorithm alg) { + return alg == SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING || alg == SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING; +} + +/** + * @brief get the required output buffer size for the specified combination of input parameters. + * + * Write required output buffer size for cipher configuration. + * Returns SEC_RESULT_SUCCESS if the cipher configuration parameters are valid. + * Returns SEC_RESULT_FAILURE otherwise (e.g. input size is not valid). + * + * @param algorithm cipher algorithm. + * @param mode cipher mode. + * @param keyType key type. + * @param inputSize size of the input buffer. + * @param outputSize size of the output buffer. + * @param lastInput is this the last input to the cipher. + * + * @return status of the call. + */ +Sec_Result SecCipher_GetRequiredOutputSize(Sec_CipherAlgorithm alg, Sec_CipherMode mode, Sec_KeyType keyType, + SEC_SIZE inputSize, SEC_SIZE* outputSize, SEC_BOOL lastInput) { + SEC_SIZE max_clear_size; + SEC_SIZE rsa_block_size; + SEC_SIZE bn_size; + *outputSize = 0; + + switch (alg) { + case SEC_CIPHERALGORITHM_AES_CTR: + *outputSize = inputSize; + break; + + case SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING: + if (inputSize % SEC_AES_BLOCK_SIZE != 0) { + SEC_LOG_ERROR("Input size is not a multiple of block size"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + *outputSize = inputSize; + break; + + case SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING: + case SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING: + if (SecCipher_IsModeEncrypt(mode) && !lastInput && inputSize % SEC_AES_BLOCK_SIZE != 0) { + SEC_LOG_ERROR("Encryption input size is not a multiple of block size and is not last input"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + if (SecCipher_IsModeDecrypt(mode) && inputSize % SEC_AES_BLOCK_SIZE != 0) { + SEC_LOG_ERROR("Decryption input size is not a multiple of block size"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + *outputSize = (inputSize / 16) * 16 + ((lastInput && (SecCipher_IsModeEncrypt(mode))) ? 16 : 0); + break; + + case SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING: + case SEC_CIPHERALGORITHM_RSA_OAEP_PADDING: + rsa_block_size = *outputSize = SecKey_GetKeyLenForKeyType(keyType); + + if (alg == SEC_CIPHERALGORITHM_RSA_OAEP_PADDING) { + max_clear_size = rsa_block_size - RSA_OAEP_PADDING_SIZE; + } else { + max_clear_size = rsa_block_size - RSA_PKCS1_PADDING_SIZE; + } + + if (SecCipher_IsModeDecrypt(mode) && inputSize != rsa_block_size) { + SEC_LOG_ERROR("Decrypt input size %u is not equal to the RSA block size", inputSize); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + if ((SecCipher_IsModeEncrypt(mode)) && inputSize > max_clear_size) { + SEC_LOG_ERROR("Encrypt input size is too large"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + break; + + case SEC_CIPHERALGORITHM_ECC_ELGAMAL: + bn_size = SecKey_GetKeyLenForKeyType(keyType); // one bignum + if (SecCipher_IsModeEncrypt(mode)) { + if (inputSize != bn_size) { // one bignum + SEC_LOG_ERROR("Input size invalid for El Gamal encryption"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + *outputSize = 4 * bn_size; // two points, which are four bignums + } else { + if (inputSize != 4 * bn_size) { // two points, which are four bignums + SEC_LOG_ERROR("Input size invalid for El Gamal encryption"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + *outputSize = bn_size; // one bignum + } + + break; + + default: + SEC_LOG_ERROR("Unimplemented cipher algorithm"); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief get the required output buffer length for fragemnted encryption/decryption. + * + * @param algorithm cipher algorithm. + * @param mode cipher mode. + * @param keyType key type. + * @param inputSize size of the input buffer. + * @param outputSize size of the output buffer. + * @param lastInput is this the last input to the cipher. + * @param framentOffset offset in bytes of the fragment data within larger packet. + * @param fragmentSize length in bytes of the data fragment. + * @param fragmentPeriod the length in bytes of the packet containing the fragment. + * + * @return status of the call. + */ +Sec_Result SecCipher_GetRequiredOutputSizeFragmented(Sec_CipherAlgorithm alg, Sec_CipherMode mode, Sec_KeyType keyType, + SEC_SIZE inputSize, SEC_SIZE* outputSizeNeeded, SEC_BOOL lastInput, SEC_SIZE fragmentOffset, + SEC_SIZE fragmentSize, SEC_SIZE fragmentPeriod) { + *outputSizeNeeded = 0; + + if ((inputSize % fragmentPeriod) != 0) { + SEC_LOG_ERROR("Input size is not a multiple of a fragment period"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + if ((fragmentSize % SEC_AES_BLOCK_SIZE) != 0) { + SEC_LOG_ERROR("Fragment size is not a multiple of block size"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + if ((fragmentOffset + fragmentSize) > fragmentPeriod) { + SEC_LOG_ERROR("Invalid fragment parameters"); + return SEC_RESULT_INVALID_INPUT_SIZE; + } + + switch (alg) { + case SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_CTR: + case SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING: + case SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING: + *outputSizeNeeded = inputSize; + break; + + default: + SEC_LOG_ERROR("Unimplemented cipher algorithm"); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Apply PKCS7 padding to the AES input block. + * + * @param inputBlock input data to pad. + * @param inputSize size of input data. + * @param outputBlock Output block. Has to be the size of SEC_AES_BLOCKSIZE. + */ +void SecCipher_PadAESPKCS7Block(SEC_BYTE* inputBlock, SEC_SIZE inputSize, SEC_BYTE* outputBlock) { + SEC_BYTE pad_val = (SEC_BYTE) (SEC_AES_BLOCK_SIZE - inputSize % SEC_AES_BLOCK_SIZE); + memset(outputBlock, pad_val, SEC_AES_BLOCK_SIZE); + memcpy(outputBlock, inputBlock, inputSize % SEC_AES_BLOCK_SIZE); +} + +/** + * @brief Checks whether the specified cipher algorithm is AES. + */ +SEC_BOOL SecCipher_IsAES(Sec_CipherAlgorithm alg) { + return alg == SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING || alg == SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING || + alg == SEC_CIPHERALGORITHM_AES_CTR || alg == SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING || + alg == SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING; +} + +/** + * @brief Checks whether the specified cipher algorithm is RSA. + */ +SEC_BOOL SecCipher_IsRsa(Sec_CipherAlgorithm alg) { + return alg == SEC_CIPHERALGORITHM_RSA_OAEP_PADDING || alg == SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING; +} + +/** + * @brief Checks whether the specified cipher algorithm is ECC. + */ +SEC_BOOL SecCipher_IsEcc(Sec_CipherAlgorithm alg) { + return alg == SEC_CIPHERALGORITHM_ECC_ELGAMAL; +} + +Sec_Result SecCipher_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_CipherAlgorithm alg, Sec_CipherMode mode, + Sec_KeyHandle* keyHandle, SEC_BYTE* iv, SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* output, + SEC_SIZE output_len, SEC_SIZE* written) { + Sec_Result result; + Sec_CipherHandle* cipherHandle = NULL; + + result = SecCipher_GetInstance(processorHandle, alg, mode, keyHandle, iv, &cipherHandle); + if (result != SEC_RESULT_SUCCESS) + return result; + + result = SecCipher_Process(cipherHandle, input, input_len, 1, output, output_len, written); + SecCipher_Release(cipherHandle); + return result; +} + +Sec_Result SecCipher_SingleInputId(Sec_ProcessorHandle* processorHandle, Sec_CipherAlgorithm alg, Sec_CipherMode mode, + SEC_OBJECTID key, SEC_BYTE* iv, SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* output, SEC_SIZE output_len, + SEC_SIZE* written) { + Sec_Result result = SEC_RESULT_FAILURE; + Sec_KeyHandle* keyHandle = NULL; + + if (SecKey_GetInstance(processorHandle, key, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + if (keyHandle != NULL) + SecKey_Release(keyHandle); + + return result; + } + + if (SecCipher_SingleInput(processorHandle, alg, mode, keyHandle, iv, input, input_len, output, output_len, + written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInput failed"); + if (keyHandle != NULL) + SecKey_Release(keyHandle); + + return result; + } + + if (keyHandle != NULL) + SecKey_Release(keyHandle); + + return SEC_RESULT_SUCCESS; +} + +SEC_BOOL SecCipher_IsPKCS7Padded(Sec_CipherAlgorithm alg) { + return alg == SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING || alg == SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING; +} + +SEC_BOOL SecCipher_IsDecrypt(Sec_CipherMode mode) { + return mode == SEC_CIPHERMODE_DECRYPT || mode == SEC_CIPHERMODE_DECRYPT_NATIVEMEM; +} + +Sec_Result SecCipher_ProcessOpaqueWithMap(Sec_CipherHandle* cipherHandle, SEC_BYTE* iv, SEC_BYTE* input, + SEC_SIZE inputSize, SEC_BOOL lastInput, SEC_MAP* map, SEC_SIZE mapLength, Sec_OpaqueBufferHandle** outputHandle, + SEC_SIZE* bytesWritten) { + + if (cipherHandle == NULL) { + SEC_LOG_ERROR("NULL cipherHandle"); + return SEC_RESULT_FAILURE; + } + + if (iv == NULL) { + SEC_LOG_ERROR("NULL iv"); + return SEC_RESULT_FAILURE; + } + + if (input == NULL) { + SEC_LOG_ERROR("NULL input"); + return SEC_RESULT_FAILURE; + } + + if (map == NULL) { + SEC_LOG_ERROR("NULL map"); + return SEC_RESULT_FAILURE; + } + + if (outputHandle == NULL) { + SEC_LOG_ERROR("NULL outputHandle"); + return SEC_RESULT_FAILURE; + } + + if (bytesWritten == NULL) { + SEC_LOG_ERROR("NULL bytesWritten"); + return SEC_RESULT_FAILURE; + } + + Sec_Result result = SecOpaqueBuffer_Malloc(inputSize, outputHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Malloc failed"); + return SEC_RESULT_FAILURE; + } + + sa_subsample_length* subsample_lengths = malloc(mapLength * sizeof(sa_subsample_length)); + for (size_t i = 0; i < mapLength; i++) { + subsample_lengths[i].bytes_of_clear_data = map[i].clear; + subsample_lengths[i].bytes_of_protected_data = map[i].encrypted; + } + + sa_buffer out_buffer; + out_buffer.buffer_type = SA_BUFFER_TYPE_SVP; + out_buffer.context.svp.buffer = (*outputHandle)->svp_buffer; + out_buffer.context.svp.offset = 0; + + sa_buffer in_buffer; + in_buffer.buffer_type = SA_BUFFER_TYPE_CLEAR; + in_buffer.context.clear.buffer = input; + in_buffer.context.clear.length = inputSize; + in_buffer.context.clear.offset = 0; + + sa_sample sample; + sample.iv = iv; + sample.iv_length = SEC_AES_BLOCK_SIZE; + sample.crypt_byte_block = 0; + sample.skip_byte_block = 0; + sample.subsample_count = mapLength; + sample.subsample_lengths = subsample_lengths; + sample.context = cipherHandle->cipher.context; + sample.out = &out_buffer; + sample.in = &in_buffer; + + sa_status status = sa_process_common_encryption(1, &sample); + free(subsample_lengths); + if (status != SA_STATUS_OK) { + SecOpaqueBuffer_Free(*outputHandle); + *outputHandle = NULL; + *bytesWritten = 0; + CHECK_STATUS(status) + } + + *bytesWritten = out_buffer.context.svp.offset; + return SEC_RESULT_SUCCESS; +} + +Sec_Result get_cipher_algorithm(const Sec_CipherAlgorithm algorithm, SEC_BOOL is_unwrap, + sa_cipher_algorithm* cipher_algorithm, void** parameters, void* iv, SEC_SIZE key_length, SEC_SIZE key_offset) { + *parameters = NULL; + switch (algorithm) { + case SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING: + *cipher_algorithm = SA_CIPHER_ALGORITHM_AES_ECB; + return SEC_RESULT_SUCCESS; + + case SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING: + *cipher_algorithm = SA_CIPHER_ALGORITHM_AES_ECB_PKCS7; + return SEC_RESULT_SUCCESS; + + case SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING: + *cipher_algorithm = SA_CIPHER_ALGORITHM_AES_CBC; + if (is_unwrap) { + *parameters = calloc(1, sizeof(sa_unwrap_parameters_aes_cbc)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_unwrap_parameters_aes_cbc*) *parameters)->iv = iv; + ((sa_unwrap_parameters_aes_cbc*) *parameters)->iv_length = SEC_AES_BLOCK_SIZE; + } else { + *parameters = calloc(1, sizeof(sa_cipher_parameters_aes_cbc)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_cipher_parameters_aes_cbc*) *parameters)->iv = iv; + ((sa_cipher_parameters_aes_cbc*) *parameters)->iv_length = SEC_AES_BLOCK_SIZE; + } + + return SEC_RESULT_SUCCESS; + + case SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING: + *cipher_algorithm = SA_CIPHER_ALGORITHM_AES_CBC_PKCS7; + if (is_unwrap) { + *parameters = calloc(1, sizeof(sa_unwrap_parameters_aes_cbc)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_unwrap_parameters_aes_cbc*) *parameters)->iv = iv; + ((sa_unwrap_parameters_aes_cbc*) *parameters)->iv_length = SEC_AES_BLOCK_SIZE; + } else { + *parameters = calloc(1, sizeof(sa_cipher_parameters_aes_cbc)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_cipher_parameters_aes_cbc*) *parameters)->iv = iv; + ((sa_cipher_parameters_aes_cbc*) *parameters)->iv_length = SEC_AES_BLOCK_SIZE; + } + + return SEC_RESULT_SUCCESS; + + case SEC_CIPHERALGORITHM_AES_CTR: + *cipher_algorithm = SA_CIPHER_ALGORITHM_AES_CTR; + if (is_unwrap) { + *parameters = calloc(1, sizeof(sa_unwrap_parameters_aes_ctr)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_unwrap_parameters_aes_ctr*) *parameters)->ctr = iv; + ((sa_unwrap_parameters_aes_ctr*) *parameters)->ctr_length = SEC_AES_BLOCK_SIZE; + } else { + *parameters = calloc(1, sizeof(sa_cipher_parameters_aes_ctr)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_cipher_parameters_aes_ctr*) *parameters)->ctr = iv; + ((sa_cipher_parameters_aes_ctr*) *parameters)->ctr_length = SEC_AES_BLOCK_SIZE; + } + + return SEC_RESULT_SUCCESS; + + case SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING: + *cipher_algorithm = SA_CIPHER_ALGORITHM_RSA_PKCS1V15; + return SEC_RESULT_SUCCESS; + + case SEC_CIPHERALGORITHM_RSA_OAEP_PADDING: + *cipher_algorithm = SA_CIPHER_ALGORITHM_RSA_OAEP; + return SEC_RESULT_SUCCESS; + + case SEC_CIPHERALGORITHM_ECC_ELGAMAL: + *cipher_algorithm = SA_CIPHER_ALGORITHM_EC_ELGAMAL; + if (is_unwrap) { + *parameters = calloc(1, sizeof(sa_unwrap_parameters_ec_elgamal)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_unwrap_parameters_ec_elgamal*) *parameters)->key_length = key_length; + ((sa_unwrap_parameters_ec_elgamal*) *parameters)->offset = key_offset; + } + return SEC_RESULT_SUCCESS; + + default: + return SEC_RESULT_INVALID_PARAMETERS; + } +} + +static sa_cipher_mode get_cipher_mode(Sec_CipherMode mode) { + switch (mode) { + case SEC_CIPHERMODE_ENCRYPT: + case SEC_CIPHERMODE_ENCRYPT_NATIVEMEM: + return SA_CIPHER_MODE_ENCRYPT; + + case SEC_CIPHERMODE_DECRYPT: + case SEC_CIPHERMODE_DECRYPT_NATIVEMEM: + return SA_CIPHER_MODE_DECRYPT; + + default: + return SA_CIPHER_MODE_ENCRYPT; + } +} + +static SEC_BOOL rsa_encrypt_pkcs1v15(void* out, size_t* out_length, const RSA* rsa, const void* in, size_t in_length) { + if (!out) { + SEC_LOG_ERROR("NULL out"); + return SEC_FALSE; + } + + if (!out_length) { + SEC_LOG_ERROR("NULL out_length"); + return SEC_FALSE; + } + + if (!rsa) { + SEC_LOG_ERROR("NULL rsa"); + return SEC_FALSE; + } + + if (!in) { + SEC_LOG_ERROR("NULL in"); + return SEC_FALSE; + } + + if (*out_length < (size_t) RSA_size(rsa)) { + SEC_LOG_ERROR("Bad out_length"); + return SEC_FALSE; + } + + if (in_length >= (size_t) RSA_size(rsa) - RSA_PKCS1_PADDING_SIZE) { + SEC_LOG_ERROR("Bad in_length"); + return SEC_FALSE; + } + + int length = RSA_public_encrypt((int) in_length, in, out, (RSA*) rsa, RSA_PKCS1_PADDING); + if (length < 0) { + SEC_LOG_ERROR("RSA_public_encrypt failed"); + return SEC_FALSE; + } + *out_length = length; + + return SEC_TRUE; +} + +static SEC_BOOL rsa_encrypt_oaep(void* out, size_t* out_length, const RSA* rsa, const void* in, size_t in_length) { + if (!out) { + SEC_LOG_ERROR("NULL out"); + return SEC_FALSE; + } + + if (!out_length) { + SEC_LOG_ERROR("NULL out_length"); + return SEC_FALSE; + } + + if (!rsa) { + SEC_LOG_ERROR("NULL rsa"); + return SEC_FALSE; + } + + if (!in) { + SEC_LOG_ERROR("NULL in"); + return SEC_FALSE; + } + + if (*out_length < (size_t) RSA_size(rsa)) { + SEC_LOG_ERROR("Bad out_length"); + return SEC_FALSE; + } + + if (in_length >= (size_t) RSA_size(rsa) - RSA_OAEP_PADDING_SIZE) { + SEC_LOG_ERROR("Bad in_length"); + return SEC_FALSE; + } + + int length = RSA_public_encrypt((int) in_length, in, out, (RSA*) rsa, RSA_PKCS1_OAEP_PADDING); + if (length < 0) { + SEC_LOG_ERROR("RSA_private_decrypt failed"); + return SEC_FALSE; + } + + *out_length = length; + return SEC_TRUE; +} + +static SEC_BOOL is_svp_required(Sec_KeyProperties* props) { + for (int i = 0; i < SEC_KEYOUTPUTRIGHT_NUM; ++i) { + if (props->rights[i] == SEC_KEYOUTPUTRIGHT_SVP_REQUIRED) { + return SEC_TRUE; + } + } + + return SEC_FALSE; +} diff --git a/src/sec_adapter_cipher.h b/src/sec_adapter_cipher.h new file mode 100644 index 0000000..e041fd3 --- /dev/null +++ b/src/sec_adapter_cipher.h @@ -0,0 +1,33 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_CIPHER_H +#define SEC_ADAPTER_CIPHER_H + +#include "sa_types.h" +#include "sec_adapter_processor.h" +#include "sec_adapter_svp.h" +#include "sec_adapter_utils.h" +#include "sec_security.h" +#include +#include + +Sec_Result get_cipher_algorithm(Sec_CipherAlgorithm algorithm, SEC_BOOL is_unwrap, + sa_cipher_algorithm* cipher_algorithm, void** parameters, void* iv, SEC_SIZE key_length, SEC_SIZE key_offset); + +#endif // SEC_ADAPTER_CIPHER_H diff --git a/src/sec_adapter_common.c b/src/sec_adapter_common.c new file mode 100644 index 0000000..be65977 --- /dev/null +++ b/src/sec_adapter_common.c @@ -0,0 +1,169 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_utils.h" +#include "sec_security.h" + +int Sec_Memcmp(const void* ptr1, const void* ptr2, const size_t num) { + size_t i; + SEC_BYTE result = 0; + SEC_BYTE* a = (SEC_BYTE*) ptr1; + SEC_BYTE* b = (SEC_BYTE*) ptr2; + + for (i = 0; i < num; ++i) + result |= a[i] ^ b[i]; + + return result; +} + +void* Sec_Memset(void* ptr, int value, size_t num) { + volatile SEC_BYTE* p = (SEC_BYTE*) ptr; + while (num--) + *p++ = value; + return ptr; +} + +Sec_Endianess Sec_GetEndianess(void) { + uint32_t u32Val = 0x03020100; + uint8_t* u8ptr = (uint8_t*) &u32Val; + + if (u8ptr[0] == 0x03 && u8ptr[1] == 0x02 && u8ptr[2] == 0x01 && u8ptr[3] == 0x00) + return SEC_ENDIANESS_BIG; + + if (u8ptr[0] == 0x00 && u8ptr[1] == 0x01 && u8ptr[2] == 0x02 && u8ptr[3] == 0x03) + return SEC_ENDIANESS_LITTLE; + + return SEC_ENDIANESS_UNKNOWN; +} + +uint32_t Sec_BEBytesToUint32(SEC_BYTE* bytes) { + uint32_t val; + + memcpy(&val, bytes, 4); + + switch (Sec_GetEndianess()) { + case SEC_ENDIANESS_BIG: + return val; + + case SEC_ENDIANESS_LITTLE: + return Sec_EndianSwap_uint32(val); + + default: + break; + } + + SEC_LOG_ERROR("Unknown endianess detected"); + return 0; +} + +uint64_t Sec_BEBytesToUint64(SEC_BYTE* bytes) { + uint64_t val; + + memcpy(&val, bytes, 8); + + switch (Sec_GetEndianess()) { + case SEC_ENDIANESS_BIG: + return val; + + case SEC_ENDIANESS_LITTLE: + return Sec_EndianSwap_uint64(val); + + default: + break; + } + + SEC_LOG_ERROR("Unknown endianess detected"); + return 0; +} + +void Sec_Uint32ToBEBytes(uint32_t val, SEC_BYTE* bytes) { + if (Sec_GetEndianess() == SEC_ENDIANESS_LITTLE) { + val = Sec_EndianSwap_uint32(val); + } + + memcpy(bytes, &val, 4); +} + +void Sec_Uint64ToBEBytes(uint64_t val, SEC_BYTE* bytes) { + if (Sec_GetEndianess() == SEC_ENDIANESS_LITTLE) { + val = Sec_EndianSwap_uint64(val); + } + + memcpy(bytes, &val, 8); +} + +// Macro that switches endianness of any stdint type. +// Note in and out parameters must be the same stdint type. +#define stdint_EndianSwap(in, out) \ + for (size_t i = 0; i < sizeof(in); i++) { \ + (out) = ((out) << 8) + ((in) >> (i * 8) & 0x0ff); \ + } + +uint16_t Sec_EndianSwap_uint16(uint16_t val) { + uint16_t ret = 0; + stdint_EndianSwap(val, ret) + return ret; +} + +int16_t Sec_EndianSwap_int16(int16_t val) { + int16_t ret = 0; + stdint_EndianSwap(val, ret) + return ret; +} + +uint32_t Sec_EndianSwap_uint32(uint32_t val) { + uint32_t ret = 0; + stdint_EndianSwap(val, ret) + return ret; +} + +int32_t Sec_EndianSwap_int32(int32_t val) { + int32_t ret = 0; + stdint_EndianSwap(val, ret) + return ret; +} + +int64_t Sec_EndianSwap_int64(int64_t val) { + int64_t ret = 0; + stdint_EndianSwap(val, ret) + return ret; +} + +uint64_t Sec_EndianSwap_uint64(uint64_t val) { + uint64_t ret = 0; + stdint_EndianSwap(val, ret) + return ret; +} + +void SecKeyProperties_SetDefault(Sec_KeyProperties* props, Sec_KeyType type) { + memset(props->keyId, 0, sizeof(props->keyId)); + SecUtils_Epoch2IsoTime(0, props->notBefore, 24); + SecUtils_Epoch2IsoTime(UINT32_MAX, props->notOnOrAfter, 24); + + memset(props->rights, SEC_KEYOUTPUTRIGHT_NOT_SET, sizeof(props->rights)); + int i = 0; + props->rights[i++] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_DTCP_ALLOWED; + props->rights[i++] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + props->rights[i++] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + props->rights[i++] = SEC_KEYOUTPUTRIGHT_ANALOG_OUTPUT_ALLOWED; + props->rights[i] = SEC_KEYOUTPUTRIGHT_CGMSA_REQUIRED; + props->keyLength = SecKey_GetKeyLenForKeyType(type); + props->keyType = type; + props->usage = SEC_KEYUSAGE_DATA_KEY; + props->cacheable = 1; +} diff --git a/src/sec_adapter_digest.c b/src/sec_adapter_digest.c new file mode 100644 index 0000000..0f6a35d --- /dev/null +++ b/src/sec_adapter_digest.c @@ -0,0 +1,311 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sa.h" +#include "sec_adapter_processor.h" +#include "sec_security.h" +#include + +struct Sec_DigestHandle_struct { + Sec_ProcessorHandle* processorHandle; + Sec_DigestAlgorithm algorithm; + SHA_CTX sha1_ctx; + SHA256_CTX sha256_ctx; + SEC_BYTE* key_digest; + size_t key_digest_length; + SEC_BOOL in_process; +}; + +/** + * @brief Obtain a digest object handle. + * + * @param processorHandle secure processor handle. + * @param algorithm digest algorithm to use. + * @param digestHandle output digest object handle. + * + * @return The status of the operation. + */ +Sec_Result SecDigest_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_DigestAlgorithm algorithm, + Sec_DigestHandle** digestHandle) { + CHECK_PROCHANDLE(processorHandle) + + *digestHandle = calloc(1, sizeof(Sec_DigestHandle)); + if (*digestHandle == NULL) { + SEC_LOG_ERROR("Malloc failed"); + return SEC_RESULT_FAILURE; + } + + (*digestHandle)->algorithm = algorithm; + (*digestHandle)->processorHandle = processorHandle; + + switch (algorithm) { + case SEC_DIGESTALGORITHM_SHA1: + if (SHA1_Init(&((*digestHandle)->sha1_ctx)) != 1) { + SEC_FREE(*digestHandle); + return SEC_RESULT_FAILURE; + } + + break; + + case SEC_DIGESTALGORITHM_SHA256: + if (SHA256_Init(&((*digestHandle)->sha256_ctx)) != 1) { + SEC_FREE(*digestHandle); + return SEC_RESULT_FAILURE; + } + + break; + + default: + SEC_LOG_ERROR("Unimplemented digest algorithm"); + SEC_FREE(*digestHandle); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Update the digest value with the specified input. + * + * @param digestHandle handle of the digest object. + * @param input pointer to the input buffer. + * @param inputSize size of the input buffer. + * + * @return The status of the operation. + */ +Sec_Result SecDigest_Update(Sec_DigestHandle* digestHandle, SEC_BYTE* input, SEC_SIZE inputSize) { + CHECK_HANDLE(digestHandle) + + // SecDigest_UpdateWithKey can't be mixed with SecDigest_Update. + if (digestHandle->key_digest != NULL) { + SEC_LOG_ERROR("SecDigest_UpdateWithKey can't be mixed with SecDigest_Update"); + return SEC_RESULT_FAILURE; + } + + switch (digestHandle->algorithm) { + case SEC_DIGESTALGORITHM_SHA1: + if (SHA1_Update(&(digestHandle->sha1_ctx), input, inputSize) != 1) + return SEC_RESULT_FAILURE; + + break; + + case SEC_DIGESTALGORITHM_SHA256: + if (SHA256_Update(&(digestHandle->sha256_ctx), input, inputSize) != 1) + return SEC_RESULT_FAILURE; + + break; + + default: + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + digestHandle->in_process = SEC_TRUE; + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Update the digest value with the key data. + * + * @param digestHandle handle of the digest object. + * @param keyHandle key to use. + * + * @return The status of the operation. + */ +Sec_Result SecDigest_UpdateWithKey(Sec_DigestHandle* digestHandle, Sec_KeyHandle* keyHandle) { + // SecDigest_UpdateWithKey can't be mixed with SecDigest_Update. + if (digestHandle->in_process) { + SEC_LOG_ERROR("SecDigest_UpdateWithKey can't be mixed with SecDigest_Update"); + return SEC_RESULT_FAILURE; + } + + if (digestHandle->key_digest != NULL) { + SEC_LOG_ERROR("SecDigest_UpdateWithKey can't be called multiple times"); + return SEC_RESULT_FAILURE; + } + + const Sec_Key* key = get_key(keyHandle); + sa_digest_algorithm algorithm = (digestHandle->algorithm == SEC_DIGESTALGORITHM_SHA1) ? SA_DIGEST_ALGORITHM_SHA1 : + SA_DIGEST_ALGORITHM_SHA256; + sa_status status = sa_key_digest(NULL, &digestHandle->key_digest_length, key->handle, algorithm); + CHECK_STATUS(status) + + digestHandle->key_digest = malloc(digestHandle->key_digest_length); + if (digestHandle->key_digest == NULL) { + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + status = sa_key_digest(digestHandle->key_digest, &digestHandle->key_digest_length, key->handle, + algorithm); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Calculate the resulting digest value and release the digest object. + * + * @param digestHandle digest handle. + * @param digestOutput pointer to an output buffer that will be filled with the resulting + * digest value. Buffer should be SEC_DIGEST_MAX_LEN bytes long. + * @param digestSize pointer to a value that will be set to actual size of the digest value. + * + * @return The status of the operation. + */ +Sec_Result SecDigest_Release(Sec_DigestHandle* digestHandle, SEC_BYTE* digestOutput, SEC_SIZE* digestSize) { + CHECK_HANDLE(digestHandle) + + if (digestOutput == NULL) { + SEC_LOG_ERROR("digestOutput is NULL"); + return SEC_RESULT_FAILURE; + } + + if (digestSize == NULL) { + SEC_LOG_ERROR("digestSize is NULL"); + return SEC_RESULT_FAILURE; + } + + if (digestHandle->key_digest == NULL) { + switch (digestHandle->algorithm) { + case SEC_DIGESTALGORITHM_SHA1: + *digestSize = SHA_DIGEST_LENGTH; + if (SHA1_Final(digestOutput, &(digestHandle->sha1_ctx)) != 1) + return SEC_RESULT_FAILURE; + + break; + + case SEC_DIGESTALGORITHM_SHA256: + *digestSize = SHA256_DIGEST_LENGTH; + if (SHA256_Final(digestOutput, &(digestHandle->sha256_ctx)) != 1) + return SEC_RESULT_FAILURE; + + break; + + default: + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + } else { + memcpy(digestOutput, digestHandle->key_digest, digestHandle->key_digest_length); + *digestSize = digestHandle->key_digest_length; + free(digestHandle->key_digest); + } + + SEC_FREE(digestHandle); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Obtain the size of the digest for a specified digest algorithm. + * + * @param alg digest algorithm. + * + * @return digest size in bytes. + */ +SEC_SIZE SecDigest_GetDigestLenForAlgorithm(Sec_DigestAlgorithm alg) { + switch (alg) { + case SEC_DIGESTALGORITHM_SHA1: + return SHA_DIGEST_LENGTH; + + case SEC_DIGESTALGORITHM_SHA256: + return SHA256_DIGEST_LENGTH; + + default: + return 0; + } +} + +/** + * @brief Utility function for calculating a digest value of a single input buffer. + * + * @param proc secure processor handle. + * @param alg digest algorithm to use. + * @param input input data to calculate digest over. + * @param input_len size of input data in bytes. + * @param digest output buffer where the calculated digest value will be written. + * @param digest_len number of bytes written to the output digest buffer. + * + * @return status of the operation. + */ +Sec_Result SecDigest_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_DigestAlgorithm alg, SEC_BYTE* input, + SEC_SIZE input_len, SEC_BYTE* digest, SEC_SIZE* digest_len) { + Sec_Result result; + Sec_DigestHandle* digestHandle = NULL; + + result = SecDigest_GetInstance(processorHandle, alg, &digestHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_GetInstance failed"); + return result; + } + + result = SecDigest_Update(digestHandle, input, input_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_Update failed"); + SecDigest_Release(digestHandle, digest, digest_len); + return result; + } + + return SecDigest_Release(digestHandle, digest, digest_len); +} + +/** + * @brief Utility function for calculating a digest value of a single input buffer. + * + * @param proc secure processor handle. + * @param alg digest algorithm to use. + * @param key_id id of the key over which the digest is being calculated. + * @param digest output buffer where the calculated digest value will be written. + * @param digest_len number of bytes written to the output digest buffer. + * + * @return status of the operation. + */ +Sec_Result SecDigest_SingleInputWithKeyId(Sec_ProcessorHandle* processorHandle, Sec_DigestAlgorithm alg, + SEC_OBJECTID key_id, SEC_BYTE* digest, SEC_SIZE* digest_len) { + Sec_Result result = SEC_RESULT_FAILURE; + + Sec_DigestHandle* digestHandle = NULL; + Sec_KeyHandle* keyHandle = NULL; + do { + if (SecDigest_GetInstance(processorHandle, alg, &digestHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_GetInstance failed"); + break; + } + + if (SecKey_GetInstance(processorHandle, key_id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + break; + } + + if (SecDigest_UpdateWithKey(digestHandle, keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_UpdateWithKey failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (SEC_FALSE); + + if (digestHandle != NULL) { + SecDigest_Release(digestHandle, digest, digest_len); + digestHandle = NULL; + } + + if (keyHandle != NULL) { + SecKey_Release(keyHandle); + keyHandle = NULL; + } + + return result; +} diff --git a/src/sec_adapter_engine.c b/src/sec_adapter_engine.c new file mode 100644 index 0000000..50b7aff --- /dev/null +++ b/src/sec_adapter_engine.c @@ -0,0 +1,355 @@ +/** +* Copyright 2020-2022 Comcast Cable Communications Management, LLC +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* SPDX-License-Identifier: Apache-2.0 +*/ + +#include "sec_security.h" +#include +#include + +#define ENGINE_ID "securityapi" + +static SEC_BOOL g_sec_openssl_inited = SEC_FALSE; + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +static RSA_METHOD* rsa_method = NULL; +#endif + +static void Sec_ShutdownOpenSSL() { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (rsa_method != NULL) { + RSA_meth_free(rsa_method); + rsa_method = NULL; + } +#endif + + ENGINE* engine = ENGINE_by_id(ENGINE_ID); + if (engine != NULL) { + ENGINE_remove(engine); + ENGINE_finish(engine); + ENGINE_free(engine); + } +} + +static int Sec_OpenSSLPrivSign(int type, const unsigned char* m, unsigned int m_len, unsigned char* sigret, + unsigned int* siglen, const RSA* rsa) { + Sec_KeyHandle* keyHandle = NULL; + Sec_SignatureAlgorithm alg; + switch (type) { + case NID_sha1: + alg = SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST; + break; + + case NID_sha256: + alg = SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST; + break; + + default: + SEC_LOG_ERROR("Unknown type %d", type); + return -1; + } + + keyHandle = (Sec_KeyHandle*) RSA_get_app_data(rsa); + if (keyHandle == NULL) { + SEC_LOG_ERROR("NULL keyHandle encountered"); + return -1; + } + + if (SecSignature_SingleInput(SecKey_GetProcessor(keyHandle), alg, SEC_SIGNATUREMODE_SIGN, keyHandle, + (SEC_BYTE*) m, m_len, (SEC_BYTE*) sigret, siglen) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInput failed"); + return -1; + } + + return 1; +} + +static int Sec_OpenSSLPubVerify(int type, const unsigned char* m, unsigned int m_len, const unsigned char* sigret, + unsigned int siglen, const RSA* rsa) { + Sec_KeyHandle* keyHandle = NULL; + Sec_SignatureAlgorithm alg; + switch (type) { + case NID_sha1: + alg = SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS; + break; + + case NID_sha256: + alg = SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS; + break; + + default: + SEC_LOG_ERROR("Unknown type %d", type); + return -1; + } + + keyHandle = (Sec_KeyHandle*) RSA_get_app_data(rsa); + if (keyHandle == NULL) { + SEC_LOG_ERROR("NULL keyHandle encountered"); + return -1; + } + + if (SecSignature_SingleInput(SecKey_GetProcessor(keyHandle), alg, SEC_SIGNATUREMODE_VERIFY, keyHandle, + (SEC_BYTE*) m, m_len, (SEC_BYTE*) sigret, &siglen) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInput failed"); + return -1; + } + + return 1; +} + +static int Sec_OpenSSLPubEncrypt(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, int padding) { + Sec_KeyHandle* keyHandle = NULL; + Sec_CipherAlgorithm alg; + SEC_SIZE written; + switch (padding) { + case RSA_PKCS1_PADDING: + alg = SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING; + break; + + case RSA_PKCS1_OAEP_PADDING: + alg = SEC_CIPHERALGORITHM_RSA_OAEP_PADDING; + break; + + default: + SEC_LOG_ERROR("Unknown padding %d", padding); + return -1; + } + + keyHandle = (Sec_KeyHandle*) RSA_get_app_data(rsa); + if (keyHandle == NULL) { + SEC_LOG_ERROR("NULL keyHandle encountered"); + return -1; + } + + if (SecCipher_SingleInput(SecKey_GetProcessor(keyHandle), alg, SEC_CIPHERMODE_ENCRYPT, keyHandle, NULL, + (SEC_BYTE*) from, flen, (SEC_BYTE*) to, SecKey_GetKeyLen(keyHandle), &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInput failed"); + return -1; + } + + return (int) written; +} + +static int Sec_OpenSSLPrivDecrypt(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, int padding) { + Sec_KeyHandle* keyHandle = NULL; + Sec_CipherAlgorithm alg; + SEC_SIZE written; + switch (padding) { + case RSA_PKCS1_PADDING: + alg = SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING; + break; + + case RSA_PKCS1_OAEP_PADDING: + alg = SEC_CIPHERALGORITHM_RSA_OAEP_PADDING; + break; + + default: + SEC_LOG_ERROR("Unknown padding %d", padding); + return -1; + } + + keyHandle = (Sec_KeyHandle*) RSA_get_app_data(rsa); + if (keyHandle == NULL) { + SEC_LOG_ERROR("NULL keyHandle encountered"); + return -1; + } + + if (SecCipher_SingleInput(SecKey_GetProcessor(keyHandle), alg, SEC_CIPHERMODE_DECRYPT, keyHandle, NULL, + (SEC_BYTE*) from, flen, (SEC_BYTE*) to, SecKey_GetKeyLen(keyHandle), &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInput failed"); + return -1; + } + + return (int) written; +} + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +static RSA_METHOD g_sec_openssl_rsamethod = { + "securityapi RSA method", + Sec_OpenSSLPubEncrypt, // rsa_pub_enc + NULL, // rsa_pub_dec + NULL, // rsa_priv_enc + Sec_OpenSSLPrivDecrypt, // rsa_priv_dec + NULL, // rsa_mod_exp + NULL, // bn_mod_exp + NULL, // init + NULL, // finish + RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY | RSA_FLAG_SIGN_VER, // flags + NULL, // app_data + Sec_OpenSSLPrivSign, // rsa_sign + Sec_OpenSSLPubVerify, // rsa_verify + NULL, // rsa_keygen +}; + +#endif + +static void ENGINE_load_securityapi(void) { + ENGINE* engine = ENGINE_new(); + if (engine == NULL) { + SEC_LOG_ERROR("ENGINE_new failed"); + return; + } + + if (!ENGINE_set_id(engine, ENGINE_ID)) { + ENGINE_free(engine); + return; + } + if (!ENGINE_set_name(engine, "SecurityApi engine")) { + ENGINE_free(engine); + return; + } + + if (!ENGINE_init(engine)) { + ENGINE_free(engine); + return; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (!ENGINE_set_RSA(engine, &g_sec_openssl_rsamethod)) { +#else + if (!ENGINE_set_RSA(engine, rsa_method)) { +#endif + ENGINE_remove(engine); + ENGINE_free(engine); + return; + } + + ENGINE_add(engine); + ENGINE_free(engine); + ERR_clear_error(); +} + +void Sec_InitOpenSSL() { + static pthread_mutex_t init_openssl_mutex = PTHREAD_MUTEX_INITIALIZER; + + pthread_mutex_lock(&init_openssl_mutex); + + if (g_sec_openssl_inited != SEC_TRUE) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (rsa_method == NULL) { + rsa_method = RSA_meth_new("securityapi RSA method", RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY); + RSA_meth_set_pub_enc(rsa_method, Sec_OpenSSLPubEncrypt); + RSA_meth_set_priv_dec(rsa_method, Sec_OpenSSLPrivDecrypt); + RSA_meth_set_sign(rsa_method, Sec_OpenSSLPrivSign); + RSA_meth_set_verify(rsa_method, Sec_OpenSSLPubVerify); + } + +#else + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); +#endif + + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); + ENGINE_load_securityapi(); + + if (atexit(Sec_ShutdownOpenSSL) != 0) { + SEC_LOG_ERROR("atexit failed"); + return; + } + + g_sec_openssl_inited = SEC_TRUE; + } + + pthread_mutex_unlock(&init_openssl_mutex); +} + +void Sec_PrintOpenSSLVersion() { + SEC_PRINT("Built against: %s\n", OPENSSL_VERSION_TEXT); + SEC_PRINT("Running against: %s\n", SSLeay_version(SSLEAY_VERSION)); +} + +RSA* SecKey_ToEngineRSA(Sec_KeyHandle* keyHandle) { + Sec_RSARawPublicKey pubKey; + RSA* rsa = NULL; + ENGINE* engine = NULL; + + engine = ENGINE_by_id(ENGINE_ID); + if (engine == NULL) { + SEC_LOG_ERROR("ENGINE_by_id failed"); + return NULL; + } + + if (SEC_RESULT_SUCCESS != SecKey_ExtractRSAPublicKey(keyHandle, &pubKey)) { + ENGINE_free(engine); + SEC_LOG_ERROR("SecKey_ExtractRSAPublicKey failed"); + return NULL; + } + + rsa = RSA_new_method(engine); + if (rsa == NULL) { + ENGINE_free(engine); + SEC_LOG_ERROR("RSA_new_method failed"); + return NULL; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + rsa->n = BN_bin2bn(pubKey.n, (int) Sec_BEBytesToUint32(pubKey.modulus_len_be), NULL); + rsa->e = BN_bin2bn(pubKey.e, 4, NULL); +#else + RSA_set0_key(rsa, BN_bin2bn(pubKey.n, (int) Sec_BEBytesToUint32(pubKey.modulus_len_be), NULL), + BN_bin2bn(pubKey.e, 4, NULL), NULL); +#endif + + RSA_set_app_data(rsa, keyHandle); + ENGINE_free(engine); + return rsa; +} + +RSA* SecKey_ToEngineRSAWithCert(Sec_KeyHandle* keyHandle, Sec_CertificateHandle* certificateHandle) { + Sec_RSARawPublicKey pubKey; + RSA* rsa = NULL; + ENGINE* engine = NULL; + + engine = ENGINE_by_id(ENGINE_ID); + if (engine == NULL) { + SEC_LOG_ERROR("ENGINE_by_id failed"); + return NULL; + } + + if (SEC_RESULT_SUCCESS != SecCertificate_ExtractRSAPublicKey(certificateHandle, &pubKey)) { + ENGINE_free(engine); + SEC_LOG_ERROR("SecKey_ExtractRSAPublicKey failed"); + return NULL; + } + + rsa = RSA_new_method(engine); + if (rsa == NULL) { + ENGINE_free(engine); + SEC_LOG_ERROR("RSA_new_method failed"); + return NULL; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + rsa->n = BN_bin2bn(pubKey.n, (int) Sec_BEBytesToUint32(pubKey.modulus_len_be), NULL); + rsa->e = BN_bin2bn(pubKey.e, 4, NULL); +#else + RSA_set0_key(rsa, BN_bin2bn(pubKey.n, (int) Sec_BEBytesToUint32(pubKey.modulus_len_be), NULL), + BN_bin2bn(pubKey.e, 4, NULL), NULL); +#endif + + RSA_set_app_data(rsa, keyHandle); + ENGINE_free(engine); + return rsa; +} + +EC_KEY* SecKey_ToEngineEcc(Sec_KeyHandle* keyHandle) { + SEC_LOG_ERROR("SecKey_ToEngineEcc is not implemented"); + return NULL; +} diff --git a/src/sec_adapter_key.c b/src/sec_adapter_key.c new file mode 100644 index 0000000..c7c78c8 --- /dev/null +++ b/src/sec_adapter_key.c @@ -0,0 +1,3428 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_key.h" // NOLINT +#include "sec_adapter_cipher.h" +#include "sec_adapter_key_legacy.h" +#include "sec_adapter_processor.h" +#include +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#include +#endif + +#ifndef SEC_TRACE_UNWRAP +#define SEC_TRACE_UNWRAP 0 +#endif + +#if SEC_TRACE_UNWRAP +#pragma message "SEC_TRACE_UNWRAP is enabled. Please disable in production builds." +#endif + +#define CHECK_MAC_RESULT(status, base_key, mac_context) \ + if ((status) != SA_STATUS_OK) { \ + if ((mac_context) != 0) \ + sa_crypto_mac_release(mac_context); \ + sa_key_release(base_key); \ + return SEC_RESULT_FAILURE; \ + } + +#define PUBLIC_KEY_BUFFER_SIZE 4 +#define ISO_TIME_SIZE 24 + +struct Sec_KeyHandle_struct { + Sec_ProcessorHandle* processorHandle; + Sec_KeyType key_type; + Sec_Key key; +}; + +static void find_ram_key_data(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_RAMKeyData** data, + Sec_RAMKeyData** parent); + +static Sec_Result retrieve_key_data(Sec_ProcessorHandle* processorHandle, + SEC_OBJECTID object_id, Sec_StorageLoc* location, Sec_KeyData* keyData); + +static Sec_Result store_key_data(Sec_ProcessorHandle* processorHandle, Sec_StorageLoc location, SEC_OBJECTID object_id, + Sec_KeyData* key_data); + +static Sec_Result process_key_container(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_KeyContainer in_key_container, void* data, SEC_SIZE data_length, Sec_Key* key, + Sec_KeyContainer* out_key_container, void* key_buffer, SEC_SIZE* key_length); + +static Sec_Result process_rsa_key_container(Sec_KeyContainer in_key_container, SEC_BYTE* data, + SEC_SIZE data_length, unsigned char* key_buffer, SEC_SIZE* key_length, Sec_KeyContainer* key_container); + +static Sec_Result process_rsa_public_key_container(Sec_KeyContainer in_key_container, SEC_BYTE* data, + SEC_SIZE data_length, RSA** rsa, unsigned char* key_buffer, SEC_SIZE* key_length, + Sec_KeyContainer* out_key_container); + +static Sec_Result process_ec_key_container(Sec_KeyContainer in_key_container, SEC_BYTE* data, + SEC_SIZE data_length, unsigned char* key_buffer, SEC_SIZE* key_length, Sec_KeyContainer* out_key_container); + +static Sec_Result process_ec_public_key_container(Sec_KeyContainer in_key_container, SEC_BYTE* data, + SEC_SIZE data_length, EC_KEY** ec_key, unsigned char* key_buffer, SEC_SIZE* key_length, + Sec_KeyContainer* out_key_container); + +static Sec_KeyContainer convert_key_container(Sec_KeyContainer key_container); + +static int disable_passphrase_prompt(char* buf, int size, int rwflag, void* u); + +static Sec_Result process_asn1_key_container(Sec_ProcessorHandle* processorHandle, const void* data, + SEC_SIZE data_length, SEC_BYTE* key_buffer, SEC_SIZE* key_length, Sec_KeyContainer* key_container); + +static Sec_Result process_store_key_container(Sec_ProcessorHandle* processorHandle, void* data, + SEC_SIZE data_length, SEC_BYTE* key_buffer, SEC_SIZE* key_length, Sec_KeyContainer* key_container); + +static Sec_KeyType get_key_type(sa_header* key_header); + +static Sec_Result derive_root_key_ladder(const SEC_BYTE* c1, const SEC_BYTE* c2, const SEC_BYTE* c3, const SEC_BYTE* c4, + SEC_SIZE key_size, sa_key* key, Sec_KeyType key_type); + +static Sec_Result derive_base_key(Sec_ProcessorHandle* processorHandle, SEC_BYTE* nonce, sa_key* key, + Sec_KeyType key_type); + +static Sec_Result derive_hkdf(Sec_MacAlgorithm macAlgorithm, Sec_KeyType typeDerived, const SEC_BYTE* salt, + SEC_SIZE saltSize, const SEC_BYTE* info, SEC_SIZE infoSize, sa_key baseKey, sa_key* derived_key); + +static Sec_Result derive_kdf_concat(Sec_DigestAlgorithm digestAlgorithm, Sec_KeyType typeDerived, + const SEC_BYTE* otherInfo, SEC_SIZE otherInfoSize, sa_key baseKey, sa_key* derived_key); + +static Sec_Result derive_kdf_cmac(Sec_KeyType typeDerived, const SEC_BYTE* otherData, SEC_SIZE otherDataSize, + const SEC_BYTE* counter, SEC_SIZE counterSize, sa_key baseKey, sa_key* derived_key); + +static Sec_Result unwrap_key(Sec_ProcessorHandle* processorHandle, Sec_CipherAlgorithm algorithm, + Sec_KeyType wrapped_key_type, SEC_SIZE wrapped_key_offset, SEC_OBJECTID id, SEC_BYTE* iv, SEC_BYTE* input, + SEC_SIZE input_len, SEC_BYTE* out_key, SEC_SIZE* out_key_len); + +static Sec_Result get_sa_key_type(Sec_KeyType keyType, sa_key_type* out_key_type, void** parameters); + +static Sec_Result export_key(Sec_Key* key, SEC_BYTE* derivationInput, SEC_BYTE* exportedKey, SEC_SIZE keyBufferLen, + SEC_SIZE* keyBytesWritten); + +static bool is_jwt_key_container(unsigned char* key_buffer, SEC_SIZE key_length); + +Sec_KeyType SecKey_GetKeyTypeForClearKeyContainer(Sec_KeyContainer kc) { + switch (kc) { + case SEC_KEYCONTAINER_RAW_AES_128: + return SEC_KEYTYPE_AES_128; + + case SEC_KEYCONTAINER_RAW_AES_256: + return SEC_KEYTYPE_AES_256; + + case SEC_KEYCONTAINER_RAW_HMAC_128: + return SEC_KEYTYPE_HMAC_128; + + case SEC_KEYCONTAINER_RAW_HMAC_160: + return SEC_KEYTYPE_HMAC_160; + + case SEC_KEYCONTAINER_RAW_HMAC_256: + return SEC_KEYTYPE_HMAC_256; + + case SEC_KEYCONTAINER_RAW_RSA_1024: + case SEC_KEYCONTAINER_PEM_RSA_1024: + case SEC_KEYCONTAINER_DER_RSA_1024: + return SEC_KEYTYPE_RSA_1024; + + case SEC_KEYCONTAINER_RAW_RSA_2048: + case SEC_KEYCONTAINER_PEM_RSA_2048: + case SEC_KEYCONTAINER_DER_RSA_2048: + return SEC_KEYTYPE_RSA_2048; + + case SEC_KEYCONTAINER_RAW_RSA_3072: + case SEC_KEYCONTAINER_PEM_RSA_3072: + case SEC_KEYCONTAINER_DER_RSA_3072: + return SEC_KEYTYPE_RSA_3072; + + case SEC_KEYCONTAINER_RAW_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC: + return SEC_KEYTYPE_RSA_1024_PUBLIC; + + case SEC_KEYCONTAINER_RAW_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC: + return SEC_KEYTYPE_RSA_2048_PUBLIC; + + case SEC_KEYCONTAINER_RAW_RSA_3072_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_3072_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_3072_PUBLIC: + return SEC_KEYTYPE_RSA_3072_PUBLIC; + + case SEC_KEYCONTAINER_PEM_ECC_NISTP256: + case SEC_KEYCONTAINER_RAW_ECC_PRIVONLY_NISTP256: + case SEC_KEYCONTAINER_RAW_ECC_NISTP256: + case SEC_KEYCONTAINER_DER_ECC_NISTP256: + return SEC_KEYTYPE_ECC_NISTP256; + + case SEC_KEYCONTAINER_PEM_ECC_NISTP256_PUBLIC: + case SEC_KEYCONTAINER_RAW_ECC_NISTP256_PUBLIC: + case SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC: + return SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + + default: + return SEC_KEYTYPE_NUM; + } +} + +SEC_SIZE SecKey_GetKeyLenForKeyType(Sec_KeyType keyType) { + switch (keyType) { + case SEC_KEYTYPE_AES_128: + return 16; + + case SEC_KEYTYPE_AES_256: + return 32; + + case SEC_KEYTYPE_HMAC_128: + return 16; + + case SEC_KEYTYPE_HMAC_160: + return 20; + + case SEC_KEYTYPE_HMAC_256: + return 32; + + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_1024_PUBLIC: + return 128; + + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + return 256; + + case SEC_KEYTYPE_RSA_3072: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + return 384; + + case SEC_KEYTYPE_ECC_NISTP256: + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + return SEC_ECC_NISTP256_KEY_LEN; + + default: + SEC_LOG_ERROR("Unknown key type encountered: %d", keyType); + return 0; + } +} + +/** + * @brief Get the properties for the key handle. + * + * @param keyHandle pointer to Sec_KeyHandle. + * @param keyProps pointer to Sec_KeyProperties where information is stored. + */ +Sec_Result SecKey_GetProperties(Sec_KeyHandle* keyHandle, Sec_KeyProperties* keyProperties) { + CHECK_HANDLE(keyHandle) + Sec_Memset(keyProperties, 0, sizeof(Sec_KeyProperties)); + + keyProperties->keyType = keyHandle->key_type; + sa_rights rights; + switch (keyHandle->key_type) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + case SEC_KEYTYPE_ECC_NISTP256: + case SEC_KEYTYPE_RSA_3072: { + sa_header key_header; + sa_status status = sa_key_header(&key_header, keyHandle->key.handle); + CHECK_STATUS(status) + + rights = key_header.rights; + keyProperties->keyLength = key_header.size; + break; + } + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + rights_set_allow_all(&rights, keyHandle->key_type); + keyProperties->keyLength = SecKey_GetKeyLenForKeyType(keyProperties->keyType); + break; + + default: + SEC_LOG_ERROR("Unsupported key_type %u", keyHandle->key_type); + return SEC_RESULT_INVALID_PARAMETERS; + } + + // Cacheable flag. + keyProperties->cacheable = SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_CACHEABLE) ? SEC_TRUE : SEC_FALSE; + + // Key ID in string format. SecApi 2 keyId is 40 chars, SecApi 3 keyID is 64 chars. Truncate to 39 bytes and null + // terminate. + memcpy(keyProperties->keyId, rights.id, 39); + keyProperties->keyId[39] = 0; + + // Validity Period + SecUtils_Epoch2IsoTime(rights.not_before, keyProperties->notBefore, ISO_TIME_SIZE); + SecUtils_Epoch2IsoTime(rights.not_on_or_after, keyProperties->notOnOrAfter, ISO_TIME_SIZE); + + // Rights flags + Sec_Memset(keyProperties->rights, SEC_KEYOUTPUTRIGHT_NOT_SET, sizeof(SEC_BYTE) * SEC_KEYOUTPUTRIGHT_NUM); + int i = 0; + // SEC_KEYOUTPUTRIGHT_TRANSCRIPTION_COPY_ALLOWED and SEC_KEYOUTPUTRIGHT_UNRESTRICTED_COPY_ALLOWED are not used in + // sec api 3. + if (!SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_SVP_OPTIONAL)) + keyProperties->rights[i++] = SEC_KEYOUTPUTRIGHT_SVP_REQUIRED; + if (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ALLOWED_DIGITAL_DTCP)) + keyProperties->rights[i++] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_DTCP_ALLOWED; + if (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ALLOWED_DIGITAL_HDCP14)) + keyProperties->rights[i++] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + if (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ALLOWED_DIGITAL_HDCP22)) + keyProperties->rights[i++] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + if (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ALLOWED_ANALOG_CGMSA) || + SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ALLOWED_ANALOG_UNPROTECTED)) + keyProperties->rights[i++] = SEC_KEYOUTPUTRIGHT_ANALOG_OUTPUT_ALLOWED; + if (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ALLOWED_ANALOG_CGMSA) && + !SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ALLOWED_ANALOG_CGMSA)) + keyProperties->rights[i++] = SEC_KEYOUTPUTRIGHT_CGMSA_REQUIRED; + + // Allow usage of both since it is not identified in the key_header. + // clang-format off + if (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_UNWRAP) && + (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_DECRYPT) || + SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ENCRYPT) || + SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_SIGN) || + SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_DERIVE))) { + keyProperties->usage = SEC_KEYUSAGE_DATA_KEY; + } else if (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_DECRYPT) || + SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_ENCRYPT) || + SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_SIGN) || + SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_DERIVE)) { + keyProperties->usage = SEC_KEYUSAGE_DATA; + } else if (SA_USAGE_BIT_TEST(rights.usage_flags, SA_USAGE_FLAG_UNWRAP)) { + keyProperties->usage = SEC_KEYUSAGE_KEY; + } + // clang-format on + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Get the length of the specified key in bytes. + * + * In case of symmetric keys, the length returned is the actual size of the key data. + * In case of asymmetric keys, the length returned is the size of the modulus in bytes. + * + * @param keyHandle key handle. + * + * @return The status of the operation. + */ +SEC_SIZE SecKey_GetKeyLen(Sec_KeyHandle* keyHandle) { + if (keyHandle == NULL) { + return 0; + } + + SEC_SIZE key_length; + sa_header key_header; + sa_status status; + switch (keyHandle->key_type) { + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + return EC_GROUP_get_degree(EC_KEY_get0_group(keyHandle->key.ec_key)) / 8; + + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + return RSA_size(keyHandle->key.rsa); + + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + case SEC_KEYTYPE_ECC_NISTP256: + case SEC_KEYTYPE_RSA_3072: + status = sa_key_header(&key_header, keyHandle->key.handle); + if (status != SA_STATUS_OK) { + return 0; + } + + return key_header.size; + + default: + return 0; + } +} + +/** + * @brief Get the key type of the specified key handle. + * + * @param keyHandle key handle. + * + * @return The key type or SEC_KEYTYPE_NUM if the key handle is invalid. + */ +Sec_KeyType SecKey_GetKeyType(Sec_KeyHandle* keyHandle) { + return keyHandle->key_type; +} + +/** + * @brief Obtain a handle to a provisioned key. + * + * @param processorHandle secure processor handle. + * @param object_id id of the provisioned key that we are attempting to obtain. + * @param keyHandle pointer to the output key handle. + * + * @return The status of the operation. + */ +Sec_Result SecKey_GetInstance(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_KeyHandle** keyHandle) { + CHECK_PROCHANDLE(processorHandle) + + if (object_id == SEC_OBJECTID_INVALID) + return SEC_RESULT_INVALID_PARAMETERS; + + Sec_StorageLoc location; + Sec_KeyData* key_data = calloc(1, sizeof(Sec_KeyData)); + if (key_data == NULL) { + SEC_LOG_ERROR("calloc failed"); + return SEC_RESULT_FAILURE; + } + + Sec_Result result = retrieve_key_data(processorHandle, object_id, &location, key_data); + if (result != SEC_RESULT_SUCCESS) { + SEC_FREE(key_data); + SEC_LOG_ERROR("retrieve_key_data failed"); + return result; + } + + Sec_Key key; + Sec_KeyContainer key_container; + SEC_SIZE key_length = SEC_KEYCONTAINER_MAX_LEN; + uint8_t* key_buffer = malloc(SEC_KEYCONTAINER_MAX_LEN); + if (key_buffer == NULL) { + SEC_FREE(key_data); + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + result = process_key_container(processorHandle, object_id, key_data->info.kc_type, &key_data->key_container, + key_data->kc_len, &key, &key_container, key_buffer, &key_length); + SEC_FREE(key_data); + SEC_FREE(key_buffer); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("import_key failed"); + return result; + } + + *keyHandle = calloc(1, sizeof(Sec_KeyHandle)); + if (*keyHandle == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + (*keyHandle)->processorHandle = processorHandle; + memcpy(&(*keyHandle)->key, &key, sizeof(Sec_Key)); + if (key_container == SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC || + key_container == SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC || + key_container == SEC_KEYCONTAINER_DER_RSA_3072_PUBLIC || + key_container == SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC) { + (*keyHandle)->key_type = SecKey_GetKeyTypeForClearKeyContainer(key_container); + } else { + sa_header key_header; + sa_status status = sa_key_header(&key_header, (*keyHandle)->key.handle); + if (status == SA_STATUS_OK) { + (*keyHandle)->key_type = get_key_type(&key_header); + } + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Extract an RSA public key from a specified private key handle. + * + * @param keyHandle handle of the private key. + * @param public_key pointer to the output structure containing the public rsa key. + * + * @return The status of the operation. + */ +Sec_Result SecKey_ExtractRSAPublicKey(Sec_KeyHandle* keyHandle, Sec_RSARawPublicKey* public_key) { + CHECK_HANDLE(keyHandle) + if (public_key == NULL) + return SEC_RESULT_INVALID_PARAMETERS; + + switch (keyHandle->key_type) { + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_RSA_3072: { + size_t out_len = SEC_KEYCONTAINER_MAX_LEN; + uint8_t* out = malloc(SEC_KEYCONTAINER_MAX_LEN); + if (out == NULL) { + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + sa_status status; + status = sa_key_get_public(out, &out_len, keyHandle->key.handle); + if (status == SA_STATUS_OK) + Pubops_ExtractRSAPubFromPUBKEYDer(out, out_len, public_key); + + SEC_FREE(out); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; + } + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: { + Sec_Uint32ToBEBytes(RSA_size(keyHandle->key.rsa), public_key->modulus_len_be); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SecUtils_BigNumToBuffer(keyHandle->key.rsa->n, public_key->n, + Sec_BEBytesToUint32(public_key->modulus_len_be)); + SecUtils_BigNumToBuffer(keyHandle->key.rsa->e, public_key->e, PUBLIC_KEY_BUFFER_SIZE); +#else + const BIGNUM* n = NULL; + const BIGNUM* e = NULL; + RSA_get0_key(keyHandle->key.rsa, &n, &e, NULL); + SecUtils_BigNumToBuffer(n, public_key->n, Sec_BEBytesToUint32(public_key->modulus_len_be)); + SecUtils_BigNumToBuffer(e, public_key->e, PUBLIC_KEY_BUFFER_SIZE); +#endif + return SEC_RESULT_SUCCESS; + } + default: + return SEC_RESULT_INVALID_PARAMETERS; + } +} + +/** + * @brief Extract an ECC public key from a specified private key handle. + * + * @param keyHandle handle of the private key. + * @param public_key pointer to the output structure containing the public ecc key. + * + * @return The status of the operation. + */ +Sec_Result SecKey_ExtractECCPublicKey(Sec_KeyHandle* keyHandle, Sec_ECCRawPublicKey* public_key) { + CHECK_HANDLE(keyHandle) + if (public_key == NULL) + return SEC_RESULT_INVALID_PARAMETERS; + + switch (keyHandle->key_type) { + case SEC_KEYTYPE_ECC_NISTP256: { + size_t out_len = SEC_KEYCONTAINER_MAX_LEN; + uint8_t* out = malloc(SEC_KEYCONTAINER_MAX_LEN); + if (out == NULL) { + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + sa_status status = sa_key_get_public(out, &out_len, keyHandle->key.handle); + if (status == SA_STATUS_OK) { + size_t key_length = out_len / 2; + Sec_Uint32ToBEBytes(key_length, public_key->key_len); + memcpy(public_key->x, out, key_length); + memcpy(public_key->y, out + key_length, key_length); + public_key->type = SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + } + + SEC_FREE(out); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; + } + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + if (SecUtils_ECCToPubBinary(keyHandle->key.ec_key, public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ECCToPubBinary failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + + default: + return SEC_RESULT_INVALID_PARAMETERS; + } +} + +/** + * @brief Generate and provision a new key. + * + * @param processorHandle secure processor handle. + * @param object_id id of the key to generate. + * @param keyType type of the key to generate. + * @param location location where the key should be stored. + * + * @return The status of the operation. + */ +Sec_Result SecKey_Generate(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_KeyType keyType, + Sec_StorageLoc location) { + CHECK_PROCHANDLE(processorHandle) + + sa_key_type key_type; + void* parameters; + + Sec_Result result = get_sa_key_type(keyType, &key_type, ¶meters); + if (result != SEC_RESULT_SUCCESS) + return result; + + Sec_Key key; + sa_rights rights; + rights_set_allow_all(&rights, keyType); + sa_status status = sa_key_generate(&key.handle, &rights, key_type, parameters); + SEC_FREE(parameters); + CHECK_STATUS(status) + + return prepare_and_store_key_data(processorHandle, location, object_id, &key, SecKey_GetClearContainer(keyType), + NULL, 0); +} + +/** + * @brief Provision a key. + * + * @param processorHandle secure processor handle. + * @param object_id id of the key to provision. + * @param location storage location where the key should be provisioned. + * @param data_type type of input key container that is being used. + * @param data pointer to the input key container. + * @param data_length the size of the input key container. + * + * @return The status of the operation. + */ +Sec_Result SecKey_Provision(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_StorageLoc location, + Sec_KeyContainer data_type, SEC_BYTE* data, SEC_SIZE data_length) { + CHECK_PROCHANDLE(processorHandle) + + if (object_id == SEC_OBJECTID_INVALID) { + SEC_LOG_ERROR("Cannot provision object with SEC_OBJECTID_INVALID"); + return SEC_RESULT_FAILURE; + } + + if (data_length > SEC_KEYCONTAINER_MAX_LEN) { + SEC_LOG_ERROR("Key data is too long"); + return SEC_RESULT_FAILURE; + } + + Sec_Key key; + Sec_KeyContainer key_container; + SEC_SIZE key_length = SEC_KEYCONTAINER_MAX_LEN; + uint8_t* key_buffer = malloc(SEC_KEYCONTAINER_MAX_LEN); + if (key_buffer == NULL) { + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + Sec_Result result = process_key_container(processorHandle, object_id, data_type, data, data_length, &key, + &key_container, key_buffer, &key_length); + if (result == SEC_RESULT_SUCCESS) + // Convert into an exported key container and store. + result = prepare_and_store_key_data(processorHandle, location, object_id, &key, key_container, key_buffer, + key_length); + + SEC_FREE(key_buffer); + return result; +} + +/** + * @brief Derive and provision a key using the HKDF algorithm. + * + * @param processorHandle secure processor handle. + * @param object_id_derived id of the key to provision. + * @param type_derived derived key type. + * @param loc_derived storage location where the derived key should be provisioned. + * @param macAlgorithm mac algorithm to use in the key derivation process. + * @param salt pointer to the salt value to use in key derivation process. + * @param saltSize the length of the salt buffer in bytes. + * @param info pointer to the info value to use in key derivation process. + * @param infoSize the length of the info buffer in bytes. + * + * @return The status of the operation. + */ +Sec_Result SecKey_Derive_HKDF(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_KeyType type_derived, Sec_StorageLoc loc_derived, Sec_MacAlgorithm macAlgorithm, SEC_BYTE* nonce, + SEC_BYTE* salt, SEC_SIZE saltSize, SEC_BYTE* info, SEC_SIZE infoSize) { + sa_key base_key; + CHECK_PROCHANDLE(processorHandle) + + Sec_Result result = derive_base_key(processorHandle, nonce, &base_key, type_derived); + if (result != SEC_RESULT_SUCCESS) + return result; + + Sec_Key key; + result = derive_hkdf(macAlgorithm, type_derived, salt, saltSize, info, infoSize, base_key, &key.handle); + sa_key_release(base_key); + if (result != SEC_RESULT_SUCCESS) { + return result; + } + + return prepare_and_store_key_data(processorHandle, loc_derived, object_id_derived, &key, + SecKey_GetClearContainer(type_derived), NULL, 0); +} + +/** + * @brief Derive and provision a key using the Concat KDF algorithm. + * + * @param processorHandle secure processor handle. + * @param object_id_derived id of the key to provision. + * @param type_derived derived key type. + * @param loc_derived storage location where the derived key should be provisioned. + * @param digestAlgorithm digest algorithm to use in the key derivation process. + * @param otherInfo pointer to the info value to use in key derivation process. + * @param otherInfoSize the length of the other info buffer in bytes. + * + * @return The status of the operation. + */ +Sec_Result SecKey_Derive_ConcatKDF(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_KeyType type_derived, Sec_StorageLoc loc_derived, Sec_DigestAlgorithm digestAlgorithm, SEC_BYTE* nonce, + SEC_BYTE* otherInfo, SEC_SIZE otherInfoSize) { + sa_key base_key; + CHECK_PROCHANDLE(processorHandle) + + Sec_Result result = derive_base_key(processorHandle, nonce, &base_key, type_derived); + if (result != SEC_RESULT_SUCCESS) + return result; + + Sec_Key key; + result = derive_kdf_concat(digestAlgorithm, type_derived, otherInfo, otherInfoSize, base_key, &key.handle); + sa_key_release(base_key); + if (result != SEC_RESULT_SUCCESS) { + return result; + } + + return prepare_and_store_key_data(processorHandle, loc_derived, object_id_derived, &key, + SecKey_GetClearContainer(type_derived), NULL, 0); +} + +Sec_Result SecKey_Derive_PBEKDF(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_KeyType type_derived, Sec_StorageLoc loc_derived, Sec_MacAlgorithm macAlgorithm, SEC_BYTE* nonce, + SEC_BYTE* salt, SEC_SIZE saltSize, SEC_SIZE numIterations) { + CHECK_PROCHANDLE(processorHandle) + + SEC_BYTE loop[] = {0, 0, 0, 0}; + SEC_BYTE out_key[SEC_AES_KEY_MAX_LEN]; + + if (!SecKey_IsSymetric(type_derived)) { + SEC_LOG_ERROR("Only symmetric keys can be derived"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + sa_key base_key; + Sec_Result result = derive_base_key(processorHandle, nonce, &base_key, type_derived); + if (result != SEC_RESULT_SUCCESS) + return result; + + SEC_SIZE key_length = SecKey_GetKeyLenForKeyType(type_derived); + SEC_SIZE digest_length = SecDigest_GetDigestLenForAlgorithm(SecMac_GetDigestAlgorithm(macAlgorithm)); + SEC_SIZE l = key_length / digest_length + ((key_length % digest_length == 0) ? 0 : 1); + + for (size_t i = 1; i <= l; i++) { + loop[3] = i; + + SEC_SIZE cp_len = (i == l) ? key_length % digest_length : digest_length; + + sa_crypto_mac_context mac_context; + sa_mac_algorithm mac_algorithm = + (macAlgorithm == SEC_MACALGORITHM_CMAC_AES_128) ? SA_MAC_ALGORITHM_CMAC : SA_MAC_ALGORITHM_HMAC; + void* parameters = NULL; + if (mac_algorithm != SEC_MACALGORITHM_CMAC_AES_128) { + sa_mac_parameters_hmac hmac_parameters = { + (mac_algorithm == SEC_MACALGORITHM_HMAC_SHA1) ? SA_DIGEST_ALGORITHM_SHA1 : + SA_DIGEST_ALGORITHM_SHA256}; + parameters = &hmac_parameters; + } + + sa_status status = sa_crypto_mac_init(&mac_context, mac_algorithm, base_key, parameters); + CHECK_MAC_RESULT(status, base_key, 0) + + status = sa_crypto_mac_process(mac_context, salt, saltSize); + CHECK_MAC_RESULT(status, base_key, mac_context) + + status = sa_crypto_mac_process(mac_context, loop, sizeof(loop)); + CHECK_MAC_RESULT(status, base_key, mac_context) + + SEC_BYTE mac1[SEC_MAC_MAX_LEN]; + size_t mac1_len; + status = sa_crypto_mac_compute(mac1, &mac1_len, mac_context); + sa_crypto_mac_release(mac_context); + CHECK_MAC_RESULT(status, base_key, 0) + + SEC_BYTE out[SEC_MAC_MAX_LEN]; + memcpy(out, mac1, digest_length); + + for (size_t j = 1; j < numIterations; j++) { + status = sa_crypto_mac_init(&mac_context, mac_algorithm, base_key, parameters); + CHECK_MAC_RESULT(status, base_key, 0) + + status = sa_crypto_mac_process(mac_context, mac1, digest_length); + CHECK_MAC_RESULT(status, base_key, mac_context) + + SEC_BYTE mac2[SEC_MAC_MAX_LEN]; + size_t mac2_len; + status = sa_crypto_mac_compute(mac2, &mac2_len, mac_context); + sa_crypto_mac_release(mac_context); + CHECK_MAC_RESULT(status, base_key, 0) + + memcpy(mac1, mac2, digest_length); + + for (int k = 0; k < digest_length; ++k) { + out[k] ^= mac1[k]; + } + } + + memcpy(out_key + (i - 1) * digest_length, out, cp_len); + } + + sa_key_release(base_key); + + return SecKey_Provision(processorHandle, object_id_derived, loc_derived, SecKey_GetClearContainer(type_derived), + out_key, key_length); +} + +/** + * @brief Derive and provision an AES 128-bit key a vendor specific key ladder algorithm. + * + * This function will generate a key derived from one of the OTP keys. The + * result of this function may not be usable in Digest and Mac _UpdateWithKey + * functions. In general, this function will keep the derived key more secure + * then the other SecKey_Derive functions because the key will not be accessable + * by the host even during the generation time. + * + * @param processorHandle secure processor handle. + * @param object_id_derived id of the key to provision. + * @param loc_derived storage location where the derived key should be provisioned. + * @param input input buffer for the key derivation. + * @param input_len the length of the input buffer. + * + * @return The status of the operation. + */ +Sec_Result SecKey_Derive_VendorAes128(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_StorageLoc loc_derived, SEC_BYTE* input, SEC_SIZE input_len) { + SEC_BYTE digest[SEC_DIGEST_MAX_LEN]; + SEC_SIZE digest_len; + SEC_BYTE digest2[SEC_DIGEST_MAX_LEN]; + SEC_SIZE digest2_len; + CHECK_PROCHANDLE(processorHandle) + + Sec_Result result = SecDigest_SingleInput(processorHandle, SEC_DIGESTALGORITHM_SHA256, input, input_len, digest, + &digest_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_SingleInput failed"); + return SEC_RESULT_FAILURE; + } + + result = SecDigest_SingleInput(processorHandle, SEC_DIGESTALGORITHM_SHA256, digest, digest_len, digest2, + &digest2_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_SingleInput failed"); + return SEC_RESULT_FAILURE; + } + + /* setup key ladder inputs */ + SEC_SIZE key_length = SecKey_GetKeyLenForKeyType(SEC_KEYTYPE_AES_128); + SEC_BYTE input1[key_length]; + SEC_BYTE input2[key_length]; + SEC_BYTE input3[key_length]; + SEC_BYTE input4[key_length]; + memcpy(input1, digest, key_length); + memcpy(input2, digest + key_length, key_length); + memcpy(input3, digest2, key_length); + memcpy(input4, digest2 + key_length, key_length); + + return SecKey_Derive_KeyLadderAes128(processorHandle, object_id_derived, loc_derived, SEC_KEYLADDERROOT_NUM, + input1, input2, input3, input4); +} + +/** + * @brief Derive and provision an AES 128-bit key. + * + * This function will generate a key derived from one of the OTP keys. The + * result of this function may not be usable in Digest and Mac _UpdateWithKey + * functions. In general, this function will keep the derived key more secure + * then the other SecKey_Derive functions because the key will not be accessable + * by the host even during the generation time. + * + * @param processorHandle secure processor handle. + * @param object_id_derived id of the key to provision. + * @param type_derived derived key type. + * @param loc_derived storage location where the derived key should be provisioned. + * @param input1 16 byte input for stage 1 of the key ladder. + * @param input2 16 byte input for stage 2 of the key ladder. + * @param input3 16 byte input for stage 3 of the key ladder. + * @param input4 16 byte input for stage 4 of the key ladder. + * + * @return The status of the operation. + */ +Sec_Result SecKey_Derive_KeyLadderAes128(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id_derived, + Sec_StorageLoc loc_derived, Sec_KeyLadderRoot root, SEC_BYTE* input1, SEC_BYTE* input2, SEC_BYTE* input3, + SEC_BYTE* input4) { + CHECK_PROCHANDLE(processorHandle) + + SEC_SIZE key_length = SecKey_GetKeyLenForKeyType(SEC_KEYTYPE_AES_128); + Sec_Key key; + if (derive_root_key_ladder(input1, input2, input3, input4, key_length, &key.handle, SEC_KEYTYPE_AES_128) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Derive_root_key_ladder failed"); + return SEC_RESULT_FAILURE; + } + + return prepare_and_store_key_data(processorHandle, loc_derived, object_id_derived, &key, + SEC_KEYCONTAINER_RAW_AES_128, NULL, 0); +} + +Sec_Result SecKey_Derive_CMAC_AES128(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID idDerived, + Sec_KeyType typeDerived, Sec_StorageLoc locDerived, SEC_OBJECTID derivationKey, SEC_BYTE* otherData, + SEC_SIZE otherDataSize, SEC_BYTE* counter, SEC_SIZE counterSize) { + Sec_KeyHandle* keyHandle; + + Sec_Result result = SecKey_GetInstance(processorHandle, derivationKey, &keyHandle); + if (result != SEC_RESULT_SUCCESS) + return result; + + Sec_Key key; + result = derive_kdf_cmac(typeDerived, otherData, otherDataSize, counter, counterSize, keyHandle->key.handle, + &key.handle); + SecKey_Release(keyHandle); + if (result != SEC_RESULT_SUCCESS) + return result; + + return prepare_and_store_key_data(processorHandle, locDerived, idDerived, &key, + SecKey_GetClearContainer(typeDerived), NULL, 0); +} + +/** + * @brief Obtain a digest value computed over the base key contents. + * + * @param processorHandle secure processor handle. + * @param nonce client nonce. + * @param alg digest algorithm. + * @param digest output digest value. + * @param digest_len the length of output digest value. + * + * @return status of the operation. + */ +Sec_Result SecKey_ComputeBaseKeyDigest(Sec_ProcessorHandle* processorHandle, SEC_BYTE* nonce, + Sec_DigestAlgorithm alg, SEC_BYTE* digest, SEC_SIZE* digest_len) { + + if (SecKey_Derive_BaseKey(processorHandle, SEC_OBJECTID_BASE_KEY_AES, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + nonce) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_BaseKey failed"); + return SEC_RESULT_FAILURE; + } + + if (SecDigest_SingleInputWithKeyId(processorHandle, alg, SEC_OBJECTID_BASE_KEY_AES, digest, digest_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_SingleInputWithKeyId failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Generates a shared symmetric key and stores it in a specified location. + * + * A shared secret is calculated using the ECDH algorithm. The shared + * secret is converted to a key using the Concat KDF (SP800-56A Section + * 5.8.1). If the key with the same id already exists, the call will + * overwrite the existing key with the new key. SHA-256 is the digest + * algorithm. + * + * @param keyHandle Handle of my private ECC key. + * @param otherPublicKey Public key for other party in key agreement. + * @param type_derived Type of key to generate. Only symmetric keys can be derived. + * @param id_derived 64-bit object id identifying the key to be generated. + * @param loc_id Location where the resulting key will be stored. + * @param digestAlgorithm Digest algorithm to use in KDF (typically SEC_DIGESTALGORITHM_SHA256). + * @param otherInfo Input keying material + * AlgorithmID || PartyUInfo || PartyVInfo) {|| SuppPubInfo }{|| SuppPrivInfo}. + * @param otherInfoSize Size of otherInfo (in bytes). + */ +Sec_Result SecKey_ECDHKeyAgreementWithKDF(Sec_KeyHandle* keyHandle, Sec_ECCRawPublicKey* otherPublicKey, + Sec_KeyType type_derived, SEC_OBJECTID id_derived, Sec_StorageLoc loc_derived, Sec_Kdf kdf, + Sec_DigestAlgorithm digestAlgorithm, const SEC_BYTE* otherInfo, SEC_SIZE otherInfoSize) { + if (kdf != SEC_KDF_CONCAT) { + SEC_LOG_ERROR("Invalid kdf parameter encountered: %d", kdf); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (otherPublicKey->type != SEC_KEYTYPE_ECC_NISTP256_PUBLIC && + otherPublicKey->type != SEC_KEYTYPE_ECC_NISTP256) { + SEC_LOG_ERROR("Can only exchange ECC keys"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (!SecKey_IsSymetric(type_derived)) { + SEC_LOG_ERROR("Can only derive symetric keys"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + // Derive the shared secret with a key exchange. + sa_key shared_secret; + sa_rights rights; + rights_set_allow_all(&rights, type_derived); + + size_t other_public_length = Sec_BEBytesToUint32(otherPublicKey->key_len); + SEC_BYTE other_public[other_public_length * 2]; + memcpy(other_public, otherPublicKey->x, other_public_length); + memcpy(other_public + other_public_length, otherPublicKey->y, other_public_length); + + sa_status status = sa_key_exchange(&shared_secret, &rights, SA_KEY_EXCHANGE_ALGORITHM_ECDH, + keyHandle->key.handle, other_public, other_public_length * 2, NULL); + CHECK_STATUS(status) + + // Derive the key from the shared secret using a key derivation algorithm. + if (digestAlgorithm != SEC_DIGESTALGORITHM_SHA1 && digestAlgorithm != SEC_DIGESTALGORITHM_SHA256) { + sa_key_release(shared_secret); + SEC_LOG_ERROR("Unsupported digest algorithm specified: %d", digestAlgorithm); + return SEC_RESULT_INVALID_PARAMETERS; + } + + sa_digest_algorithm digest_algorithm = + (digestAlgorithm == SEC_DIGESTALGORITHM_SHA1) ? SA_DIGEST_ALGORITHM_SHA1 : SA_DIGEST_ALGORITHM_SHA256; + + sa_kdf_algorithm kdf_algorithm; + void* parameters; + sa_kdf_parameters_hkdf hkdf_parameters; + sa_kdf_parameters_concat concat_parameters; + sa_kdf_parameters_ansi_x963 x963_parameters; + switch (kdf) { + case SEC_KDF_HKDF: + kdf_algorithm = SA_KDF_ALGORITHM_HKDF; + hkdf_parameters.key_length = SecKey_GetKeyLenForKeyType(type_derived); + hkdf_parameters.digest_algorithm = digest_algorithm; + hkdf_parameters.parent = shared_secret; + hkdf_parameters.salt = NULL; + hkdf_parameters.salt_length = 0; + hkdf_parameters.info = otherInfo; + hkdf_parameters.info_length = otherInfoSize; + parameters = &hkdf_parameters; + break; + + case SEC_KDF_CONCAT: + kdf_algorithm = SA_KDF_ALGORITHM_CONCAT; + concat_parameters.key_length = SecKey_GetKeyLenForKeyType(type_derived); + concat_parameters.digest_algorithm = digest_algorithm; + concat_parameters.parent = shared_secret; + concat_parameters.info = otherInfo; + concat_parameters.info_length = otherInfoSize; + parameters = &concat_parameters; + break; + + case SEC_KDF_ANSI_X_9_63: + kdf_algorithm = SA_KDF_ALGORITHM_ANSI_X963; + x963_parameters.key_length = SecKey_GetKeyLenForKeyType(type_derived); + x963_parameters.digest_algorithm = digest_algorithm; + x963_parameters.parent = shared_secret; + x963_parameters.info = otherInfo; + x963_parameters.info_length = otherInfoSize; + parameters = &x963_parameters; + break; + + default: + sa_key_release(shared_secret); + return SEC_RESULT_INVALID_PARAMETERS; + } + + Sec_Key key; + status = sa_key_derive(&key.handle, &rights, kdf_algorithm, parameters); + sa_key_release(shared_secret); + CHECK_STATUS(status) + + return prepare_and_store_key_data(keyHandle->processorHandle, loc_derived, id_derived, &key, + SecKey_GetClearContainer(type_derived), NULL, 0); +} + +Sec_Result SecKey_Derive_BaseKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID idDerived, Sec_KeyType key_type, + Sec_StorageLoc loc, SEC_BYTE* nonce) { + CHECK_PROCHANDLE(processorHandle) + + Sec_Key key; + Sec_Result result = derive_base_key(processorHandle, nonce, &key.handle, key_type); + if (result != SEC_RESULT_SUCCESS) + return result; + + return prepare_and_store_key_data(processorHandle, loc, idDerived, &key, SecKey_GetClearContainer(key_type), NULL, + 0); +} + +Sec_Result SecKey_Derive_HKDF_BaseKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID idDerived, + Sec_KeyType typeDerived, Sec_StorageLoc locDerived, Sec_MacAlgorithm macAlgorithm, SEC_BYTE* salt, + SEC_SIZE saltSize, SEC_BYTE* info, SEC_SIZE infoSize, SEC_OBJECTID baseKeyId) { + Sec_KeyHandle* keyHandle; + + Sec_Result result = SecKey_GetInstance(processorHandle, baseKeyId, &keyHandle); + if (result != SEC_RESULT_SUCCESS) { + return result; + } + + Sec_Key key; + result = derive_hkdf(macAlgorithm, typeDerived, salt, saltSize, info, infoSize, keyHandle->key.handle, + &key.handle); + SecKey_Release(keyHandle); + if (result != SEC_RESULT_SUCCESS) + return result; + + return prepare_and_store_key_data(processorHandle, locDerived, idDerived, &key, + SecKey_GetClearContainer(typeDerived), NULL, 0); +} + +Sec_Result SecKey_Derive_ConcatKDF_BaseKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID idDerived, + Sec_KeyType typeDerived, Sec_StorageLoc locDerived, Sec_DigestAlgorithm digestAlgorithm, SEC_BYTE* otherInfo, + SEC_SIZE otherInfoSize, SEC_OBJECTID baseKeyId) { + Sec_KeyHandle* keyHandle; + + Sec_Result result = SecKey_GetInstance(processorHandle, baseKeyId, &keyHandle); + if (result != SEC_RESULT_SUCCESS) { + return result; + } + + Sec_Key key; + result = derive_kdf_concat(digestAlgorithm, typeDerived, otherInfo, otherInfoSize, keyHandle->key.handle, + &key.handle); + SecKey_Release(keyHandle); + if (result != SEC_RESULT_SUCCESS) + return result; + + return prepare_and_store_key_data(processorHandle, locDerived, idDerived, &key, + SecKey_GetClearContainer(typeDerived), NULL, 0); +} + +/** + * @brief compute inputs for the base key ladder. + */ +Sec_Result SecKey_ComputeBaseKeyLadderInputs(Sec_ProcessorHandle* processorHandle, + const char* inputDerivationStr, const char* cipherAlgorithmStr, SEC_BYTE* nonce, + Sec_DigestAlgorithm digestAlgorithm, SEC_SIZE inputSize, SEC_BYTE* c1, SEC_BYTE* c2, SEC_BYTE* c3, + SEC_BYTE* c4) { + int i; + SEC_BYTE loop[] = {0, 0, 0, 0}; + SEC_BYTE digest[SEC_DIGEST_MAX_LEN]; + SEC_SIZE digest_len; + Sec_Result result = SEC_RESULT_FAILURE; + SEC_BYTE* c[4] = {c1, c2, c3, c4}; + CHECK_PROCHANDLE(processorHandle) + + if (inputSize > SecDigest_GetDigestLenForAlgorithm(digestAlgorithm)) { + SEC_LOG_ERROR("Invalid input size for specified digest algorithm"); + return SEC_RESULT_FAILURE; + } + + SEC_SIZE buffer_len = SEC_NONCE_LEN + strlen(inputDerivationStr) + strlen(cipherAlgorithmStr) + sizeof(loop); + SEC_BYTE input_buffer[buffer_len]; + + for (i = 1; i <= 4; i++) { + loop[3] = i; + SEC_SIZE offset = 0; + memcpy(input_buffer + offset, nonce, SEC_NONCE_LEN); + offset += SEC_NONCE_LEN; + memcpy(input_buffer + offset, inputDerivationStr, strlen(inputDerivationStr)); // NOLINT + offset += strlen(inputDerivationStr); + memcpy(input_buffer + offset, cipherAlgorithmStr, strlen(cipherAlgorithmStr)); // NOLINT + offset += strlen(cipherAlgorithmStr); + memcpy(input_buffer + offset, loop, sizeof(loop)); + offset += sizeof(loop); + + result = SecDigest_SingleInput(processorHandle, digestAlgorithm, input_buffer, offset, digest, &digest_len); + if (result != SEC_RESULT_SUCCESS) + return result; + + memcpy(c[i - 1], digest, inputSize); + } + + return result; +} + +/** + * @brief Delete a provisioned key. + * + * @param processorHandle secure processor handle. + * @param object_id id of the key to delete. + * + * @return The status of the operation. + */ +Sec_Result SecKey_Delete(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id) { + Sec_RAMKeyData* ram_key = NULL; + Sec_RAMKeyData* ram_key_parent = NULL; + SEC_SIZE keys_found = 0; + SEC_SIZE keys_deleted = 0; + CHECK_PROCHANDLE(processorHandle) + + /* ram */ + find_ram_key_data(processorHandle, object_id, &ram_key, &ram_key_parent); + if (ram_key != NULL) { + if (ram_key_parent == NULL) + processorHandle->ram_keys = ram_key->next; + else + ram_key_parent->next = ram_key->next; + + Sec_Memset(ram_key, 0, sizeof(Sec_RAMKeyData)); + + SEC_FREE(ram_key); + + ++keys_found; + ++keys_deleted; + } + + /* file system */ + if (processorHandle->app_dir != NULL) { + char file_name[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name, sizeof(file_name), SEC_KEY_FILENAME_PATTERN, processorHandle->app_dir, object_id); + if (SecUtils_FileExists(file_name)) { + SecUtils_RmFile(file_name); + ++keys_found; + + if (!SecUtils_FileExists(file_name)) + ++keys_deleted; + } + + char file_name_info[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_info, sizeof(file_name_info), SEC_KEYINFO_FILENAME_PATTERN, processorHandle->app_dir, + object_id); + if (!SecUtils_FileExists(file_name) && SecUtils_FileExists(file_name_info)) { + SecUtils_RmFile(file_name_info); + } + + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + processorHandle->app_dir, object_id); + if (!SecUtils_FileExists(file_name) && SecUtils_FileExists(file_name_verification)) { + SecUtils_RmFile(file_name_verification); + } + } + + if (keys_found == 0) + return SEC_RESULT_NO_SUCH_ITEM; + + if (keys_found != keys_deleted) + return SEC_RESULT_ITEM_NON_REMOVABLE; + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Release the key object. + * + * @param keyHandle key handle to release. + * + * @return The status of the operation. + */ +Sec_Result SecKey_Release(Sec_KeyHandle* keyHandle) { + CHECK_HANDLE(keyHandle) + + switch (keyHandle->key_type) { + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + SEC_ECC_FREE(keyHandle->key.ec_key); + break; + + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + SEC_RSA_FREE(keyHandle->key.rsa); + break; + + default: + sa_key_release(keyHandle->key.handle); + break; + } + + SEC_FREE(keyHandle); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Obtain a processor handle. + * + * @param keyHandle key handle. + * + * @return Processor handle. + */ +Sec_ProcessorHandle* SecKey_GetProcessor(Sec_KeyHandle* keyHandle) { + if (keyHandle != NULL) + return keyHandle->processorHandle; + + return NULL; +} + +Sec_Result SecKey_ExportKey(Sec_KeyHandle* keyHandle, SEC_BYTE* derivationInput, SEC_BYTE* exportedKey, + SEC_SIZE keyBufferLen, SEC_SIZE* keyBytesWritten) { + CHECK_HANDLE(keyHandle) + + if (keyHandle->key_type == SEC_KEYTYPE_RSA_1024_PUBLIC || + keyHandle->key_type == SEC_KEYTYPE_RSA_2048_PUBLIC || + keyHandle->key_type == SEC_KEYTYPE_RSA_3072_PUBLIC || + keyHandle->key_type == SEC_KEYTYPE_ECC_NISTP256_PUBLIC) + return SEC_RESULT_FAILURE; + + return export_key(&keyHandle->key, derivationInput, exportedKey, keyBufferLen, keyBytesWritten); +} + +Sec_KeyType SecKey_GetRSAKeyTypeForBitLength(int numBits) { + switch (numBits) { + case 1024: + return SEC_KEYTYPE_RSA_1024; + + case 2048: + return SEC_KEYTYPE_RSA_2048; + + case 3072: + return SEC_KEYTYPE_RSA_3072; + + default: + SEC_LOG_ERROR("Invalid numBits encountered: %d", numBits); + return SEC_KEYTYPE_NUM; + } +} + +Sec_KeyType SecKey_GetRSAKeyTypeForByteLength(int numBytes) { + switch (numBytes) { + case 128: + return SEC_KEYTYPE_RSA_1024; + + case 256: + return SEC_KEYTYPE_RSA_2048; + + case 384: + return SEC_KEYTYPE_RSA_3072; + + default: + SEC_LOG_ERROR("Invalid numBytes encountered: %d", numBytes); + return SEC_KEYTYPE_NUM; + } +} + +/** + * @brief Checks if a passed in key type is symmetric. + * + * @param type key type. + * + * @return 1 if key type is symmetric, 0 if asymmetric. + */ +SEC_BOOL SecKey_IsSymetric(Sec_KeyType type) { + switch (type) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + return SEC_TRUE; + + default: + break; + } + + return SEC_FALSE; +} + +/** + * @brief Checks if a passed in key type is an AES key. + * + * @param type key type. + * + * @return 1 if key type is AES, 0 if not. + */ +SEC_BOOL SecKey_IsAES(Sec_KeyType type) { + switch (type) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + return SEC_TRUE; + + default: + break; + } + + return SEC_FALSE; +} + +SEC_BOOL SecKey_IsHMAC(Sec_KeyType type) { + switch (type) { + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + return SEC_TRUE; + + default: + break; + } + + return SEC_FALSE; +} + +/** + * @brief Checks if a passed in key type is RSA. + * + * @param type key type. + * + * @return 1 if key type is rsa, 0 otherwise. + */ +SEC_BOOL SecKey_IsRsa(Sec_KeyType type) { + switch (type) { + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + return SEC_TRUE; + + default: + break; + } + + return SEC_FALSE; +} + +/** + * @brief Checks if a passed in key type is pub RSA. + * + * @param type key type. + * + * @return 1 if key type is pub rsa, 0 otherwise. + */ +SEC_BOOL SecKey_IsPubRsa(Sec_KeyType type) { + switch (type) { + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + return SEC_TRUE; + + default: + break; + } + + return SEC_FALSE; +} + +/** + * @brief Checks if a passed in key type is priv RSA. + * + * @param type key type. + * + * @return 1 if key type is priv rsa, 0 otherwise. + */ +SEC_BOOL SecKey_IsPrivRsa(Sec_KeyType type) { + switch (type) { + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_RSA_3072: + return SEC_TRUE; + + default: + break; + } + + return SEC_FALSE; +} + +/** + * @brief Checks if a passed in key type is ECC. + * + * @param type key type. + * + * @return 1 if key type is priv ECC, 0 otherwise. + */ +SEC_BOOL SecKey_IsEcc(Sec_KeyType type) { + switch (type) { + case SEC_KEYTYPE_ECC_NISTP256: + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + return SEC_TRUE; + + default: + break; + } + + return SEC_FALSE; +} + +/** + * @brief Checks if a passed in key type is priv ECC. + * + * @param type key type. + * + * @return 1 if key type is priv ECC, 0 otherwise. + */ +SEC_BOOL SecKey_IsPrivEcc(Sec_KeyType type) { + if (type == SEC_KEYTYPE_ECC_NISTP256) + return SEC_TRUE; + + return SEC_FALSE; +} + +/** + * @brief Checks if a passed in key type is pub ECC. + * + * @param type key type. + * + * @return 1 if key type is pub ECC, 0 otherwise. + */ +SEC_BOOL SecKey_IsPubEcc(Sec_KeyType type) { + if (type == SEC_KEYTYPE_ECC_NISTP256_PUBLIC) + return SEC_TRUE; + + return SEC_FALSE; +} + +/** + * @brief Is the specified container a raw (clear) container. + */ +SEC_BOOL SecKey_IsClearKeyContainer(Sec_KeyContainer kct) { + switch (kct) { + case SEC_KEYCONTAINER_RAW_AES_128: + case SEC_KEYCONTAINER_RAW_AES_256: + case SEC_KEYCONTAINER_RAW_HMAC_128: + case SEC_KEYCONTAINER_RAW_HMAC_160: + case SEC_KEYCONTAINER_RAW_HMAC_256: + case SEC_KEYCONTAINER_RAW_RSA_1024: + case SEC_KEYCONTAINER_RAW_RSA_2048: + case SEC_KEYCONTAINER_RAW_RSA_3072: + case SEC_KEYCONTAINER_RAW_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_RAW_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_RAW_RSA_3072_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_1024: + case SEC_KEYCONTAINER_PEM_RSA_2048: + case SEC_KEYCONTAINER_PEM_RSA_3072: + case SEC_KEYCONTAINER_PEM_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_3072_PUBLIC: + case SEC_KEYCONTAINER_RAW_ECC_NISTP256: + case SEC_KEYCONTAINER_RAW_ECC_NISTP256_PUBLIC: + return SEC_TRUE; + + default: + return SEC_FALSE; + } +} + +/** + * @brief Obtain a key container type for a specified key type. + * + * @param key_type key type. + * @return key container type. + */ +Sec_KeyContainer SecKey_GetClearContainer(Sec_KeyType key_type) { + switch (key_type) { + case SEC_KEYTYPE_AES_128: + return SEC_KEYCONTAINER_RAW_AES_128; + + case SEC_KEYTYPE_AES_256: + return SEC_KEYCONTAINER_RAW_AES_256; + + case SEC_KEYTYPE_HMAC_128: + return SEC_KEYCONTAINER_RAW_HMAC_128; + + case SEC_KEYTYPE_HMAC_160: + return SEC_KEYCONTAINER_RAW_HMAC_160; + + case SEC_KEYTYPE_HMAC_256: + return SEC_KEYCONTAINER_RAW_HMAC_256; + + case SEC_KEYTYPE_RSA_1024: + return SEC_KEYCONTAINER_DER_RSA_1024; + + case SEC_KEYTYPE_RSA_2048: + return SEC_KEYCONTAINER_DER_RSA_2048; + + case SEC_KEYTYPE_RSA_3072: + return SEC_KEYCONTAINER_DER_RSA_3072; + + case SEC_KEYTYPE_RSA_1024_PUBLIC: + return SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC; + + case SEC_KEYTYPE_RSA_2048_PUBLIC: + return SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC; + + case SEC_KEYTYPE_RSA_3072_PUBLIC: + return SEC_KEYCONTAINER_DER_RSA_3072_PUBLIC; + + case SEC_KEYTYPE_ECC_NISTP256: + return SEC_KEYCONTAINER_RAW_ECC_PRIVONLY_NISTP256; + + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + return SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC; + + default: + return SEC_KEYCONTAINER_NUM; + } +} + +/** + * @brief Find if the key with a specific id has been provisioned. + * + * @param processorHandle secure processor handle. + * @param object_id id of the certificate. + * + * @return 1 if an object has been provisioned, 0 if it has not been. + */ +SEC_BOOL SecKey_IsProvisioned(Sec_ProcessorHandle* processorHandle, + SEC_OBJECTID object_id) { + Sec_KeyHandle* keyHandle; + + if (SEC_OBJECTID_INVALID == object_id) + return SEC_FALSE; + + if (SecKey_GetInstance(processorHandle, object_id, &keyHandle) != SEC_RESULT_SUCCESS) + return SEC_FALSE; + + SecKey_Release(keyHandle); + return SEC_TRUE; +} + +/** + * @brief finds the first available key id in the range passed in. + * + * @param proc secure processor. + * @param base bottom of the range to search. + * @param top top of the range to search. + * @return + */ +SEC_OBJECTID SecKey_ObtainFreeObjectId(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID base, SEC_OBJECTID top) { + SEC_OBJECTID id; + Sec_KeyHandle* keyHandle; + Sec_Result result; + + for (id = base; id < top; ++id) { + result = SecKey_GetInstance(processorHandle, id, &keyHandle); + if (result == SEC_RESULT_SUCCESS) + SecKey_Release(keyHandle); + else + return id; + } + + return SEC_OBJECTID_INVALID; +} + +/** + * @brief Get the type (MSB byte) of the object id. + */ +uint8_t SecKey_GetObjectType(SEC_OBJECTID object_id) { + return (SEC_BYTE) ((object_id & 0xff00000000000000ULL) >> 56); +} + +/** + * @brief Obtain a digest value computed over a specified key. + * + * @param proc secure processor handle. + * @param key_id key id. + * @param alg digest algorithm to use. + * @param digest output digest value. + * @param digest_len size of the written digest value. + * @return + */ +Sec_Result SecKey_ComputeKeyDigest(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID key_id, Sec_DigestAlgorithm alg, + SEC_BYTE* digest, SEC_SIZE* digest_len) { + Sec_KeyHandle* keyHandle = NULL; + Sec_DigestHandle* digestHandle = NULL; + Sec_Result result = SEC_RESULT_FAILURE; + do { + if (SecKey_GetInstance(processorHandle, key_id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance returned error"); + break; + } + + if (SecDigest_GetInstance(processorHandle, alg, &digestHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_GetInstance returned error"); + break; + } + + if (SecDigest_UpdateWithKey(digestHandle, keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_UpdateWithKey returned error"); + break; + } + + result = SecDigest_Release(digestHandle, digest, digest_len); + digestHandle = NULL; + } while (SEC_FALSE); + + if (keyHandle != NULL) + SecKey_Release(keyHandle); + + if (digestHandle != NULL) + SecDigest_Release(digestHandle, digest, digest_len); + + return result; +} + +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1V3(Sec_Asn1KC* kc, SEC_BYTE* payload, SEC_SIZE payloadLen, + SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, SEC_BYTE* wrappingIv, + Sec_CipherAlgorithm* wrappingAlg, SEC_SIZE* key_offset, SEC_BYTE* wrappingKey, SEC_SIZE wrappingKeyLen, + SEC_SIZE* writtenWrappingKey) { + uint64_t ulong_val; + SEC_SIZE written_iv; + + *writtenWrappingKey = 0; + *wrappingId = 0; + + if (kc == NULL) + return SEC_RESULT_FAILURE; + + if (SecAsn1KC_GetAttrBuffer(kc, SEC_ASN1KC_WRAPPEDKEY, payload, payloadLen, written) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPEDKEY failed"); + return SEC_RESULT_FAILURE; + } + + if (SecAsn1KC_GetAttrUlong(kc, SEC_ASN1KC_WRAPPEDKEYTYPEID, &ulong_val) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPEDKEYTYPEID failed"); + return SEC_RESULT_FAILURE; + } + + *wrappedKeyType = (Sec_KeyType) ulong_val; + + if (SecAsn1KC_HasAttr(kc, SEC_ASN1KC_WRAPPEDKEYOFFSET)) { + if (SecAsn1KC_GetAttrUlong(kc, SEC_ASN1KC_WRAPPEDKEYOFFSET, &ulong_val) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPEDKEYOFFSET failed"); + return SEC_RESULT_FAILURE; + } + + *key_offset = (SEC_SIZE) ulong_val; + } else + *key_offset = (SEC_SIZE) 0; // default value + + if (SecAsn1KC_HasAttr(kc, SEC_ASN1KC_WRAPPINGIV) && + SecAsn1KC_GetAttrBuffer(kc, SEC_ASN1KC_WRAPPINGIV, wrappingIv, SEC_AES_BLOCK_SIZE, &written_iv) != + SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPEDKEYOFFSET failed"); + return SEC_RESULT_FAILURE; + } + + if (SecAsn1KC_GetAttrUlong(kc, SEC_ASN1KC_WRAPPINGALGORITHMID, &ulong_val) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPINGALGORITHMID failed"); + return SEC_RESULT_FAILURE; + } + + *wrappingAlg = (Sec_CipherAlgorithm) ulong_val; + + if (SecAsn1KC_HasAttr(kc, SEC_ASN1KC_WRAPPINGKEY)) { + if (SecAsn1KC_GetAttrBuffer(kc, SEC_ASN1KC_WRAPPINGKEY, wrappingKey, wrappingKeyLen, writtenWrappingKey) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPINGKEY failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (SecAsn1KC_GetAttrUint64(kc, SEC_ASN1KC_WRAPPINGKEYID, wrappingId) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPINGKEYID failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1BufferOff(SEC_BYTE* asn1, SEC_SIZE asn1_len, SEC_BYTE* payload, + SEC_SIZE payloadLen, SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, + SEC_BYTE* wrappingIv, Sec_CipherAlgorithm* wrappingAlg, SEC_SIZE* key_offset) { + Sec_Asn1KC* asn1kc = NULL; + Sec_Result result = SEC_RESULT_FAILURE; + + asn1kc = SecAsn1KC_Decode(asn1, asn1_len); + if (asn1kc == NULL) { + SEC_LOG_ERROR("SecAsn1KC_Decode failed"); + SecAsn1KC_Free(asn1kc); + return result; + } + + result = SecKey_ExtractWrappedKeyParamsAsn1Off(asn1kc, payload, payloadLen, written, wrappedKeyType, wrappingId, + wrappingIv, wrappingAlg, key_offset); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractWrappedKeyParamsAsn1Off failed"); + SecAsn1KC_Free(asn1kc); + return result; + } + + SecAsn1KC_Free(asn1kc); + return SEC_RESULT_SUCCESS; +} + +#ifndef SEC_COMMON_17 + +Sec_Result SecKey_GenerateWrappedKeyAsn1(SEC_BYTE* wrappedKey, SEC_SIZE wrappedKeyLen, Sec_KeyType wrappedKeyType, + SEC_OBJECTID wrappingKeyId, SEC_BYTE* wrappingIv, Sec_CipherAlgorithm wrappingAlgorithm, SEC_BYTE* output, + SEC_SIZE output_len, SEC_SIZE* written) { + Sec_Asn1KC* asn1kc = NULL; + Sec_Result result = SEC_RESULT_FAILURE; + + asn1kc = SecAsn1KC_Alloc(); + if (SecAsn1KC_AddAttrBuffer(asn1kc, SEC_ASN1KC_WRAPPEDKEY, wrappedKey, wrappedKeyLen) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrBuffer failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUlong(asn1kc, SEC_ASN1KC_WRAPPEDKEYTYPEID, wrappedKeyType) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUlong failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUint64(asn1kc, SEC_ASN1KC_WRAPPINGKEYID, wrappingKeyId) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUint64 failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (wrappingIv != NULL) { + if (SecAsn1KC_AddAttrBuffer(asn1kc, SEC_ASN1KC_WRAPPINGIV, wrappingIv, SEC_AES_BLOCK_SIZE) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrBuffer failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + } + + if (SecAsn1KC_AddAttrUlong(asn1kc, SEC_ASN1KC_WRAPPINGALGORITHMID, wrappingAlgorithm) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUlong failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_Encode(asn1kc, output, output_len, written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_Encode failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecKey_GenerateWrappedKeyAsn1Off(SEC_BYTE* payload, SEC_SIZE payloadLen, Sec_KeyType wrappedKeyType, + SEC_OBJECTID wrappingKeyId, SEC_BYTE* wrappingIv, Sec_CipherAlgorithm wrappingAlgorithm, SEC_BYTE* output, + SEC_SIZE output_len, SEC_SIZE* written, SEC_SIZE key_offset) { + Sec_Asn1KC* asn1kc = NULL; + Sec_Result result = SEC_RESULT_FAILURE; + + asn1kc = SecAsn1KC_Alloc(); + if (SecAsn1KC_AddAttrBuffer(asn1kc, SEC_ASN1KC_WRAPPEDKEY, payload, payloadLen) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrBuffer failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUlong(asn1kc, SEC_ASN1KC_WRAPPEDKEYTYPEID, wrappedKeyType) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUlong failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUint64(asn1kc, SEC_ASN1KC_WRAPPINGKEYID, wrappingKeyId) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUint64 failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (wrappingIv != NULL) { + if (SecAsn1KC_AddAttrBuffer(asn1kc, SEC_ASN1KC_WRAPPINGIV, wrappingIv, SEC_AES_BLOCK_SIZE) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrBuffer failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + } + + if ((key_offset + SecKey_GetKeyLenForKeyType(wrappedKeyType)) > payloadLen) { + SEC_LOG_ERROR("Illegal key_offset %ld", (long) key_offset); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUlong(asn1kc, SEC_ASN1KC_WRAPPEDKEYOFFSET, key_offset) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUlong failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUlong(asn1kc, SEC_ASN1KC_WRAPPINGALGORITHMID, wrappingAlgorithm) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUlong failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_Encode(asn1kc, output, output_len, written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_Encode failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecKey_GenerateWrappedKeyAsn1V3(SEC_BYTE* payload, SEC_SIZE payloadLen, Sec_KeyType wrappedKeyType, + SEC_BYTE* wrappingKey, SEC_SIZE wrappingKeyLen, SEC_BYTE* wrappingIv, + Sec_CipherAlgorithm wrappingAlgorithm, SEC_BYTE* output, SEC_SIZE output_len, + SEC_SIZE* written, SEC_SIZE key_offset) { + Sec_Asn1KC* asn1kc = NULL; + Sec_Result result = SEC_RESULT_FAILURE; + + asn1kc = SecAsn1KC_Alloc(); + if (SecAsn1KC_AddAttrBuffer(asn1kc, SEC_ASN1KC_WRAPPEDKEY, payload, payloadLen) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrBuffer failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUlong(asn1kc, SEC_ASN1KC_WRAPPEDKEYTYPEID, wrappedKeyType) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUlong failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrBuffer(asn1kc, SEC_ASN1KC_WRAPPINGKEY, wrappingKey, wrappingKeyLen) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrBuffer failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (wrappingIv != NULL) { + if (SecAsn1KC_AddAttrBuffer(asn1kc, SEC_ASN1KC_WRAPPINGIV, wrappingIv, SEC_AES_BLOCK_SIZE) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrBuffer failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + } + + if ((key_offset + SecKey_GetKeyLenForKeyType(wrappedKeyType)) > payloadLen) { + SEC_LOG_ERROR("Illegal key_offset %ld", (long) key_offset); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUlong(asn1kc, SEC_ASN1KC_WRAPPEDKEYOFFSET, key_offset) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUlong failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_AddAttrUlong(asn1kc, SEC_ASN1KC_WRAPPINGALGORITHMID, wrappingAlgorithm) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_AddAttrUlong failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (SecAsn1KC_Encode(asn1kc, output, output_len, written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecAsn1KC_Encode failed"); + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return result; + } + + if (asn1kc != NULL) { + SecAsn1KC_Free(asn1kc); + asn1kc = NULL; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecKey_ExtractWrappedKeyParamsAsn1Off(Sec_Asn1KC* kc, SEC_BYTE* payload, SEC_SIZE payloadLen, + SEC_SIZE* written, Sec_KeyType* wrappedKeyType, SEC_OBJECTID* wrappingId, SEC_BYTE* wrappingIv, + Sec_CipherAlgorithm* wrappingAlg, SEC_SIZE* key_offset) { + uint64_t ulong_val; + SEC_SIZE written_iv; + + if (kc == NULL) + return SEC_RESULT_FAILURE; + + if (SecAsn1KC_GetAttrBuffer(kc, SEC_ASN1KC_WRAPPEDKEY, payload, payloadLen, written) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPEDKEY failed"); + return SEC_RESULT_FAILURE; + } + + if (SecAsn1KC_GetAttrUlong(kc, SEC_ASN1KC_WRAPPEDKEYTYPEID, &ulong_val) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrUlong SEC_ASN1KC_WRAPPEDKEYTYPEID failed"); + return SEC_RESULT_FAILURE; + } + + *wrappedKeyType = (Sec_KeyType) ulong_val; + + if (SecAsn1KC_GetAttrUint64(kc, SEC_ASN1KC_WRAPPINGKEYID, wrappingId) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrUint64 SEC_ASN1KC_WRAPPINGKEYID failed"); + return SEC_RESULT_FAILURE; + } + + if (SecAsn1KC_HasAttr(kc, SEC_ASN1KC_WRAPPEDKEYOFFSET)) { + if (SecAsn1KC_GetAttrUlong(kc, SEC_ASN1KC_WRAPPEDKEYOFFSET, &ulong_val) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrUlong SEC_ASN1KC_WRAPPEDKEYOFFSET failed"); + return SEC_RESULT_FAILURE; + } + *key_offset = (SEC_SIZE) ulong_val; + } else { + *key_offset = (SEC_SIZE) 0; // default value + } + + if (SecAsn1KC_HasAttr(kc, SEC_ASN1KC_WRAPPINGIV) && + SecAsn1KC_GetAttrBuffer(kc, SEC_ASN1KC_WRAPPINGIV, wrappingIv, SEC_AES_BLOCK_SIZE, &written_iv) != + SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrBuffer SEC_ASN1KC_WRAPPINGIV failed"); + return SEC_RESULT_FAILURE; + } + + if (SecAsn1KC_GetAttrUlong(kc, SEC_ASN1KC_WRAPPINGALGORITHMID, &ulong_val) != SEC_RESULT_SUCCESS) { + SEC_TRACE(SEC_TRACE_UNWRAP, "SecAsn1KC_GetAttrUlong SEC_ASN1KC_WRAPPINGALGORITHMID failed"); + return SEC_RESULT_FAILURE; + } + + *wrappingAlg = (Sec_CipherAlgorithm) ulong_val; + return SEC_RESULT_SUCCESS; +} + +#endif + +void rights_set_allow_all(sa_rights* rights, Sec_KeyType key_type) { + memset(rights, 0, sizeof(sa_rights)); + + rights->not_before = 0; + rights->not_on_or_after = UINT64_MAX; + + rights->usage_flags = 0; + switch (key_type) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_UNWRAP); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_ENCRYPT); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_DECRYPT); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_SIGN); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_DERIVE); + break; + + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_SIGN); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_DERIVE); + break; + + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_RSA_3072: + case SEC_KEYTYPE_ECC_NISTP256: + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_UNWRAP); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_DECRYPT); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_SIGN); + break; + + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + case SEC_KEYTYPE_ECC_NISTP256_PUBLIC: + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_ENCRYPT); + break; + + default: + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_DERIVE); + break; + } + + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_KEY_EXCHANGE); + rights->usage_flags |= SA_USAGE_OUTPUT_PROTECTIONS_MASK; + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_CACHEABLE); + Sec_Memset(rights->allowed_tas, 0, sizeof(rights->allowed_tas)); + + const sa_uuid ALL_MATCH = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + memcpy(&rights->allowed_tas[7], &ALL_MATCH, sizeof(sa_uuid)); +} + +Sec_Result prepare_and_store_key_data(Sec_ProcessorHandle* processorHandle, Sec_StorageLoc location, + SEC_OBJECTID object_id, Sec_Key* key, Sec_KeyContainer key_container, void* key_buffer, SEC_SIZE key_length) { + Sec_KeyData* key_data = calloc(1, sizeof(Sec_KeyData)); + if (key_data == NULL) { + SEC_LOG_ERROR("calloc failed"); + return SEC_RESULT_FAILURE; + } + + Sec_Result result; + switch (key_container) { + case SEC_KEYCONTAINER_RAW_AES_128: + case SEC_KEYCONTAINER_RAW_AES_256: + case SEC_KEYCONTAINER_RAW_HMAC_128: + case SEC_KEYCONTAINER_RAW_HMAC_160: + case SEC_KEYCONTAINER_RAW_HMAC_256: + case SEC_KEYCONTAINER_DER_RSA_1024: + case SEC_KEYCONTAINER_DER_RSA_2048: + case SEC_KEYCONTAINER_DER_RSA_3072: + case SEC_KEYCONTAINER_RAW_ECC_PRIVONLY_NISTP256: + case SEC_KEYCONTAINER_SOC: + key_data->info.kc_type = SEC_KEYCONTAINER_EXPORTED; + result = export_key(key, NULL, key_data->key_container, SEC_KEYCONTAINER_MAX_LEN, &key_data->kc_len); + sa_key_release(key->handle); + break; + + case SEC_KEYCONTAINER_EXPORTED: + case SEC_KEYCONTAINER_JTYPE: + if (key_buffer != NULL && key_length != 0) { + key_data->info.kc_type = key_container; + memcpy(key_data->key_container, key_buffer, key_length); + key_data->kc_len = key_length; + sa_key_release(key->handle); + result = SEC_RESULT_SUCCESS; + } else { + result = SEC_RESULT_INVALID_PARAMETERS; + } + + break; + + case SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_3072_PUBLIC: + if (key_buffer != NULL && key_length != 0) { + key_data->info.kc_type = key_container; + memcpy(key_data->key_container, key_buffer, key_length); + key_data->kc_len = key_length; + RSA_free(key->rsa); + result = SEC_RESULT_SUCCESS; + } else { + result = SEC_RESULT_INVALID_PARAMETERS; + } + + break; + + case SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC: + if (key_buffer != NULL && key_length != 0) { + key_data->info.kc_type = key_container; + memcpy(key_data->key_container, key_buffer, key_length); + key_data->kc_len = key_length; + EC_KEY_free(key->ec_key); + result = SEC_RESULT_SUCCESS; + } else { + result = SEC_RESULT_INVALID_PARAMETERS; + } + + break; + + default: + result = SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + if (result == SEC_RESULT_SUCCESS) + result = store_key_data(processorHandle, location, object_id, key_data); + + SEC_FREE(key_data); + return result; +} + +const Sec_Key* get_key(Sec_KeyHandle* keyHandle) { + return &keyHandle->key; +} + +static Sec_KeyType get_key_type(sa_header* key_header) { + Sec_KeyType key_type; + switch ((*key_header).type) { + case SA_KEY_TYPE_SYMMETRIC: + if ((SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_SIGN) || + SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_DERIVE)) && + !SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_ENCRYPT) && + !SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_DECRYPT) && + !SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_UNWRAP)) { + if ((*key_header).size == 16) + key_type = SEC_KEYTYPE_HMAC_128; + else if ((*key_header).size == 20) + key_type = SEC_KEYTYPE_HMAC_160; + else if ((*key_header).size == 32) + key_type = SEC_KEYTYPE_HMAC_256; + else + key_type = SEC_KEYTYPE_NUM; + } else if (SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_DERIVE) || + SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_ENCRYPT) || + SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_DECRYPT) || + SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_SIGN) || + SA_USAGE_BIT_TEST((*key_header).rights.usage_flags, SA_USAGE_FLAG_UNWRAP)) { + if ((*key_header).size == 16) + key_type = SEC_KEYTYPE_AES_128; + else if ((*key_header).size == 20) + key_type = SEC_KEYTYPE_HMAC_160; + else if ((*key_header).size == 32) + key_type = SEC_KEYTYPE_AES_256; + else + key_type = SEC_KEYTYPE_NUM; + } else { + key_type = SEC_KEYTYPE_NUM; + } + + break; + + case SA_KEY_TYPE_EC: + key_type = SEC_KEYTYPE_ECC_NISTP256; + break; + + case SA_KEY_TYPE_RSA: + if ((*key_header).size == 128) + key_type = SEC_KEYTYPE_RSA_1024; + else if ((*key_header).size == 256) + key_type = SEC_KEYTYPE_RSA_2048; + else if ((*key_header).size == 384) + key_type = SEC_KEYTYPE_RSA_3072; + else + key_type = SEC_KEYTYPE_NUM; + break; + + case SA_KEY_TYPE_DH: + default: + key_type = SEC_KEYTYPE_NUM; + break; + } + + return key_type; +} + +static void find_ram_key_data(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, Sec_RAMKeyData** data, + Sec_RAMKeyData** parent) { + *parent = NULL; + *data = processorHandle->ram_keys; + + while ((*data) != NULL) { + if (object_id == (*data)->object_id) + return; + + *parent = (*data); + *data = (*data)->next; + } + + *parent = NULL; +} + +static Sec_Result retrieve_key_data(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_StorageLoc* location, Sec_KeyData* keyData) { + char file_name_key[SEC_MAX_FILE_PATH_LEN]; + char file_name_info[SEC_MAX_FILE_PATH_LEN]; + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + Sec_RAMKeyData* ram_key = NULL; + Sec_RAMKeyData* ram_key_parent = NULL; + SEC_SIZE data_read; + + CHECK_PROCHANDLE(processorHandle) + + /* check in RAM */ + find_ram_key_data(processorHandle, object_id, &ram_key, &ram_key_parent); + if (ram_key != NULL) { + memcpy(keyData, &(ram_key->key_data), sizeof(Sec_KeyData)); + *location = SEC_STORAGELOC_RAM; + return SEC_RESULT_SUCCESS; + } + + /* check in app_dir */ + char* sec_dirs[] = {processorHandle->app_dir, processorHandle->global_dir}; + for (int i = 0; i < 2; i++) { + if (sec_dirs[i] != NULL) { + snprintf(file_name_key, sizeof(file_name_key), SEC_KEY_FILENAME_PATTERN, sec_dirs[i], + object_id); + snprintf(file_name_info, sizeof(file_name_info), SEC_KEYINFO_FILENAME_PATTERN, sec_dirs[i], + object_id); + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + sec_dirs[i], object_id); + if (SecUtils_FileExists(file_name_key) && SecUtils_FileExists(file_name_info)) { + if (SecUtils_ReadFile(file_name_key, keyData->key_container, sizeof(keyData->key_container), + &keyData->kc_len) != SEC_RESULT_SUCCESS || + SecUtils_ReadFile(file_name_info, &keyData->info, sizeof(keyData->info), &data_read) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not read one of the key files"); + return SEC_RESULT_FAILURE; + } + + if (data_read != sizeof(keyData->info)) { + SEC_LOG_ERROR("File is not of the correct size"); + return SEC_RESULT_FAILURE; + } + + if (SecUtils_FileExists(file_name_verification)) { + if (verify_verification_file(processorHandle, file_name_verification, keyData->key_container, + keyData->kc_len, (SEC_BYTE*) &keyData->info, sizeof(keyData->info)) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Key verification failed"); + return SEC_RESULT_FAILURE; + } + } else { + // If the verification file doesn't exist, the key file was created by an old SecApi. If the key + // container type is Exported, the old SecApi uses a different export format and the key file cannot + // be read. So fail the key retrieval. + if (keyData->info.kc_type == SEC_KEYCONTAINER_EXPORTED) { + SEC_LOG_ERROR("Old Exported key container format"); + return SEC_RESULT_FAILURE; + } + + if (write_verification_file(processorHandle, file_name_verification, keyData->key_container, + keyData->kc_len, (SEC_BYTE*) &keyData->info, sizeof(keyData->info)) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not write verification file"); + } + } + *location = SEC_STORAGELOC_FILE; + return SEC_RESULT_SUCCESS; + } + } + } + + return SEC_RESULT_NO_SUCH_ITEM; +} + +static Sec_Result store_key_data(Sec_ProcessorHandle* processorHandle, Sec_StorageLoc location, SEC_OBJECTID object_id, + Sec_KeyData* key_data) { + Sec_RAMKeyData* ram_key; + + if (location == SEC_STORAGELOC_RAM || location == SEC_STORAGELOC_RAM_SOFT_WRAPPED) { + SecKey_Delete(processorHandle, object_id); + + ram_key = calloc(1, sizeof(Sec_RAMKeyData)); + if (ram_key == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + ram_key->object_id = object_id; + memcpy(&(ram_key->key_data), key_data, sizeof(Sec_KeyData)); + ram_key->next = processorHandle->ram_keys; + processorHandle->ram_keys = ram_key; + return SEC_RESULT_SUCCESS; + } + + if (location == SEC_STORAGELOC_FILE || location == SEC_STORAGELOC_FILE_SOFT_WRAPPED) { + if (processorHandle->app_dir == NULL) { + SEC_LOG_ERROR("Cannot write file because app_dir is NULL"); + return SEC_RESULT_FAILURE; + } + + SecKey_Delete(processorHandle, object_id); + + char file_name_key[SEC_MAX_FILE_PATH_LEN]; + char file_name_info[SEC_MAX_FILE_PATH_LEN]; + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_key, sizeof(file_name_key), SEC_KEY_FILENAME_PATTERN, processorHandle->app_dir, + object_id); + snprintf(file_name_info, sizeof(file_name_info), SEC_KEYINFO_FILENAME_PATTERN, + processorHandle->app_dir, object_id); + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + processorHandle->app_dir, object_id); + + if (SecUtils_WriteFile(file_name_key, key_data->key_container, key_data->kc_len) != + SEC_RESULT_SUCCESS || + SecUtils_WriteFile(file_name_info, &key_data->info, sizeof(key_data->info)) != + SEC_RESULT_SUCCESS || + write_verification_file(processorHandle, file_name_verification, + key_data->key_container, key_data->kc_len, + (SEC_BYTE*) &key_data->info, sizeof(key_data->info)) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not write info file"); + SecUtils_RmFile(file_name_key); + SecUtils_RmFile(file_name_info); + SecUtils_RmFile(file_name_verification); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; + } + + SEC_LOG_ERROR("Unimplemented location type"); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +static Sec_Result process_key_container(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID object_id, + Sec_KeyContainer in_key_container, void* data, SEC_SIZE data_length, Sec_Key* key, + Sec_KeyContainer* out_key_container, void* key_buffer, SEC_SIZE* key_length) { + Sec_Result result; + unsigned char* p_data; + SEC_SIZE key_size; + Sec_KeyType key_type; + sa_rights rights; + sa_key_format key_format; + void* parameters; + sa_import_parameters_symmetric symmetric_parameters; + sa_import_parameters_rsa_private_key_info rsa_parameters; + sa_import_parameters_ec_private_bytes ec_parameters; + sa_import_parameters_typej typej_parameters; + sa_import_parameters_soc_legacy parameters_soc_legacy; + Sec_KeyHandle* cipherKeyHandle = NULL; + Sec_KeyHandle* hmacKeyHandle = NULL; + sa_status status; + + if (in_key_container == SEC_KEYCONTAINER_STORE) { + result = process_store_key_container(processorHandle, data, data_length, key_buffer, key_length, + out_key_container); + if (result != SEC_RESULT_SUCCESS) + return result; + + p_data = key_buffer; + } else { + *out_key_container = in_key_container; + p_data = data; + *key_length = data_length; + } + + if (*out_key_container == SEC_KEYCONTAINER_ASN1) { + result = process_asn1_key_container(processorHandle, p_data, *key_length, key_buffer, key_length, + out_key_container); + if (result != SEC_RESULT_SUCCESS) + return result; + + p_data = key_buffer; + } + + switch (*out_key_container) { + case SEC_KEYCONTAINER_RAW_AES_128: + case SEC_KEYCONTAINER_RAW_AES_256: + case SEC_KEYCONTAINER_RAW_HMAC_128: + case SEC_KEYCONTAINER_RAW_HMAC_160: + case SEC_KEYCONTAINER_RAW_HMAC_256: + key_type = SecKey_GetKeyTypeForClearKeyContainer(*out_key_container); + key_size = SecKey_GetKeyLenForKeyType(key_type); + if (*key_length != key_size) { + SEC_LOG_ERROR("Invalid key container length"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + memmove(key_buffer, p_data, *key_length); + key_format = SA_KEY_FORMAT_SYMMETRIC_BYTES; + rights_set_allow_all(&rights, SecKey_GetKeyTypeForClearKeyContainer(*out_key_container)); + symmetric_parameters.rights = &rights; + parameters = &symmetric_parameters; + break; + + case SEC_KEYCONTAINER_DER_RSA_1024: + case SEC_KEYCONTAINER_DER_RSA_2048: + case SEC_KEYCONTAINER_DER_RSA_3072: + case SEC_KEYCONTAINER_RAW_RSA_1024: + case SEC_KEYCONTAINER_RAW_RSA_2048: + case SEC_KEYCONTAINER_RAW_RSA_3072: + case SEC_KEYCONTAINER_PEM_RSA_1024: + case SEC_KEYCONTAINER_PEM_RSA_2048: + case SEC_KEYCONTAINER_PEM_RSA_3072: + result = process_rsa_key_container(*out_key_container, p_data, *key_length, key_buffer, key_length, + out_key_container); + if (result != SEC_RESULT_SUCCESS) + return result; + + key_format = SA_KEY_FORMAT_RSA_PRIVATE_KEY_INFO; + rights_set_allow_all(&rights, SecKey_GetKeyTypeForClearKeyContainer(*out_key_container)); + rsa_parameters.rights = &rights; + parameters = &rsa_parameters; + break; + + case SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_3072_PUBLIC: + case SEC_KEYCONTAINER_RAW_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_RAW_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_RAW_RSA_3072_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_3072_PUBLIC: + result = process_rsa_public_key_container(*out_key_container, p_data, *key_length, &key->rsa, + key_buffer, key_length, out_key_container); + if (result != SEC_RESULT_SUCCESS) + return result; + + // Public key so skip key import. + return SEC_RESULT_SUCCESS; + + case SEC_KEYCONTAINER_DER_ECC_NISTP256: + case SEC_KEYCONTAINER_RAW_ECC_NISTP256: + case SEC_KEYCONTAINER_RAW_ECC_PRIVONLY_NISTP256: + case SEC_KEYCONTAINER_PEM_ECC_NISTP256: + result = process_ec_key_container(*out_key_container, p_data, *key_length, key_buffer, key_length, + out_key_container); + if (result != SEC_RESULT_SUCCESS) + return result; + + key_format = SA_KEY_FORMAT_EC_PRIVATE_BYTES; + rights_set_allow_all(&rights, SecKey_GetKeyTypeForClearKeyContainer(*out_key_container)); + ec_parameters.rights = &rights; + ec_parameters.curve = SA_ELLIPTIC_CURVE_NIST_P256; + parameters = &ec_parameters; + break; + + case SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC: + case SEC_KEYCONTAINER_RAW_ECC_NISTP256_PUBLIC: + case SEC_KEYCONTAINER_PEM_ECC_NISTP256_PUBLIC: + result = process_ec_public_key_container(*out_key_container, p_data, *key_length, &key->ec_key, + key_buffer, key_length, out_key_container); + if (result != SEC_RESULT_SUCCESS) + return result; + + // Public key so skip key import. + return SEC_RESULT_SUCCESS; + + case SEC_KEYCONTAINER_SOC: + case SEC_KEYCONTAINER_SOC_INTERNAL_0: + case SEC_KEYCONTAINER_SOC_INTERNAL_1: + case SEC_KEYCONTAINER_SOC_INTERNAL_2: + case SEC_KEYCONTAINER_SOC_INTERNAL_3: + case SEC_KEYCONTAINER_SOC_INTERNAL_4: + case SEC_KEYCONTAINER_SOC_INTERNAL_5: + case SEC_KEYCONTAINER_SOC_INTERNAL_6: + case SEC_KEYCONTAINER_SOC_INTERNAL_7: + case SEC_KEYCONTAINER_SOC_INTERNAL_8: + case SEC_KEYCONTAINER_SOC_INTERNAL_9: + case SEC_KEYCONTAINER_SOC_INTERNAL_10: + case SEC_KEYCONTAINER_SOC_INTERNAL_11: + case SEC_KEYCONTAINER_SOC_INTERNAL_12: + case SEC_KEYCONTAINER_SOC_INTERNAL_13: + case SEC_KEYCONTAINER_SOC_INTERNAL_14: + case SEC_KEYCONTAINER_SOC_INTERNAL_15: + *out_key_container = SEC_KEYCONTAINER_SOC; + memmove(key_buffer, p_data, *key_length); + key_format = SA_KEY_FORMAT_SOC; + if (is_jwt_key_container(key_buffer, *key_length)) { + parameters = NULL; + } else { + size_t length = sizeof(sa_import_parameters_soc_legacy); + rights_set_allow_all(&rights, SEC_KEYTYPE_AES_128); + parameters_soc_legacy.length[0] = length >> 8 & 0xff; + parameters_soc_legacy.length[1] = length & 0xff; + parameters_soc_legacy.version = VERSION_2_KEY_CONTAINER; + parameters_soc_legacy.default_rights = rights; + parameters_soc_legacy.object_id = object_id; + parameters = ¶meters_soc_legacy; + } + + break; + + case SEC_KEYCONTAINER_EXPORTED: + memmove(key_buffer, p_data, *key_length); + key_format = SA_KEY_FORMAT_EXPORTED; + parameters = NULL; + break; + + case SEC_KEYCONTAINER_JTYPE: + memmove(key_buffer, p_data, *key_length); + key_format = SA_KEY_FORMAT_TYPEJ; + + result = SecKey_GetInstance(processorHandle, SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY, &cipherKeyHandle); + if (result != SEC_RESULT_SUCCESS) + return result; + + result = SecKey_GetInstance(processorHandle, SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY, &hmacKeyHandle); + if (result != SEC_RESULT_SUCCESS) { + if (cipherKeyHandle != NULL) + SecKey_Release(cipherKeyHandle); + + return result; + } + + typej_parameters.kcipher = cipherKeyHandle->key.handle; + typej_parameters.khmac = hmacKeyHandle->key.handle; + parameters = &typej_parameters; + break; + + default: + return SEC_RESULT_FAILURE; + } + + // Validate the key and import it. + status = sa_key_import(&key->handle, key_format, key_buffer, *key_length, parameters); + + if (cipherKeyHandle != NULL) + SecKey_Release(cipherKeyHandle); + + if (hmacKeyHandle != NULL) + SecKey_Release(hmacKeyHandle); + + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +static bool is_jwt_key_container(SEC_BYTE* key_buffer, SEC_SIZE key_length) { + + SEC_BYTE* in_string = key_buffer; + SEC_BYTE* in_string_end = in_string + key_length; + + SEC_BYTE* header_b64 = in_string; + SEC_BYTE* header_b64_end = memchr(header_b64, '.', in_string_end - header_b64); + if (header_b64_end == NULL) + return false; + + SEC_SIZE header_b64_length = header_b64_end - header_b64; + SEC_BYTE* payload_b64 = header_b64_end + 1; + if (payload_b64 >= in_string_end) + return false; + + SEC_BYTE* payload_b64_end = memchr(payload_b64, '.', in_string_end - payload_b64); + if (payload_b64_end == NULL) + return false; + + SEC_SIZE payload_b64_length = payload_b64_end - payload_b64; + SEC_BYTE* mac_b64 = payload_b64_end + 1; + if (mac_b64 >= in_string_end) + return false; + + SEC_BYTE* mac_b64_end = in_string_end; + SEC_SIZE mac_b64_length = mac_b64_end - mac_b64; + SEC_SIZE header_length = 3 * header_b64_length / 4; + SEC_SIZE length; + SEC_BYTE* header = malloc(header_length); + Sec_Result result = SecUtils_Base64Decode(header_b64, header_b64_length, header, header_length, &length); + free(header); + if (result != SEC_RESULT_SUCCESS) + return false; + + SEC_SIZE payload_length = 3 * payload_b64_length / 4; + SEC_BYTE* payload = malloc(payload_length); + result = SecUtils_Base64Decode(payload_b64, payload_b64_length, payload, payload_length, &length); + free(payload); + if (result != SEC_RESULT_SUCCESS) + return false; + + SEC_SIZE mac_length = 3 * mac_b64_length / 4; + SEC_BYTE* mac = malloc(mac_length); + result = SecUtils_Base64Decode(mac_b64, mac_b64_length, mac, mac_length, &length); + free(mac); + if (result != SEC_RESULT_SUCCESS) + return false; + + return true; +} + +static Sec_Result process_rsa_key_container(Sec_KeyContainer in_key_container, SEC_BYTE* data, + SEC_SIZE data_length, unsigned char* key_buffer, SEC_SIZE* key_length, Sec_KeyContainer* out_key_container) { + RSA* rsa = NULL; + switch (in_key_container) { + case SEC_KEYCONTAINER_DER_RSA_1024: + case SEC_KEYCONTAINER_DER_RSA_2048: + case SEC_KEYCONTAINER_DER_RSA_3072: { + const unsigned char* p_data = data; + rsa = d2i_RSAPrivateKey(NULL, &p_data, data_length); + if (rsa == NULL) { + SEC_LOG_ERROR("d2i_RSAPrivateKey failed"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + break; + } + case SEC_KEYCONTAINER_RAW_RSA_1024: + case SEC_KEYCONTAINER_RAW_RSA_2048: + case SEC_KEYCONTAINER_RAW_RSA_3072: { + if (data_length != sizeof(Sec_RSARawPrivateKey)) { + SEC_LOG_ERROR("Invalid key container length"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + // Validate the key and convert to RSA. + Sec_RSARawPrivateKey* rawPrivateKey = (Sec_RSARawPrivateKey*) data; + rsa = RSA_new(); + if (rsa == NULL) { + SEC_LOG_ERROR("RSA_new failed"); + return SEC_RESULT_INVALID_PARAMETERS; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + rsa->n = BN_bin2bn(rawPrivateKey->n, (int) Sec_BEBytesToUint32(rawPrivateKey->modulus_len_be), NULL); + rsa->e = BN_bin2bn(rawPrivateKey->e, 4, NULL); + rsa->d = BN_bin2bn(rawPrivateKey->d, (int) Sec_BEBytesToUint32(rawPrivateKey->modulus_len_be), NULL); +#else + RSA_set0_key(rsa, + BN_bin2bn(rawPrivateKey->n, (int) Sec_BEBytesToUint32(rawPrivateKey->modulus_len_be), NULL), + BN_bin2bn(rawPrivateKey->e, 4, NULL), + BN_bin2bn(rawPrivateKey->d, (int) Sec_BEBytesToUint32(rawPrivateKey->modulus_len_be), NULL)); +#endif + break; + } + case SEC_KEYCONTAINER_PEM_RSA_1024: + case SEC_KEYCONTAINER_PEM_RSA_2048: + case SEC_KEYCONTAINER_PEM_RSA_3072: { + // Validate the key and convert to RSA. + BIO* bio = BIO_new_mem_buf(data, (int) data_length); + rsa = PEM_read_bio_RSAPrivateKey(bio, &rsa, disable_passphrase_prompt, NULL); + Sec_KeyType key_type = SecKey_GetKeyTypeForClearKeyContainer(in_key_container); + if ((rsa == NULL) || ((SEC_SIZE) RSA_size(rsa) != SecKey_GetKeyLenForKeyType(key_type))) { + SEC_RSA_FREE(rsa); + SEC_LOG_ERROR("Invalid RSA key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + break; + } + default: + return SEC_RESULT_FAILURE; + } + + Sec_KeyType key_type = SecKey_GetKeyTypeForClearKeyContainer(in_key_container); + if ((rsa == NULL) || ((SEC_SIZE) RSA_size(rsa) != SecKey_GetKeyLenForKeyType(key_type))) { + SEC_RSA_FREE(rsa); + SEC_LOG_ERROR("Invalid RSA key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + *out_key_container = convert_key_container(in_key_container); + unsigned char* p_data = key_buffer; + *key_length = i2d_RSAPrivateKey(rsa, &p_data); + SEC_RSA_FREE(rsa); + if (*key_length <= 0) { + SEC_LOG_ERROR("Invalid RSA key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result process_rsa_public_key_container(Sec_KeyContainer in_key_container, SEC_BYTE* data, + SEC_SIZE data_length, RSA** rsa, unsigned char* key_buffer, SEC_SIZE* key_length, + Sec_KeyContainer* out_key_container) { + switch (in_key_container) { + case SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_DER_RSA_3072_PUBLIC: { + const unsigned char* p_data = data; + *rsa = d2i_RSA_PUBKEY(NULL, &p_data, data_length); + if (*rsa == NULL) + *rsa = d2i_RSAPublicKey(NULL, &p_data, data_length); + + if (*rsa == NULL) { + SEC_LOG_ERROR("d2i_RSAPublicKey failed"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + break; + } + case SEC_KEYCONTAINER_RAW_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_RAW_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_RAW_RSA_3072_PUBLIC: { + if (data_length < sizeof(Sec_RSARawPublicKey)) { + SEC_LOG_ERROR("Invalid key container length"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + // Validate the key and convert to RSA. + Sec_RSARawPublicKey* rawPublicKey = (Sec_RSARawPublicKey*) data; + *rsa = RSA_new(); + if (rsa == NULL) { + SEC_LOG_ERROR("RSA_new failed"); + return SEC_RESULT_FAILURE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + (*rsa)->n = BN_bin2bn(rawPublicKey->n, (int) Sec_BEBytesToUint32(rawPublicKey->modulus_len_be), NULL); + (*rsa)->e = BN_bin2bn(rawPublicKey->e, 4, NULL); +#else + RSA_set0_key(*rsa, + BN_bin2bn(rawPublicKey->n, (int) Sec_BEBytesToUint32(rawPublicKey->modulus_len_be), NULL), + BN_bin2bn(rawPublicKey->e, 4, NULL), + NULL); +#endif + break; + } + case SEC_KEYCONTAINER_PEM_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_3072_PUBLIC: { + BIO* bio = BIO_new_mem_buf(data, (int) data_length); + EVP_PKEY* evp_pkey = PEM_read_bio_PUBKEY(bio, &evp_pkey, disable_passphrase_prompt, NULL); + if (evp_pkey == NULL) { + SEC_LOG_ERROR("PEM_read_bio_PUBKEY failed"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + *rsa = EVP_PKEY_get1_RSA(evp_pkey); + EVP_PKEY_free(evp_pkey); + if (*rsa == NULL) { + SEC_LOG_ERROR("EVP_PKEY_get0_RSA failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + default: + return SEC_RESULT_FAILURE; + } + + Sec_KeyType key_type = SecKey_GetKeyTypeForClearKeyContainer(in_key_container); + if ((SEC_SIZE) RSA_size(*rsa) != SecKey_GetKeyLenForKeyType(key_type)) { + SEC_RSA_FREE(*rsa); + *rsa = NULL; + SEC_LOG_ERROR("Invalid RSA key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + *out_key_container = convert_key_container(in_key_container); + unsigned char* p_data = key_buffer; + *key_length = i2d_RSAPublicKey(*rsa, &p_data); + if (*key_length <= 0) { + SEC_LOG_ERROR("Invalid RSA key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result process_ec_key_container(Sec_KeyContainer in_key_container, SEC_BYTE* data, + SEC_SIZE data_length, unsigned char* key_buffer, SEC_SIZE* key_length, Sec_KeyContainer* out_key_container) { + switch (in_key_container) { + case SEC_KEYCONTAINER_DER_ECC_NISTP256: { + const unsigned char* p_der = data; + EC_KEY* ec_key = d2i_ECPrivateKey(NULL, &p_der, data_length); + if (ec_key == NULL) { + SEC_LOG_ERROR("Invalid ECC key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + *key_length = BN_bn2bin(EC_KEY_get0_private_key(ec_key), key_buffer); + SEC_ECC_FREE(ec_key); + break; + } + case SEC_KEYCONTAINER_RAW_ECC_NISTP256: { + if (data_length != sizeof(Sec_ECCRawPrivateKey)) { + SEC_LOG_ERROR("Invalid key container length"); + SEC_LOG_ERROR("Data_len != sizeof(Sec_ECCRawPrivateKey) data_length: %d, expected: %d", data_length, + sizeof(Sec_ECCRawPrivateKey)); + return SEC_RESULT_INVALID_PARAMETERS; + } + + Sec_ECCRawPrivateKey* rawPrivateKey = (Sec_ECCRawPrivateKey*) data; + if (rawPrivateKey->type != SEC_KEYTYPE_ECC_NISTP256) { + SEC_LOG_ERROR("Invalid ECC key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + memcpy(key_buffer, rawPrivateKey->prv, SEC_ECC_NISTP256_KEY_LEN); + *key_length = SEC_ECC_NISTP256_KEY_LEN; + break; + } + case SEC_KEYCONTAINER_RAW_ECC_PRIVONLY_NISTP256: { + if (data_length != sizeof(Sec_ECCRawOnlyPrivateKey)) { + SEC_LOG_ERROR("Invalid key container length"); + SEC_LOG_ERROR("Data_len != sizeof(Sec_ECCRawOnlyPrivateKey) data_length: %d, expected: %d", data_length, + sizeof(Sec_ECCRawOnlyPrivateKey)); + return SEC_RESULT_INVALID_PARAMETERS; + } + + memcpy(key_buffer, ((Sec_ECCRawOnlyPrivateKey*) data)->prv, SEC_ECC_NISTP256_KEY_LEN); + *key_length = SEC_ECC_NISTP256_KEY_LEN; + break; + } + case SEC_KEYCONTAINER_PEM_ECC_NISTP256: { + BIO* bio = BIO_new_mem_buf(data, (int) data_length); + EC_KEY* ec_key = PEM_read_bio_ECPrivateKey(bio, &ec_key, disable_passphrase_prompt, NULL); + SEC_BIO_FREE(bio); + if (ec_key == NULL) { + SEC_LOG_ERROR("Invalid ECC key container"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + *key_length = BN_bn2bin(EC_KEY_get0_private_key(ec_key), key_buffer); + SEC_ECC_FREE(ec_key); + break; + } + default: + return SEC_RESULT_FAILURE; + } + + *out_key_container = convert_key_container(in_key_container); + return SEC_RESULT_SUCCESS; +} + +static Sec_Result process_ec_public_key_container(Sec_KeyContainer in_key_container, SEC_BYTE* data, + SEC_SIZE data_length, EC_KEY** ec_key, unsigned char* key_buffer, SEC_SIZE* key_length, + Sec_KeyContainer* out_key_container) { + switch (in_key_container) { + case SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC: { + const unsigned char* p_data = data; + *ec_key = d2i_EC_PUBKEY(NULL, &p_data, data_length); + if (*ec_key == NULL) { + SEC_LOG_ERROR("d2i_EC_PUBKEY failed"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + break; + } + case SEC_KEYCONTAINER_RAW_ECC_NISTP256_PUBLIC: { + Sec_ECCRawPublicKey* binary = (Sec_ECCRawPublicKey*) data; + BN_CTX* bn_ctx = BN_CTX_new(); + + if (*key_length < sizeof(Sec_ECCRawPublicKey)) { + SEC_LOG_ERROR("Invalid key container length"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (binary->type != SEC_KEYTYPE_ECC_NISTP256_PUBLIC && binary->type != SEC_KEYTYPE_ECC_NISTP256) + return SEC_RESULT_INVALID_PARAMETERS; + + //create ec_key structure with NIST p256 curve; + *ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + const EC_GROUP* group = EC_KEY_get0_group(*ec_key); + EC_POINT* ec_point = EC_POINT_new(group); + BN_CTX_start(bn_ctx); + BIGNUM* xp; + BIGNUM* yp; + + if (((xp = BN_CTX_get(bn_ctx)) == NULL) || ((yp = BN_CTX_get(bn_ctx)) == NULL)) + return SEC_RESULT_INVALID_PARAMETERS; + + EC_POINT_set_affine_coordinates_GFp(group, ec_point, + BN_bin2bn(binary->x, (int) Sec_BEBytesToUint32(binary->key_len), xp), + BN_bin2bn(binary->y, (int) Sec_BEBytesToUint32(binary->key_len), yp), bn_ctx); + EC_KEY_set_public_key(*ec_key, ec_point); + + EC_POINT_free(ec_point); + BN_CTX_end(bn_ctx); + BN_CTX_free(bn_ctx); + return SEC_RESULT_SUCCESS; + } + case SEC_KEYCONTAINER_PEM_ECC_NISTP256_PUBLIC: { + BIO* bio = BIO_new_mem_buf(data, (int) data_length); + EVP_PKEY* evp_pkey = NULL; + evp_pkey = PEM_read_bio_PUBKEY(bio, &evp_pkey, disable_passphrase_prompt, NULL); + if (evp_pkey == NULL) { + SEC_LOG_ERROR("PEM_read_bio_PUBKEY failed"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + *ec_key = EVP_PKEY_get1_EC_KEY(evp_pkey); + EVP_PKEY_free(evp_pkey); + if (*ec_key == NULL) { + SEC_LOG_ERROR("EVP_PKEY_get0_EC_KEY failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + default: + return SEC_RESULT_FAILURE; + } + + *out_key_container = convert_key_container(in_key_container); + *key_length = i2d_EC_PUBKEY(*ec_key, &key_buffer); + if (*key_length < 0) + return SEC_RESULT_INVALID_PARAMETERS; + + return SEC_RESULT_SUCCESS; +} + +static Sec_KeyContainer convert_key_container(Sec_KeyContainer key_container) { + switch (key_container) { + case SEC_KEYCONTAINER_RAW_RSA_1024: + case SEC_KEYCONTAINER_PEM_RSA_1024: + return SEC_KEYCONTAINER_DER_RSA_1024; + + case SEC_KEYCONTAINER_RAW_RSA_2048: + case SEC_KEYCONTAINER_PEM_RSA_2048: + return SEC_KEYCONTAINER_DER_RSA_2048; + + case SEC_KEYCONTAINER_RAW_RSA_3072: + case SEC_KEYCONTAINER_PEM_RSA_3072: + return SEC_KEYCONTAINER_DER_RSA_3072; + + case SEC_KEYCONTAINER_RAW_RSA_1024_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_1024_PUBLIC: + return SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC; + + case SEC_KEYCONTAINER_RAW_RSA_2048_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_2048_PUBLIC: + return SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC; + + case SEC_KEYCONTAINER_RAW_RSA_3072_PUBLIC: + case SEC_KEYCONTAINER_PEM_RSA_3072_PUBLIC: + return SEC_KEYCONTAINER_DER_RSA_3072_PUBLIC; + + case SEC_KEYCONTAINER_DER_ECC_NISTP256: + case SEC_KEYCONTAINER_RAW_ECC_NISTP256: + case SEC_KEYCONTAINER_PEM_ECC_NISTP256: + case SEC_KEYCONTAINER_RAW_ECC_PRIVONLY_NISTP256: + return SEC_KEYCONTAINER_RAW_ECC_PRIVONLY_NISTP256; + + case SEC_KEYCONTAINER_RAW_ECC_NISTP256_PUBLIC: + case SEC_KEYCONTAINER_PEM_ECC_NISTP256_PUBLIC: + return SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC; + + default: + return key_container; + } +} + +static Sec_Result process_asn1_key_container(Sec_ProcessorHandle* processorHandle, const void* data, + SEC_SIZE data_length, SEC_BYTE* key_buffer, SEC_SIZE* key_length, Sec_KeyContainer* key_container) { + SEC_SIZE tempkc_length = SEC_KEYCONTAINER_MAX_LEN; + uint8_t* tempkc = malloc(SEC_KEYCONTAINER_MAX_LEN); + if (tempkc == NULL) { + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType wrapped_key_type; + SEC_OBJECTID wrapping_id; + SEC_BYTE wrapping_iv[SEC_AES_BLOCK_SIZE]; + Sec_CipherAlgorithm wrapping_alg; + SEC_SIZE wrapped_key_offset; + SEC_SIZE wrapping_key_length = SEC_KEYCONTAINER_MAX_LEN; + uint8_t* wrapping_key = malloc(SEC_KEYCONTAINER_MAX_LEN); + if (wrapping_key == NULL) { + SEC_FREE(tempkc); + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + Sec_Asn1KC* asn1kc = SecAsn1KC_Decode(data, data_length); + if (asn1kc == NULL) { + SEC_FREE(tempkc); + SEC_FREE(wrapping_key); + SEC_LOG_ERROR("SecAsn1KC_Decode failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_ExtractWrappedKeyParamsAsn1V3(asn1kc, tempkc, SEC_KEYCONTAINER_MAX_LEN, &tempkc_length, + &wrapped_key_type, &wrapping_id, wrapping_iv, &wrapping_alg, &wrapped_key_offset, wrapping_key, + SEC_KEYCONTAINER_MAX_LEN, &wrapping_key_length) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractWrappedKeyParamsAsn1V3 failed"); + SEC_FREE(tempkc); + SEC_FREE(wrapping_key); + SecAsn1KC_Free(asn1kc); + return SEC_RESULT_FAILURE; + } + + SecAsn1KC_Free(asn1kc); + + //V3 + if (wrapping_key_length > 0) { + //get free id + wrapping_id = SecKey_ObtainFreeObjectId(processorHandle, SEC_OBJECTID_RESERVED_BASE, SEC_OBJECTID_RESERVED_TOP); + if (SEC_OBJECTID_INVALID == wrapping_id) { + SEC_LOG_ERROR("SecKey_ObtainFreeObjectId failed"); + SEC_FREE(tempkc); + SEC_FREE(wrapping_key); + return SEC_RESULT_FAILURE; + } + + // provision wrapping key--we don't know whether it is a SEC_KEYCONTAINER_ASN1 or a SEC_KEYCONTAINER_SOC + // so try the ASN1 container first. If it fails, then try to SOC container. + if (SecKey_Provision(processorHandle, wrapping_id, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_ASN1, wrapping_key, + wrapping_key_length) != SEC_RESULT_SUCCESS) { + if (SecKey_Provision(processorHandle, wrapping_id, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_SOC, wrapping_key, + wrapping_key_length) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + SEC_FREE(tempkc); + SEC_FREE(wrapping_key); + return SEC_RESULT_FAILURE; + } + } + } + + //unwrap + sa_key unwrapped_key; + Sec_Result result = unwrap_key(processorHandle, wrapping_alg, wrapped_key_type, wrapped_key_offset, wrapping_id, + wrapping_iv, tempkc, tempkc_length, key_buffer, key_length); + *key_container = SEC_KEYCONTAINER_EXPORTED; + if (wrapping_key_length > 0) + SecKey_Delete(processorHandle, wrapping_id); + + SEC_FREE(tempkc); + SEC_FREE(wrapping_key); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Unwrap_key failed"); + return result; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result process_store_key_container(Sec_ProcessorHandle* processorHandle, void* data, + SEC_SIZE data_length, SEC_BYTE* key_buffer, SEC_SIZE* key_length, Sec_KeyContainer* key_container) { + if (SecStore_GetStoreLen(data) != data_length) { + SEC_LOG_ERROR("Secure store length does not match the expected one"); + return SEC_RESULT_FAILURE; + } + + /* validate the store */ + Sec_Result result = SecUtils_ValidateKeyStore(processorHandle, SEC_FALSE, data, data_length); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ValidateKeyStore failed"); + return SEC_RESULT_FAILURE; + } + + SecUtils_KeyStoreHeader keystore_header; + result = SecStore_RetrieveData(processorHandle, SEC_FALSE, &keystore_header, sizeof(keystore_header), + key_buffer, SEC_KEYCONTAINER_MAX_LEN, data, data_length); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ValidateKeyStore failed"); + return SEC_RESULT_FAILURE; + } + + if (keystore_header.inner_kc_type == SEC_KEYCONTAINER_SOC_INTERNAL_0) { + if (sizeof(SecAdapter_DerivedInputs) != SecStore_GetDataLen(data)) { + SEC_LOG_ERROR("Invalid key length in the store"); + return SEC_RESULT_FAILURE; + } + + SecAdapter_DerivedInputs* derived_inputs = (SecAdapter_DerivedInputs*) key_buffer; + Sec_Key derived_key; + result = derive_root_key_ladder(derived_inputs->input1, derived_inputs->input2, derived_inputs->input3, + derived_inputs->input4, SEC_AES_BLOCK_SIZE, &derived_key.handle, SEC_KEYTYPE_AES_128); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Derive_root_key_ladder failed"); + return SEC_RESULT_FAILURE; + } + + // Export the key + result = export_key(&derived_key, NULL, key_buffer, SEC_KEYCONTAINER_MAX_LEN, key_length); + sa_key_release(derived_key.handle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Export of store keycontainer derived key failed"); + return SEC_RESULT_FAILURE; + } + + *key_container = SEC_KEYCONTAINER_EXPORTED; + } else if (SecKey_IsClearKeyContainer(keystore_header.inner_kc_type)) { + *key_container = keystore_header.inner_kc_type; + *key_length = SecStore_GetDataLen(data); + } else { + SEC_LOG_ERROR("Unsupported key container in store"); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result derive_root_key_ladder(const SEC_BYTE* c1, const SEC_BYTE* c2, const SEC_BYTE* c3, const SEC_BYTE* c4, + SEC_SIZE key_size, sa_key* key, Sec_KeyType key_type) { + + sa_kdf_parameters_root_key_ladder kdf_parameters = { + .c1 = c1, + .c1_length = c1 != NULL ? key_size : 0, + .c2 = c2, + .c2_length = c2 != NULL ? key_size : 0, + .c3 = c3, + .c3_length = c3 != NULL ? key_size : 0, + .c4 = c4, + .c4_length = c4 != NULL ? key_size : 0}; + + sa_rights rights; + rights_set_allow_all(&rights, key_type); + sa_status status = sa_key_derive(key, &rights, SA_KDF_ALGORITHM_ROOT_KEY_LADDER, &kdf_parameters); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +static Sec_Result derive_base_key(Sec_ProcessorHandle* processorHandle, SEC_BYTE* nonce, sa_key* key, + Sec_KeyType key_type) { + SEC_SIZE keySize = SEC_AES_BLOCK_SIZE; + SEC_BYTE c1[keySize]; + SEC_BYTE c2[keySize]; + SEC_BYTE c3[keySize]; + SEC_BYTE c4[keySize]; + + // Most SOCs use aesEcbNone. Some SOCs use desEdeNone and this will be fixed with a SOC specific patch. + Sec_Result result = SecKey_ComputeBaseKeyLadderInputs(processorHandle, "sivSha1", "aesEcbNone", nonce, + SEC_DIGESTALGORITHM_SHA1, keySize, c1, c2, c3, c4); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ComputeBaseKeyLadderInputs failed"); + return SEC_RESULT_FAILURE; + } + + // the first input is fixed to 0x00..01 + memset(c1, 0, sizeof(c1)); + c1[15] = 0x01; + + result = derive_root_key_ladder(c1, c2, c3, c4, keySize, key, key_type); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ComputeBaseKeyLadderInputs failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result derive_hkdf(Sec_MacAlgorithm macAlgorithm, Sec_KeyType typeDerived, const SEC_BYTE* salt, + SEC_SIZE saltSize, const SEC_BYTE* info, SEC_SIZE infoSize, sa_key baseKey, + sa_key* derived_key) { + if (macAlgorithm != SEC_MACALGORITHM_HMAC_SHA1 && macAlgorithm != SEC_MACALGORITHM_HMAC_SHA256) { + SEC_LOG_ERROR("Unsupported mac algorithm specified: %d", macAlgorithm); + return SEC_RESULT_FAILURE; + } + + if (!SecKey_IsSymetric(typeDerived)) { + SEC_LOG_ERROR("Can only derive symmetric keys"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + sa_digest_algorithm digest_algorithm = + (macAlgorithm == SEC_MACALGORITHM_HMAC_SHA1) ? SA_DIGEST_ALGORITHM_SHA1 : SA_DIGEST_ALGORITHM_SHA256; + sa_kdf_parameters_hkdf kdf_parameters = { + .key_length = SecKey_GetKeyLenForKeyType(typeDerived), + .digest_algorithm = digest_algorithm, + .parent = baseKey, + .salt = salt, + .salt_length = saltSize, + .info = info, + .info_length = infoSize}; + + sa_rights rights; + rights_set_allow_all(&rights, typeDerived); + sa_status status = sa_key_derive(derived_key, &rights, SA_KDF_ALGORITHM_HKDF, &kdf_parameters); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +static Sec_Result derive_kdf_concat(Sec_DigestAlgorithm digestAlgorithm, Sec_KeyType typeDerived, + const SEC_BYTE* otherInfo, SEC_SIZE otherInfoSize, sa_key baseKey, + sa_key* derived_key) { + if (digestAlgorithm != SEC_DIGESTALGORITHM_SHA1 && digestAlgorithm != SEC_DIGESTALGORITHM_SHA256) { + SEC_LOG_ERROR("Unsupported digest algorithm specified: %d", digestAlgorithm); + return SEC_RESULT_FAILURE; + } + + if (!SecKey_IsSymetric(typeDerived)) { + SEC_LOG_ERROR("Can only derive symmetric keys"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + sa_digest_algorithm digest_algorithm = + (digestAlgorithm == SEC_DIGESTALGORITHM_SHA1) ? SA_DIGEST_ALGORITHM_SHA1 : SA_DIGEST_ALGORITHM_SHA256; + sa_kdf_parameters_concat kdf_parameters = { + .key_length = SecKey_GetKeyLenForKeyType(typeDerived), + .digest_algorithm = digest_algorithm, + .parent = baseKey, + .info = otherInfo, + .info_length = otherInfoSize}; + + sa_rights rights; + rights_set_allow_all(&rights, typeDerived); + sa_status status = sa_key_derive(derived_key, &rights, SA_KDF_ALGORITHM_CONCAT, &kdf_parameters); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +static Sec_Result derive_kdf_cmac(Sec_KeyType typeDerived, const SEC_BYTE* otherData, SEC_SIZE otherDataSize, + const SEC_BYTE* counter, SEC_SIZE counterSize, sa_key baseKey, sa_key* derived_key) { + if (!SecKey_IsSymetric(typeDerived)) { + SEC_LOG_ERROR("Can only derive symmetric keys"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (counterSize != 1) { + SEC_LOG_ERROR("Only 1 byte counter is supported"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (*counter < 1 || *counter > 4) { + SEC_LOG_ERROR("Invalid counter passed in: %d", *counter); + return SEC_RESULT_INVALID_PARAMETERS; + } + + sa_kdf_parameters_cmac cmac_parameters = { + .key_length = SecKey_GetKeyLenForKeyType(typeDerived), + .parent = baseKey, + .other_data = otherData, + .other_data_length = otherDataSize, + .counter = *counter}; + + sa_rights rights; + rights_set_allow_all(&rights, typeDerived); + sa_status status = sa_key_derive(derived_key, &rights, SA_KDF_ALGORITHM_CMAC, &cmac_parameters); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +static Sec_Result unwrap_key(Sec_ProcessorHandle* processorHandle, Sec_CipherAlgorithm algorithm, + Sec_KeyType wrapped_key_type, SEC_SIZE wrapped_key_offset, SEC_OBJECTID id, SEC_BYTE* iv, SEC_BYTE* input, + SEC_SIZE input_len, SEC_BYTE* out_key, SEC_SIZE* out_key_len) { + Sec_KeyHandle* keyHandle; + Sec_Result result = SecKey_GetInstance(processorHandle, id, &keyHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return result; + } + + sa_rights rights; + rights_set_allow_all(&rights, wrapped_key_type); + sa_key_type key_type; + void* key_parameters; + result = get_sa_key_type(wrapped_key_type, &key_type, &key_parameters); + if (result != SEC_RESULT_SUCCESS) { + SecKey_Release(keyHandle); + SEC_LOG_ERROR("Get_sa_key_type failed"); + return result; + } + + void* cipher_parameters; + sa_cipher_algorithm cipher_algorithm; + result = get_cipher_algorithm(algorithm, SEC_TRUE, &cipher_algorithm, &cipher_parameters, iv, + SecKey_GetKeyLenForKeyType(wrapped_key_type), wrapped_key_offset); + if (result != SEC_RESULT_SUCCESS) { + SEC_FREE(key_parameters); + SecKey_Release(keyHandle); + SEC_LOG_ERROR("Get_cipher_algorithm failed"); + return result; + } + + Sec_Key unwrapped_key; + sa_status status = sa_key_unwrap(&unwrapped_key.handle, &rights, key_type, key_parameters, cipher_algorithm, + cipher_parameters, keyHandle->key.handle, input, input_len); + SEC_FREE(key_parameters); + SEC_FREE(cipher_parameters); + SecKey_Release(keyHandle); + CHECK_STATUS(status) + + // Export the key + result = export_key(&unwrapped_key, NULL, out_key, SEC_KEYCONTAINER_MAX_LEN, out_key_len); + sa_key_release(unwrapped_key.handle); + return result; +} + +static Sec_Result get_sa_key_type(Sec_KeyType keyType, sa_key_type* out_key_type, void** parameters) { + + sa_generate_parameters_symmetric parameters_symmetric; + sa_generate_parameters_rsa parameters_rsa; + sa_generate_parameters_ec parameters_ec; + *parameters = NULL; + switch (keyType) { + case SEC_KEYTYPE_AES_128: + case SEC_KEYTYPE_AES_256: + case SEC_KEYTYPE_HMAC_128: + case SEC_KEYTYPE_HMAC_160: + case SEC_KEYTYPE_HMAC_256: + *out_key_type = SA_KEY_TYPE_SYMMETRIC; + *parameters = calloc(1, sizeof(parameters_symmetric)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_generate_parameters_symmetric*) *parameters)->key_length = SecKey_GetKeyLenForKeyType(keyType); + return SEC_RESULT_SUCCESS; + + case SEC_KEYTYPE_RSA_1024: + case SEC_KEYTYPE_RSA_2048: + case SEC_KEYTYPE_RSA_3072: + *out_key_type = SA_KEY_TYPE_RSA; + *parameters = calloc(1, sizeof(sa_generate_parameters_rsa)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_generate_parameters_rsa*) *parameters)->modulus_length = SecKey_GetKeyLenForKeyType(keyType); + return SEC_RESULT_SUCCESS; + + case SEC_KEYTYPE_ECC_NISTP256: + *out_key_type = SA_KEY_TYPE_EC; + *parameters = calloc(1, sizeof(sa_generate_parameters_ec)); + if (parameters == NULL) + return SEC_RESULT_FAILURE; + + ((sa_generate_parameters_ec*) *parameters)->curve = SA_ELLIPTIC_CURVE_NIST_P256; + return SEC_RESULT_SUCCESS; + + default: + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } +} + +static Sec_Result export_key(Sec_Key* key, SEC_BYTE* derivationInput, SEC_BYTE* exportedKey, SEC_SIZE keyBufferLen, + SEC_SIZE* keyBytesWritten) { + + SEC_BYTE mixin[SEC_AES_BLOCK_SIZE]; + if (derivationInput == NULL) + sa_crypto_random(mixin, sizeof(mixin)); + else + memcpy(mixin, derivationInput, SEC_AES_BLOCK_SIZE); + + // Get key length. + if (exportedKey == NULL) { + size_t out_length = 0; + sa_status status = sa_key_export(exportedKey, &out_length, mixin, SEC_AES_BLOCK_SIZE, key->handle); + CHECK_STATUS(status) + + // Include the length of the derivationInput. + *keyBytesWritten = out_length; + return SEC_RESULT_SUCCESS; + } + + size_t out_length = keyBufferLen; + sa_status status = sa_key_export(exportedKey, &out_length, mixin, SEC_AES_BLOCK_SIZE, key->handle); + CHECK_STATUS(status) + *keyBytesWritten = out_length; + return SEC_RESULT_SUCCESS; +} + +static int disable_passphrase_prompt(char* buf, int size, int rwflag, void* u) { + return 0; +} diff --git a/src/sec_adapter_key.h b/src/sec_adapter_key.h new file mode 100644 index 0000000..6f8ed9b --- /dev/null +++ b/src/sec_adapter_key.h @@ -0,0 +1,55 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_KEY_H +#define SEC_ADAPTER_KEY_H + +#include "sa.h" +#include "sec_security.h" +#include "sec_security_comcastids.h" +#include + +typedef union Sec_Key_union { + // if key_type is SEC_KEYTYPE_RSA_XXXX_PUBLIC + RSA* rsa; + // if key_type is SEC_KEYTYPE_ECC_NISTP256_PUBLIC + EC_KEY* ec_key; + // if key_type is anything else + sa_key handle; +} Sec_Key; + +typedef struct Sec_KeyInfo_struct { + // This field is effectively unused, but is maintained for backward compatibility. + Sec_KeyType key_type; + Sec_KeyContainer kc_type; +} Sec_KeyInfo; + +typedef struct Sec_KeyData_struct { + Sec_KeyInfo info; + SEC_BYTE key_container[SEC_KEYCONTAINER_MAX_LEN]; + SEC_SIZE kc_len; +} Sec_KeyData; + +void rights_set_allow_all(sa_rights* rights, Sec_KeyType key_type); + +Sec_Result prepare_and_store_key_data(Sec_ProcessorHandle* processorHandle, Sec_StorageLoc location, + SEC_OBJECTID object_id, Sec_Key* key, Sec_KeyContainer key_container, void* key_buffer, SEC_SIZE key_length); + +const Sec_Key* get_key(Sec_KeyHandle* keyHandle); + +#endif // SEC_ADAPTER_KEY_H diff --git a/src/sec_adapter_key_legacy.h b/src/sec_adapter_key_legacy.h new file mode 100644 index 0000000..22cf868 --- /dev/null +++ b/src/sec_adapter_key_legacy.h @@ -0,0 +1,44 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_KEY_LEGACY_H +#define SEC_ADAPTER_KEY_LEGACY_H + +#define VERSION_2_KEY_CONTAINER 2 + +/** + * Import parameters for a Legacy SOC. This structure is used to signal the version of the Legacy + * key container. This structure is required for SecApi 2 (non-JWT) key containers and is optional for SecApi + * 3 (or JWT) key containers. If the sa_key_import parameters field is NULL, a SecApi 3 (JWT) key container is + * assumed. + */ +typedef struct { + /** The size of this structure. The most significant size byte is in length[0] and the least + significant size byte is in length[1]. */ + uint8_t length[2]; + + /** The version of the key container. Must be either version 2 or version 3. */ + uint8_t version; + + /** The default key rights to use only if the key container does not contain included key rights. */ + sa_rights default_rights; + + uint64_t object_id; +} sa_import_parameters_soc_legacy; + +#endif // SEC_ADAPTER_KEY_LEGACY_H diff --git a/src/sec_adapter_keyexchange.c b/src/sec_adapter_keyexchange.c new file mode 100644 index 0000000..2dd16ca --- /dev/null +++ b/src/sec_adapter_keyexchange.c @@ -0,0 +1,246 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sa.h" +#include "sec_adapter_key.h" +#include "sec_adapter_processor.h" +#include "sec_security.h" +#include + +#define BUFFER_SIZE 4096 + +struct Sec_KeyExchangeHandle_struct { + Sec_ProcessorHandle* processorHandle; + Sec_KeyExchangeAlgorithm alg; + void* parameters; + sa_key* key; +}; + +Sec_Result SecKeyExchange_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_KeyExchangeAlgorithm exchangeType, + void* exchangeParameters, Sec_KeyExchangeHandle** keyExchangeHandle) { + CHECK_PROCHANDLE(processorHandle) + + if (keyExchangeHandle == NULL) { + SEC_LOG_ERROR("NULL keyExchangeHandle"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (exchangeParameters == NULL) { + SEC_LOG_ERROR("NULL exchangeParameters"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + *keyExchangeHandle = NULL; + sa_generate_parameters_dh* dh_parameters = NULL; + sa_generate_parameters_ec* ec_parameters = NULL; + + switch (exchangeType) { + case SEC_KEYEXCHANGE_DH: + dh_parameters = calloc(1, sizeof(sa_generate_parameters_dh)); + if (dh_parameters == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + Sec_DHParameters* sec_dh_parameters = (Sec_DHParameters*) exchangeParameters; + dh_parameters->g = sec_dh_parameters->g; + dh_parameters->g_length = sec_dh_parameters->gLen; + dh_parameters->p = sec_dh_parameters->p; + dh_parameters->p_length = sec_dh_parameters->pLen; + break; + + case SEC_KEYEXCHANGE_ECDH: + if (((Sec_ECDHParameters*) exchangeParameters)->curve != NISTP256) { + SEC_LOG_ERROR("Unknown EC curve"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + ec_parameters = calloc(1, sizeof(sa_generate_parameters_ec)); + if (ec_parameters == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + ec_parameters->curve = SA_ELLIPTIC_CURVE_NIST_P256; + break; + + default: + SEC_LOG_ERROR("Unknown exchange_type encountered: %d", exchangeType); + return SEC_RESULT_INVALID_PARAMETERS; + } + + *keyExchangeHandle = calloc(1, sizeof(Sec_KeyExchangeHandle)); + if (*keyExchangeHandle == NULL) { + SEC_FREE(dh_parameters); + SEC_FREE(ec_parameters); + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + (*keyExchangeHandle)->processorHandle = processorHandle; + (*keyExchangeHandle)->alg = exchangeType; + (*keyExchangeHandle)->parameters = dh_parameters != NULL ? (void*) dh_parameters : (void*) ec_parameters; + + return *keyExchangeHandle != NULL ? SEC_RESULT_SUCCESS : SEC_RESULT_FAILURE; +} + +Sec_Result SecKeyExchange_GenerateKeys(Sec_KeyExchangeHandle* keyExchangeHandle, SEC_BYTE* publicKey, + SEC_SIZE pubKeySize) { + CHECK_HANDLE(keyExchangeHandle) + if (publicKey == NULL) { + SEC_LOG_ERROR("NULL publicKey"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + sa_key_type type; + sa_rights rights; + switch (keyExchangeHandle->alg) { + case SEC_KEYEXCHANGE_DH: + type = SA_KEY_TYPE_DH; + rights_set_allow_all(&rights, SEC_KEYTYPE_RSA_1024); + break; + + case SEC_KEYEXCHANGE_ECDH: + type = SA_KEY_TYPE_EC; + rights_set_allow_all(&rights, SEC_KEYTYPE_ECC_NISTP256); + break; + + default: + SEC_LOG_ERROR("Invalid key exchange type"); + return SEC_RESULT_FAILURE; + } + + keyExchangeHandle->key = calloc(1, sizeof(sa_key)); + if (keyExchangeHandle->key == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + sa_status status = sa_key_generate(keyExchangeHandle->key, &rights, type, keyExchangeHandle->parameters); + CHECK_STATUS(status) + size_t out_length = pubKeySize; + SEC_BYTE public_key_bytes[BUFFER_SIZE]; + status = sa_key_get_public(&public_key_bytes, &out_length, *keyExchangeHandle->key); + CHECK_STATUS(status) + + Sec_ECCRawPublicKey ecc_raw_public_key; + switch (keyExchangeHandle->alg) { + case SEC_KEYEXCHANGE_DH: + memcpy(publicKey, &public_key_bytes, out_length); + break; + + case SEC_KEYEXCHANGE_ECDH: + Sec_Uint32ToBEBytes(out_length / 2, ecc_raw_public_key.key_len); + memcpy(ecc_raw_public_key.x, &public_key_bytes[0], out_length / 2); + memcpy(ecc_raw_public_key.y, &public_key_bytes[out_length / 2], out_length / 2); + ecc_raw_public_key.type = SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + memcpy(publicKey, &ecc_raw_public_key, sizeof(ecc_raw_public_key)); + break; + + default: + SEC_LOG_ERROR("Invalid key exchange type"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecKeyExchange_ComputeSecret(Sec_KeyExchangeHandle* keyExchangeHandle, SEC_BYTE* otherPublicKey, + SEC_SIZE otherPublicKeySize, Sec_KeyType typeComputed, SEC_OBJECTID idComputed, + Sec_StorageLoc locComputed) { + CHECK_HANDLE(keyExchangeHandle) + if (keyExchangeHandle->key == NULL) { + SEC_LOG_ERROR("NULL keyExchangeHandle->key"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (otherPublicKey == NULL) { + SEC_LOG_ERROR("NULL otherPublicKey"); + return SEC_RESULT_INVALID_PARAMETERS; + } + + if (!SecKey_IsSymetric(typeComputed)) { + SEC_LOG_ERROR("Invalid key type encountered: %d", typeComputed); + return SEC_RESULT_FAILURE; + } + + // Set rights to derive only. SecApi 3.0 only allows a secret to be generated that can be fed into a derivation + // algorithm. It does not truncate the key to the typeComputed key type like is specified in SecApi 2. So disable + // the ability to sign, decrypt, encrypt, or unwrap. + sa_key_exchange_algorithm algorithm; + sa_rights rights; + rights_set_allow_all(&rights, SEC_KEYTYPE_NUM); + + SEC_BYTE public_key_bytes[BUFFER_SIZE]; + uint32_t key_len; + Sec_KeyContainer key_container; + switch (keyExchangeHandle->alg) { + case SEC_KEYEXCHANGE_DH: + algorithm = SA_KEY_EXCHANGE_ALGORITHM_DH; + memcpy(&public_key_bytes, otherPublicKey, otherPublicKeySize); + key_len = otherPublicKeySize; + + // The resulting key is actually the length of the p value. We just need a key container that will trigger + // the key to be exported and the result will be an exported key container, so pick the largest RSA key. + key_container = SEC_KEYCONTAINER_DER_RSA_3072; + break; + + case SEC_KEYEXCHANGE_ECDH: + algorithm = SA_KEY_EXCHANGE_ALGORITHM_ECDH; + if (otherPublicKeySize != sizeof(Sec_ECCRawPublicKey)) { + SEC_LOG_ERROR("Invalid ECC key"); + return SEC_RESULT_FAILURE; + } + + Sec_ECCRawPublicKey* ecc_raw_public_key = (Sec_ECCRawPublicKey*) otherPublicKey; + key_len = Sec_BEBytesToUint32(ecc_raw_public_key->key_len) * 2; + memcpy(&public_key_bytes[0], ecc_raw_public_key->x, key_len / 2); + memcpy(&public_key_bytes[key_len / 2], ecc_raw_public_key->y, key_len / 2); + + // The resulting secret is actually a valid AES 256 key. We just need a key container that will trigger + // the key to be exported and the result will be an exported key container, so just use AES_256. + key_container = SEC_KEYCONTAINER_RAW_AES_256; + break; + + default: + SEC_LOG_ERROR("Unknown alg encountered: %d", keyExchangeHandle->alg); + return SEC_RESULT_FAILURE; + } + + sa_key shared_secret; + sa_status status = sa_key_exchange(&shared_secret, &rights, algorithm, *keyExchangeHandle->key, public_key_bytes, + key_len, NULL); + CHECK_STATUS(status) + + Sec_Key key = {.handle = shared_secret}; + return prepare_and_store_key_data(keyExchangeHandle->processorHandle, locComputed, idComputed, &key, key_container, + NULL, 0); +} + +Sec_Result SecKeyExchange_Release(Sec_KeyExchangeHandle* keyExchangeHandle) { + if (keyExchangeHandle != NULL) { + if (keyExchangeHandle->key != NULL) + sa_key_release(*keyExchangeHandle->key); + + SEC_FREE(keyExchangeHandle->parameters); + SEC_FREE(keyExchangeHandle->key); + SEC_FREE(keyExchangeHandle); + } + + return SEC_RESULT_SUCCESS; +} diff --git a/src/sec_adapter_logger.c b/src/sec_adapter_logger.c new file mode 100644 index 0000000..33bdd30 --- /dev/null +++ b/src/sec_adapter_logger.c @@ -0,0 +1,70 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_security.h" +#include + +#define BUFFER_SIZE 1024 + +SecApiLogCallback g_sec_logcb = Sec_DefaultLoggerCb; + +void Sec_SetLogger(SecApiLogCallback cb) { + g_sec_logcb = cb; +} + +SecApiLogCallback Sec_GetLogger(void) { + return g_sec_logcb; +} + +void Sec_DefaultLoggerCb(const char* fmt, ...) { + va_list args; + + va_start(args, fmt); + vfprintf(stdout, fmt, args); // NOLINT + va_end(args); + + fflush(stdout); +} + +void Sec_PrintHex(void* data, SEC_SIZE numBytes) { + char buffer[BUFFER_SIZE]; + memset(buffer, 0, sizeof(buffer)); + char* ptr = buffer; + + size_t maxBytes = (sizeof(buffer) - 1) / 2; + + SEC_BYTE* data_ptr = (SEC_BYTE*) data; + SEC_SIZE i; + + for (i = 0; i < SEC_MIN(maxBytes, numBytes); ++i) { + int result = sprintf(ptr, "%02x", data_ptr[i]); + if (result < 0) + break; + + ptr += result; + } + + SEC_PRINT(buffer); +} + +/** + * @brief NOP logger implementation + */ +void Sec_NOPLoggerCb(const char* fmt, ...) { + // NOOP +} diff --git a/src/sec_adapter_mac.c b/src/sec_adapter_mac.c new file mode 100644 index 0000000..e38208a --- /dev/null +++ b/src/sec_adapter_mac.c @@ -0,0 +1,239 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sa.h" +#include "sec_adapter_processor.h" +#include "sec_security.h" + +struct Sec_MacHandle_struct { + Sec_ProcessorHandle* processorHandle; + Sec_MacAlgorithm algorithm; + Sec_KeyHandle* keyHandle; + sa_crypto_mac_context mac_context; +}; + +Sec_Result SecMac_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm alg, Sec_KeyHandle* keyHandle, + SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* mac, SEC_SIZE* mac_len) { + Sec_Result result; + Sec_MacHandle* macHandle= NULL; + + result = SecMac_GetInstance(processorHandle, alg, keyHandle, &macHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_GetInstance failed"); + return result; + } + + result = SecMac_Update(macHandle, input, input_len); + SecMac_Release(macHandle, mac, mac_len); + return result; +} + +Sec_Result SecMac_SingleInputId(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm alg, SEC_OBJECTID key, + SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* mac, SEC_SIZE* mac_len) { + Sec_KeyHandle* keyHandle = NULL; + Sec_Result result = SecKey_GetInstance(processorHandle, key, &keyHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return result; + } + + result = SecMac_SingleInput(processorHandle, alg, keyHandle, input, input_len, mac, mac_len); + SecKey_Release(keyHandle); + + return result; +} + +/** + * @brief Obtain a handle for the MAC calculator. + * + * @param processorHandle secure processor handle. + * @param algorithm MAC algorithm to use for MAC calculation. + * @param keyHandle key to use for the MAC calculation. + * @param macHandle output MAC calculator handle. + * + * @return The status of the operation. + */ +Sec_Result SecMac_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm algorithm, + Sec_KeyHandle* keyHandle, Sec_MacHandle** macHandle) { + CHECK_PROCHANDLE(processorHandle) + *macHandle = NULL; + + Sec_KeyType key_type = SecKey_GetKeyType(keyHandle); + Sec_Result result = SecMac_IsValidKey(key_type, algorithm); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Not a valid mac key"); + return result; + } + + *macHandle = calloc(1, sizeof(Sec_MacHandle)); + if (*macHandle == NULL) { + SEC_LOG_ERROR("Malloc failed"); + return SEC_RESULT_FAILURE; + } + + (*macHandle)->processorHandle = processorHandle; + (*macHandle)->algorithm = algorithm; + (*macHandle)->keyHandle = keyHandle; + + sa_mac_algorithm mac_algorithm; + sa_mac_parameters_hmac hmac_parameters; + void* parameters; + switch (algorithm) { + case SEC_MACALGORITHM_HMAC_SHA1: + mac_algorithm = SA_MAC_ALGORITHM_HMAC; + hmac_parameters.digest_algorithm = SA_DIGEST_ALGORITHM_SHA1; + parameters = &hmac_parameters; + break; + + case SEC_MACALGORITHM_HMAC_SHA256: + mac_algorithm = SA_MAC_ALGORITHM_HMAC; + hmac_parameters.digest_algorithm = SA_DIGEST_ALGORITHM_SHA256; + parameters = &hmac_parameters; + break; + + case SEC_MACALGORITHM_CMAC_AES_128: + mac_algorithm = SA_MAC_ALGORITHM_CMAC; + parameters = NULL; + break; + + default: + return SEC_RESULT_INVALID_PARAMETERS; + } + + const Sec_Key* key = get_key(keyHandle); + sa_status status = sa_crypto_mac_init(&(*macHandle)->mac_context, mac_algorithm, key->handle, parameters); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Updates the digest value with the input data. + * + * @param macHandle mac handle. + * @param input pointer to the input data. + * @param size of the input buffer. + * + * @return The status of the operation. + */ +Sec_Result SecMac_Update(Sec_MacHandle* macHandle, SEC_BYTE* input, SEC_SIZE inputSize) { + CHECK_HANDLE(macHandle) + sa_status status = sa_crypto_mac_process(macHandle->mac_context, input, inputSize); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Updates the digest value with the contents of a key. + * + * @param macHandle mac handle. + * @param keyHandle key to use. + * + * @return The status of the operation. + */ +Sec_Result SecMac_UpdateWithKey(Sec_MacHandle* macHandle, Sec_KeyHandle* keyHandle) { + CHECK_HANDLE(macHandle) + CHECK_HANDLE(keyHandle) + const Sec_Key* key = get_key(keyHandle); + sa_status status = sa_crypto_mac_process_key(macHandle->mac_context, key->handle); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Calculate the resulting MAC value and release the MAC object. + * + * @param macHandle mac handle. + * @param macBuffer pointer to an output buffer that will be filled with the resulting. + * MAC value. Buffer should be SEC_MAC_MAX_LEN bytes long. + * @param macSize pointer to a value that will be set to actual size of the MAC value. + * + * @return The status of the operation. + */ +Sec_Result SecMac_Release(Sec_MacHandle* macHandle, SEC_BYTE* macBuffer, SEC_SIZE* macSize) { + CHECK_HANDLE(macHandle) + + size_t out_length = SEC_MAC_MAX_LEN; + sa_status status = sa_crypto_mac_compute(macBuffer, &out_length, macHandle->mac_context); + sa_crypto_mac_release(macHandle->mac_context); + CHECK_STATUS(status) + + *macSize = out_length; + SEC_FREE(macHandle); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Check whether the passed in key type is valid for a chosen MAC algorithm. + * + * @param key_type key type. + * @param algorithm MAC algorithm. + * + * @return status of the operation. + */ + +Sec_Result SecMac_IsValidKey(Sec_KeyType key_type, Sec_MacAlgorithm algorithm) { + switch (algorithm) { + case SEC_MACALGORITHM_HMAC_SHA1: + case SEC_MACALGORITHM_HMAC_SHA256: + // SecApi 3 does not distinguish between HMAC and AES keys. + if (key_type == SEC_KEYTYPE_HMAC_128 || + key_type == SEC_KEYTYPE_HMAC_160 || + key_type == SEC_KEYTYPE_HMAC_256 || + key_type == SEC_KEYTYPE_AES_128 || + key_type == SEC_KEYTYPE_AES_256) { + return SEC_RESULT_SUCCESS; + } else { + return SEC_RESULT_FAILURE; + } + + case SEC_MACALGORITHM_CMAC_AES_128: + // SecApi 3 does not distinguish between HMAC and AES keys. + if (key_type == SEC_KEYTYPE_HMAC_128 || + key_type == SEC_KEYTYPE_HMAC_256 || + key_type == SEC_KEYTYPE_AES_128 || + key_type == SEC_KEYTYPE_AES_256) { + return SEC_RESULT_SUCCESS; + } else { + return SEC_RESULT_FAILURE; + } + + default: + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } +} + +/** + * @brief Obtain a digest algorithm used by a specified MAC algorithm. + * + * @param alg MAC algorithm. + * + * @return digest algorithm used. + */ +Sec_DigestAlgorithm SecMac_GetDigestAlgorithm(Sec_MacAlgorithm algorithm) { + switch (algorithm) { + case SEC_MACALGORITHM_HMAC_SHA1: + return SEC_DIGESTALGORITHM_SHA1; + + case SEC_MACALGORITHM_HMAC_SHA256: + return SEC_DIGESTALGORITHM_SHA256; + + case SEC_MACALGORITHM_CMAC_AES_128: + default: + return SEC_DIGESTALGORITHM_NUM; + } +} diff --git a/src/sec_adapter_processor.c b/src/sec_adapter_processor.c new file mode 100644 index 0000000..cd0430e --- /dev/null +++ b/src/sec_adapter_processor.c @@ -0,0 +1,505 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_processor.h" + +// Processor handles are stored in the threadlocal proc_handle. Every time SecProcessor_GetInstance_Directories is +// called, proc_handle will be searched for a Sec_ProcessorHandle with the same globalDir and appDir. If an existing +// Sec_ProcessorHandle is found, it is returned. If not, a new one is created and stored in proc_handle. All will be +// destroyed when the thread or the application shuts down. At most 25 unique Sec_ProcessorHandles can be created per +// thread. 25 was chosen because it is believed that this is more than enough to handle current applications. It +// can be increase if this is not enough. +#define MAX_PROC_HANDLES 25 + +struct Sec_ProcessorInitParams_struct { +}; + +static SEC_BOOL initialized = SEC_FALSE; +static _Thread_local Sec_ProcessorHandle* processorHandles[MAX_PROC_HANDLES]; +static pthread_key_t key; +static pthread_once_t key_once = PTHREAD_ONCE_INIT; + +static void make_key(); + +static void release_proc_handle(void* handle); + +static void proc_shutdown(); + +static Sec_Result Sec_SetStorageDir(const char* provided_dir, const char* default_dir, char* output_dir); + +static void thread_shutdown(void* unused); + +/** + * @brief Initialize secure processor. + * + * Initializes the secure processor, generates key derivation base key, + * sets up all required resources. Only one secure processor can be + * active at a time. + * + * @param processorHandle pointer to a processor handle that will be set to + * a constructed handle. + * @param socInitParams pointer to initialization information for the secure + * processor. This structure is implementation specific. + * + * @return The status of the operation. + */ +Sec_Result SecProcessor_GetInstance(Sec_ProcessorHandle** processorHandle, + Sec_ProcessorInitParams* socInitParams) { + return SecProcessor_GetInstance_Directories(processorHandle, SEC_GLOBAL_DIR_DEFAULT, SEC_GLOBAL_DIR_DEFAULT); +} + +/** + * @brief Initialize secure processor. + * + * Initializes the secure processor, generates key derivation base key, + * sets up all required resources. Only one secure processor can be + * active at a time. + * + * @param processorHandle pointer to a processor handle that will be set to + * a constructed handle. + * @param globalDir path to the read only object directory. Can be set to NULL. + * @param appDir path to the read/write object directory. Can be set to NULL. + * + * @return The status of the operation. + */ +Sec_Result SecProcessor_GetInstance_Directories(Sec_ProcessorHandle** processorHandle, const char* globalDir, + const char* appDir) { + Sec_Result result; + SecAdapter_DerivedInputs derived_inputs; + SecUtils_KeyStoreHeader keystore_header; + SEC_BYTE store[SEC_KEYCONTAINER_MAX_LEN]; + + if (pthread_once(&key_once, make_key) != 0) + return SEC_RESULT_FAILURE; + + if (processorHandle == NULL) { + SEC_LOG_ERROR("proc_handle is NULL"); + return SEC_RESULT_FAILURE; + } + + size_t free_proc_handle = MAX_PROC_HANDLES; + for (size_t i = 0; i < MAX_PROC_HANDLES; i++) { + const char* temp_app_dir = appDir == NULL ? SEC_APP_DIR_DEFAULT : appDir; + const char* temp_global_dir = globalDir == NULL ? SEC_GLOBAL_DIR_DEFAULT : globalDir; + if (processorHandles[i] != NULL) { + if (memcmp(processorHandles[i]->global_dir, temp_global_dir, strlen(temp_global_dir)) == 0 && + memcmp(processorHandles[i]->app_dir, temp_app_dir, strlen(temp_app_dir)) == 0) { + *processorHandle = processorHandles[i]; + return SEC_RESULT_SUCCESS; + } + } else { + free_proc_handle = i; + break; + } + } + + if (free_proc_handle == MAX_PROC_HANDLES) { + SEC_LOG_ERROR("No free proc handles"); + return SEC_RESULT_FAILURE; + } + + /* create handle */ + *processorHandle = calloc(1, sizeof(Sec_ProcessorHandle)); + if (*processorHandle == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + /* setup key and cert directories */ + if (appDir != NULL) { + (*processorHandle)->app_dir = (char*) calloc(1, SEC_MAX_FILE_PATH_LEN); + if ((*processorHandle)->app_dir == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + result = Sec_SetStorageDir(appDir, SEC_APP_DIR_DEFAULT, (*processorHandle)->app_dir); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating app_dir"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE(*processorHandle); + return result; + } + + result = SecUtils_MkDir((*processorHandle)->app_dir); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating app_dir"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE(*processorHandle); + return result; + } + } + + if (globalDir != NULL) { + (*processorHandle)->global_dir = (char*) calloc(1, SEC_MAX_FILE_PATH_LEN); + if ((*processorHandle)->global_dir == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + result = Sec_SetStorageDir(globalDir, SEC_GLOBAL_DIR_DEFAULT, (*processorHandle)->global_dir); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating global_dir"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + SEC_FREE(*processorHandle); + return result; + } + } + + // Calls client_thread_shutdown when the thread exits. + if (pthread_key_create(&key, thread_shutdown) != 0) { + SEC_LOG_ERROR("tss_create failed"); + return SEC_RESULT_FAILURE; + } + + processorHandles[free_proc_handle] = *processorHandle; + if (pthread_setspecific(key, processorHandle) != 0) { + SEC_LOG_ERROR("Error storing procHandle in thread local storage"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return SEC_RESULT_FAILURE; + } + + // Initial OpenSSL. + Sec_InitOpenSSL(); + + /* generate sec store proc ins */ + result = SecStore_GenerateLadderInputs(*processorHandle, SEC_STORE_AES_LADDER_INPUT, NULL, + (SEC_BYTE*) &derived_inputs, sizeof(derived_inputs)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error Generating LadderInputs"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + result = SecUtils_FillKeyStoreUserHeader(*processorHandle, &keystore_header, SEC_KEYCONTAINER_SOC_INTERNAL_0); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error Filling KeyStoreUserHeader"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + result = SecStore_StoreData(*processorHandle, SEC_FALSE, SEC_FALSE, (SEC_BYTE*) SEC_UTILS_KEYSTORE_MAGIC, + &keystore_header, sizeof(keystore_header), &derived_inputs, sizeof(derived_inputs), store, sizeof(store)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error storing derived_inputs"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + result = SecKey_Provision(*processorHandle, SEC_OBJECTID_STORE_AES_KEY, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_KEYCONTAINER_STORE, store, SecStore_GetStoreLen(store)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating SEC_OBJECTID_STORE_AES_KEY"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + result = SecStore_GenerateLadderInputs(*processorHandle, SEC_STORE_MAC_LADDER_INPUT, NULL, + (SEC_BYTE*) &derived_inputs, sizeof(derived_inputs)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating SEC_STORE_MAC_LADDER_INPUT"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + result = SecUtils_FillKeyStoreUserHeader(*processorHandle, &keystore_header, SEC_KEYCONTAINER_SOC_INTERNAL_0); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating keystore_header"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + result = SecStore_StoreData(*processorHandle, SEC_FALSE, SEC_FALSE, (SEC_BYTE*) SEC_UTILS_KEYSTORE_MAGIC, + &keystore_header, sizeof(keystore_header), &derived_inputs, sizeof(derived_inputs), store, sizeof(store)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating sec_store"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + result = SecKey_Provision(*processorHandle, SEC_OBJECTID_STORE_MACKEYGEN_KEY, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_KEYCONTAINER_STORE, store, SecStore_GetStoreLen(store)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating SEC_OBJECTID_STORE_MACKEYGEN_KEY"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + // generate certificate mac key + const char* otherInfo = "certMacKeyhmacSha256concatKdfSha1"; + const char* nonce = "abcdefghijklmnopqr\0"; + result = SecKey_Derive_ConcatKDF(*processorHandle, SEC_OBJECTID_CERTSTORE_KEY, SEC_KEYTYPE_HMAC_256, + SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA256, (SEC_BYTE*) nonce, (SEC_BYTE*) otherInfo, + strlen(otherInfo)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Error creating certificate mac key"); + SEC_FREE((*processorHandle)->app_dir); + SEC_FREE((*processorHandle)->global_dir); + processorHandles[free_proc_handle] = NULL; + SEC_FREE(*processorHandle); + return result; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Get the minimum depth of the hardware key ladder. + * + * @param handle pointer to a handle. + * @param root root key type. + * + * @return The key ladder depth. + */ +SEC_SIZE SecProcessor_GetKeyLadderMinDepth(Sec_ProcessorHandle* processorHandle, Sec_KeyLadderRoot root) { + return SECAPI3_KEY_DEPTH; +} + +/** + * @brief Get the maximum depth of the hardware key ladder. + * + * @param handle pointer to a handle. + * @param root root key type. + * + * @return The key ladder depth. + */ +SEC_SIZE SecProcessor_GetKeyLadderMaxDepth(Sec_ProcessorHandle* processorHandle, Sec_KeyLadderRoot root) { + return SECAPI3_KEY_DEPTH; +} + +/** + * @brief Prints SOC specific version info. + * + * @param processorHandle secure processor handle. + */ +Sec_Result SecProcessor_PrintInfo(Sec_ProcessorHandle* processorHandle) { + CHECK_PROCHANDLE(processorHandle) + + SEC_BYTE deviceId[SEC_DEVICEID_LEN]; + if (SecProcessor_GetDeviceId(processorHandle, deviceId) == SEC_RESULT_SUCCESS) + SEC_PRINT("device id: " SEC_OBJECTID_PATTERN "\n", Sec_BEBytesToUint64(deviceId)); + else + SEC_PRINT("device id: unknown\n"); + + SEC_PRINT("platform: SEC_API_2_ADAPTER\n"); + SEC_PRINT("version: %s\n", SEC_API_VERSION); + + SEC_PRINT("app_dir: %s\n", processorHandle->app_dir); + SEC_PRINT("global_dir: %s\n", processorHandle->global_dir); + Sec_PrintOpenSSLVersion(); + + sa_version version; + sa_status status = sa_get_version(&version); + CHECK_STATUS(status) + + SEC_PRINT("specification_major: %ld, specification_minor: %ld, " + "specification_revision: %ld, implementation_revision: %ld\n", + version.specification_major, version.specification_minor, + version.specification_revision, version.implementation_revision); + + Sec_PrintOpenSSLVersion(); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Get the Security Processor information (SecAPI version and build + * information). + * + * @param processorHandle secure processor handle. + * @param pointer to secure processor information. + */ +Sec_Result SecProcessor_GetInfo(Sec_ProcessorHandle* processorHandle, Sec_ProcessorInfo* secProcInfo) { + CHECK_PROCHANDLE(processorHandle) + + if (secProcInfo == NULL) + return SEC_RESULT_INVALID_PARAMETERS; + + sa_version version; + sa_status status = sa_get_version(&version); + CHECK_STATUS(status) + + memcpy(secProcInfo, &version, sizeof(sa_version)); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Obtain the device id. + * + * @param processorHandle secure processor handle. + * @param deviceId pointer to a buffer that is SEC_DEVICEID_LEN long. The + * buffer will be filled with a device id. + * + * @return The status of the operation. + */ +Sec_Result SecProcessor_GetDeviceId(Sec_ProcessorHandle* processorHandle, SEC_BYTE* deviceId) { + CHECK_PROCHANDLE(processorHandle) + + if (deviceId == NULL) + return SEC_RESULT_INVALID_PARAMETERS; + + uint64_t sa3_device_id; + sa_status status = sa_get_device_id(&sa3_device_id); + CHECK_STATUS(status) + + Sec_Uint64ToBEBytes(sa3_device_id, deviceId); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Release the security processor. + * + * @param processorHandle secure processor handle. + * + * @return The status of the operation. + */ +Sec_Result SecProcessor_Release(Sec_ProcessorHandle* processorHandle) { + // Do nothing. Released when the thread shutsdown. + return SEC_RESULT_SUCCESS; +} + +/** + * This was done for legacy BRCM HW which would get a performance boost if used with special pool of memory for AES + * cipher. For SecApi3, I would just map this to malloc. + * --Davor + */ +SEC_BYTE* Sec_NativeMalloc(Sec_ProcessorHandle* processorHandle, SEC_SIZE length) { + if (processorHandle == NULL) + return NULL; + + return malloc(length); +} + +/** + * This was done for legacy BRCM HW which would get a performance boost if used with special pool of memory for AES + * cipher. For SecApi3, I would just map this to malloc. + * --Davor + */ +void Sec_NativeFree(Sec_ProcessorHandle* processorHandle, void* ptr) { + if (processorHandle == NULL) + return; + + free(ptr); +} + +Sec_Result Sec_SetStorageDir(const char* provided_dir, const char* default_dir, char* output_dir) { + const char* dir_to_use; + size_t len; + + if (provided_dir == NULL || strlen(provided_dir) == 0) { + if (default_dir == NULL || strlen(default_dir) == 0) + return SEC_RESULT_FAILURE; + + dir_to_use = default_dir; + } else + dir_to_use = provided_dir; + + len = strlen(dir_to_use); + if (len >= (SEC_MAX_FILE_PATH_LEN - 2)) { + SEC_LOG_ERROR("Directory name length is too long"); + return SEC_RESULT_FAILURE; + } + + snprintf(output_dir, SEC_MAX_FILE_PATH_LEN, "%s", dir_to_use); + + if (output_dir[len - 1] != '/' && output_dir[len - 1] != '\\') { + output_dir[len] = '/'; + output_dir[len + 1] = '\0'; + } + + return SEC_RESULT_SUCCESS; +} + +static void make_key() { + // Calls release_proc_handle on thread exit and passes in the processorHandle stored in the key. But does not run + // on application (main thread) exit. + pthread_key_create(&key, release_proc_handle); + + for (size_t i = 0; i < MAX_PROC_HANDLES; i++) + processorHandles[i] = NULL; + + // Calls proc_shutdown when the application (main thread) exits. + if (atexit(proc_shutdown) != 0) { + SEC_LOG_ERROR("atexit failed"); + return; + } +} + +static void release_proc_handle(void* handle) { + if (handle == NULL) + return; + + Sec_ProcessorHandle* processorHandle = handle; + + /* release ram keys */ + while (processorHandle->ram_keys != NULL) + SecKey_Delete(processorHandle, processorHandle->ram_keys->object_id); + + /* release ram bundles */ + while (processorHandle->ram_bundles != NULL) + SecBundle_Delete(processorHandle, processorHandle->ram_bundles->object_id); + + /* release ram certs */ + while (processorHandle->ram_certs != NULL) + SecCertificate_Delete(processorHandle, processorHandle->ram_certs->object_id); + + SEC_FREE(processorHandle->app_dir); + SEC_FREE(processorHandle->global_dir); + + free(processorHandle); +} + +static void proc_shutdown() { + for (size_t i = 0; i < MAX_PROC_HANDLES; i++) { + if (processorHandles[i] != NULL) { + release_proc_handle(processorHandles[i]); + processorHandles[i] = NULL; + } + } +} + +static void thread_shutdown(void* unused) { + proc_shutdown(); +} diff --git a/src/sec_adapter_processor.h b/src/sec_adapter_processor.h new file mode 100644 index 0000000..d8a1706 --- /dev/null +++ b/src/sec_adapter_processor.h @@ -0,0 +1,120 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_PROCESSOR_H +#define SEC_ADAPTER_PROCESSOR_H + +#include "sa.h" +#include "sec_adapter_key.h" +#include "sec_adapter_store.h" +#include "sec_adapter_utils.h" +#include "sec_security.h" +#include "sec_version.h" +#include +#include +#include + +#ifdef __cplusplus +#include +#else +#include +#endif + +typedef struct { + SEC_BYTE input1[SEC_AES_BLOCK_SIZE]; + SEC_BYTE input2[SEC_AES_BLOCK_SIZE]; + SEC_BYTE input3[SEC_AES_BLOCK_SIZE]; + SEC_BYTE input4[SEC_AES_BLOCK_SIZE]; +} SecAdapter_DerivedInputs; + +typedef struct { + SEC_BYTE mac[SEC_MAC_MAX_LEN]; + SEC_SIZE cert_len; + SEC_BYTE cert[SEC_CERT_MAX_DATA_LEN]; +} Sec_CertificateData; + +typedef struct { + SEC_BYTE bundle[SEC_BUNDLE_MAX_LEN]; + SEC_SIZE bundle_len; +} Sec_BundleData; + +typedef struct Sec_RAMKeyData_struct { + SEC_OBJECTID object_id; + Sec_KeyData key_data; + struct Sec_RAMKeyData_struct* next; +} Sec_RAMKeyData; + +typedef struct Sec_RAMCertificateData_struct { + SEC_OBJECTID object_id; + Sec_CertificateData cert_data; + struct Sec_RAMCertificateData_struct* next; +} Sec_RAMCertificateData; + +typedef struct Sec_RAMBundleData_struct { + SEC_OBJECTID object_id; + Sec_BundleData bundle_data; + struct Sec_RAMBundleData_struct* next; +} Sec_RAMBundleData; + +struct Sec_ProcessorHandle_struct { + Sec_RAMKeyData* ram_keys; + Sec_RAMBundleData* ram_bundles; + Sec_RAMCertificateData* ram_certs; + char* global_dir; + char* app_dir; + int device_settings_init_flag; +}; + +static const int SECAPI3_KEY_DEPTH = 4; + +#define SEC_APP_DIR_DEFAULT "./" +#define SEC_GLOBAL_DIR_DEFAULT "/opt/drm" + +#define CHECK_PROCHANDLE(handle) CHECK_HANDLE(handle) + +#define CHECK_HANDLE(handle) \ + if ((handle) == NULL) { \ + SEC_LOG_ERROR("Invalid handle"); \ + return SEC_RESULT_INVALID_HANDLE; \ + } + +#define CHECK_STATUS(status) \ + switch (status) { \ + case SA_STATUS_OK: \ + break; \ + case SA_STATUS_NO_AVAILABLE_RESOURCE_SLOT: \ + return SEC_RESULT_NO_KEYSLOTS_AVAILABLE; \ + case SA_STATUS_BAD_KEY_TYPE: \ + case SA_STATUS_NULL_PARAMETER: \ + case SA_STATUS_BAD_PARAMETER: \ + return SEC_RESULT_INVALID_PARAMETERS; \ + case SA_STATUS_BAD_SVP_BUFFER: \ + return SEC_RESULT_INVALID_SVP_DATA; \ + case SA_STATUS_OPERATION_NOT_SUPPORTED: \ + return SEC_RESULT_UNIMPLEMENTED_FEATURE; \ + case SA_STATUS_VERIFICATION_FAILED: \ + return SEC_RESULT_VERIFICATION_FAILED; \ + case SA_STATUS_BAD_KEY_FORMAT: \ + case SA_STATUS_OPERATION_NOT_ALLOWED: \ + case SA_STATUS_SELF_TEST: \ + case SA_STATUS_INTERNAL_ERROR: \ + default: \ + return SEC_RESULT_FAILURE; \ + } + +#endif // SEC_ADAPTER_PROCESSOR_H diff --git a/src/sec_adapter_pubops.c b/src/sec_adapter_pubops.c new file mode 100644 index 0000000..150fd61 --- /dev/null +++ b/src/sec_adapter_pubops.c @@ -0,0 +1,629 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_pubops.h" + +static Sec_Result SecUtils_BigNumToBuffer(const BIGNUM* bignum, SEC_BYTE* buffer, SEC_SIZE buffer_len) { + SEC_SIZE num_bytes; + + memset(buffer, 0, buffer_len); + num_bytes = BN_num_bytes(bignum); + + if (num_bytes > buffer_len) { + SEC_LOG_ERROR("Buffer not large enough. needed: %d, actual: %d", num_bytes, buffer_len); + return SEC_RESULT_FAILURE; + } + + BN_bn2bin(bignum, buffer + buffer_len - num_bytes); + + return SEC_RESULT_SUCCESS; +} + +static RSA* SecUtils_RSAFromPubBinary(Sec_RSARawPublicKey* binary) { + RSA* rsa = NULL; + + rsa = RSA_new(); + if (rsa == NULL) { + SEC_LOG_ERROR("RSA_new failed"); + return NULL; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + rsa->n = BN_bin2bn(binary->n, (int) Sec_BEBytesToUint32(binary->modulus_len_be), NULL); + rsa->e = BN_bin2bn(binary->e, 4, NULL); +#else + RSA_set0_key(rsa, BN_bin2bn(binary->n, (int) Sec_BEBytesToUint32(binary->modulus_len_be), NULL), + BN_bin2bn(binary->e, 4, NULL), NULL); +#endif + + return rsa; +} + +static EC_KEY* SecUtils_ECCFromPubBinary(Sec_ECCRawPublicKey* binary) { + BN_CTX* ctx = BN_CTX_new(); + + if (binary->type != SEC_KEYTYPE_ECC_NISTP256_PUBLIC && binary->type != SEC_KEYTYPE_ECC_NISTP256) + return NULL; + + //create ec_key structure with NIST p256 curve; + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + EC_POINT* ec_point = EC_POINT_new(group); + BN_CTX_start(ctx); + BIGNUM* xp; + BIGNUM* yp; + + if (((xp = BN_CTX_get(ctx)) == NULL) || ((yp = BN_CTX_get(ctx)) == NULL)) { + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return NULL; + } + + EC_POINT_set_affine_coordinates_GFp(group, ec_point, + BN_bin2bn(binary->x, (int) Sec_BEBytesToUint32(binary->key_len), xp), + BN_bin2bn(binary->y, (int) Sec_BEBytesToUint32(binary->key_len), yp), ctx); + EC_KEY_set_public_key(ec_key, ec_point); + + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ec_key; +} + +static Sec_Result SecUtils_VerifyX509WithRawECCPublicKey(X509* x509, Sec_ECCRawPublicKey* public_key) { + EC_KEY* ec_key = NULL; + EVP_PKEY* evp_key = NULL; + int verify_res; + + ec_key = SecUtils_ECCFromPubBinary(public_key); + if (ec_key == NULL) { + SEC_LOG_ERROR("_SecUtils_ECCFromPubBinary failed"); + SEC_ECC_FREE(ec_key); + SEC_EVPPKEY_FREE(evp_key); + return SEC_RESULT_FAILURE; + } + + evp_key = EVP_PKEY_new(); + if (EVP_PKEY_set1_EC_KEY(evp_key, ec_key) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_PKEY_set1_EC_KEY failed"); + SEC_ECC_FREE(ec_key); + SEC_EVPPKEY_FREE(evp_key); + return SEC_RESULT_FAILURE; + } + + verify_res = X509_verify(x509, evp_key); + + SEC_ECC_FREE(ec_key); + SEC_EVPPKEY_FREE(evp_key); + + if (verify_res != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("X509_verify failed, %s", + ERR_error_string(ERR_get_error(), NULL)); + return SEC_RESULT_VERIFICATION_FAILED; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result SecUtils_VerifyX509WithRawRSAPublicKey(X509* x509, Sec_RSARawPublicKey* public_key) { + RSA* rsa = NULL; + EVP_PKEY* evp_key = NULL; + int verify_res; + + rsa = SecUtils_RSAFromPubBinary(public_key); + if (rsa == NULL) { + SEC_LOG_ERROR("_Sec_ReadRSAPublic failed"); + SEC_RSA_FREE(rsa); + SEC_EVPPKEY_FREE(evp_key); + return SEC_RESULT_FAILURE; + } + + evp_key = EVP_PKEY_new(); + if (EVP_PKEY_set1_RSA(evp_key, rsa) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_PKEY_set1_RSA failed"); + SEC_RSA_FREE(rsa); + SEC_EVPPKEY_FREE(evp_key); + return SEC_RESULT_FAILURE; + } + + verify_res = X509_verify(x509, evp_key); + + SEC_RSA_FREE(rsa); + SEC_EVPPKEY_FREE(evp_key); + + if (verify_res != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("X509_verify failed, %s", + ERR_error_string(ERR_get_error(), NULL)); + return SEC_RESULT_VERIFICATION_FAILED; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result SecUtils_Extract_EC_KEY_X_Y(const EC_KEY* ec_key, BIGNUM** xp, BIGNUM** yp, Sec_KeyType* keyTypep) { + const EC_GROUP* group = NULL; + const EC_POINT* ec_point = NULL; + BN_CTX* ctx = NULL; + Sec_Result result = SEC_RESULT_FAILURE; + + if (xp == NULL) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: X cannot be NULL"); + if (ctx != NULL) + BN_CTX_free(ctx); + + return result; + } + + group = EC_KEY_get0_group(ec_key); + if (group == NULL) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_KEY_get0_group: %s", ERR_error_string(ERR_get_error(), NULL)); + if (ctx != NULL) + BN_CTX_free(ctx); + + return result; + } + + ec_point = EC_KEY_get0_public_key(ec_key); + if (ec_point == NULL) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_KEY_get0_public_key: %s", + ERR_error_string(ERR_get_error(), NULL)); + if (ctx != NULL) + BN_CTX_free(ctx); + + return result; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + SEC_LOG_ERROR("BN_CTX_new() failed"); + if (ctx != NULL) + BN_CTX_free(ctx); + + return result; + } + + *xp = BN_new(); + if (*xp == NULL) { + SEC_LOG_ERROR("BN_new() failed"); + if (ctx != NULL) + BN_CTX_free(ctx); + + return result; + } + + if (yp != NULL) { // if caller wants y coordinate returned + *yp = BN_new(); + if (*yp == NULL) { + SEC_LOG_ERROR("BN_new() failed"); + if (ctx != NULL) + BN_CTX_free(ctx); + + return result; + } + } + + if (keyTypep != NULL) // if caller wants key type returned + { + *keyTypep = SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + } + + // Get the X coordinate and optionally the Y coordinate + if (EC_POINT_get_affine_coordinates_GFp(group, ec_point, *xp, yp != NULL ? *yp : NULL, ctx) != 1) { + BN_clear_free(*xp); + if (yp != NULL) + BN_clear_free(*yp); + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_POINT_get_affine_coordinates_GFp: %s", + ERR_error_string(ERR_get_error(), NULL)); + if (ctx != NULL) + BN_CTX_free(ctx); + + return result; + } + + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_SUCCESS; +} + +static EC_KEY* SecUtils_ECCFromDERPub(const SEC_BYTE* der, SEC_SIZE der_len) { + const unsigned char* p = (const unsigned char*) der; + EC_KEY* ec_key = NULL; + + ec_key = d2i_EC_PUBKEY(&ec_key, &p, der_len); + + if (ec_key == NULL) { + SEC_LOG_ERROR("Invalid ECC key container"); + return NULL; + } + + return ec_key; +} + +Sec_Result Pubops_VerifyX509WithPubEcc(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_ECCRawPublicKey* pub) { + X509* x509 = SecCertificate_DerToX509(cert, cert_len); + Sec_Result result = SEC_RESULT_FAILURE; + + if (x509 == NULL) { + SEC_LOG_ERROR("SecCertificate_DerToX509 failed"); + SEC_X509_FREE(x509); + return result; + } + + if (SecUtils_VerifyX509WithRawECCPublicKey(x509, pub) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_SecUtils_VerifyX509WithRawECCPublicKey failed"); + SEC_X509_FREE(x509); + return result; + } + + SEC_X509_FREE(x509); + return SEC_RESULT_SUCCESS; +} + +Sec_Result Pubops_ExtractRSAPubFromX509Der(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_RSARawPublicKey* pub) { + X509* x509 = SecCertificate_DerToX509(cert, cert_len); + EVP_PKEY* evp_key = NULL; + RSA* rsa = NULL; + Sec_Result result = SEC_RESULT_FAILURE; + + if (x509 == NULL) { + SEC_LOG_ERROR("SecCertificate_DerToX509 failed"); + SEC_X509_FREE(x509); + SEC_EVPPKEY_FREE(evp_key); + SEC_RSA_FREE(rsa); + return result; + } + + evp_key = X509_get_pubkey(x509); + if (evp_key == NULL) { + SEC_LOG_ERROR("%s", ERR_error_string(ERR_get_error(), NULL)); + SEC_X509_FREE(x509); + SEC_EVPPKEY_FREE(evp_key); + SEC_RSA_FREE(rsa); + return result; + } + + rsa = EVP_PKEY_get1_RSA(evp_key); + if (rsa == NULL) { + SEC_X509_FREE(x509); + SEC_EVPPKEY_FREE(evp_key); + SEC_RSA_FREE(rsa); + return result; + } + + Sec_Uint32ToBEBytes(RSA_size(rsa), pub->modulus_len_be); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SecUtils_BigNumToBuffer(rsa->n, pub->n, Sec_BEBytesToUint32(pub->modulus_len_be)); + SecUtils_BigNumToBuffer(rsa->e, pub->e, 4); +#else + SecUtils_BigNumToBuffer(RSA_get0_n(rsa), pub->n, Sec_BEBytesToUint32(pub->modulus_len_be)); + SecUtils_BigNumToBuffer(RSA_get0_e(rsa), pub->e, 4); +#endif + + SEC_X509_FREE(x509); + SEC_EVPPKEY_FREE(evp_key); + SEC_RSA_FREE(rsa); + return SEC_RESULT_SUCCESS; +} + +Sec_Result Pubops_ExtractECCPubFromX509Der(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_ECCRawPublicKey* pub) { + X509* x509 = SecCertificate_DerToX509(cert, cert_len); + Sec_Result result = SEC_RESULT_FAILURE; + + if (x509 == NULL) { + SEC_LOG_ERROR("SecCertificate_DerToX509 failed"); + SEC_X509_FREE(x509); + return result; + } + + EVP_PKEY* evp_key = X509_get_pubkey(x509); + if (evp_key == NULL) { + SEC_LOG_ERROR("%s", ERR_error_string(ERR_get_error(), NULL)); + SEC_X509_FREE(x509); + SEC_EVPPKEY_FREE(evp_key); + return result; + } + + EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(evp_key); + if (ec_key == NULL) { + SEC_X509_FREE(x509); + SEC_EVPPKEY_FREE(evp_key); + SEC_ECC_FREE(ec_key); + return result; + } + + BIGNUM* x = NULL; + BIGNUM* y = NULL; + Sec_KeyType key_type; + if (SecUtils_Extract_EC_KEY_X_Y(ec_key, &x, &y, &key_type) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y failed"); + if (x != NULL) + BN_clear_free(x); + + if (y != NULL) + BN_clear_free(y); + + SEC_X509_FREE(x509); + SEC_EVPPKEY_FREE(evp_key); + SEC_ECC_FREE(ec_key); + return result; + } + + pub->type = key_type; + + Sec_Uint32ToBEBytes(SecKey_GetKeyLenForKeyType(key_type), pub->key_len); + SecUtils_BigNumToBuffer(x, pub->x, Sec_BEBytesToUint32(pub->key_len)); + SecUtils_BigNumToBuffer(y, pub->y, Sec_BEBytesToUint32(pub->key_len)); + + if (x != NULL) + BN_clear_free(x); + + if (y != NULL) + BN_clear_free(y); + + SEC_X509_FREE(x509); + SEC_EVPPKEY_FREE(evp_key); + SEC_ECC_FREE(ec_key); + return SEC_RESULT_SUCCESS; +} + +static RSA* SecUtils_RSAFromDERPub(const SEC_BYTE* der, SEC_SIZE der_len) { + const unsigned char* p = (const unsigned char*) der; + RSA* rsa = NULL; + + rsa = d2i_RSAPublicKey(&rsa, &p, der_len); + + if (!rsa) { + p = (const unsigned char*) der; + rsa = d2i_RSA_PUBKEY(&rsa, &p, der_len); + } + + if (!rsa) { + SEC_LOG_ERROR("Invalid RSA key container"); + return rsa; + } + + return rsa; +} + +Sec_Result Pubops_VerifyX509WithPubRsa(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_RSARawPublicKey* pub) { + X509* x509 = SecCertificate_DerToX509(cert, cert_len); + Sec_Result result = SEC_RESULT_FAILURE; + + if (x509 == NULL) { + SEC_LOG_ERROR("SecCertificate_DerToX509 failed"); + SEC_X509_FREE(x509); + return result; + } + + if (SecUtils_VerifyX509WithRawRSAPublicKey(x509, pub) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_SecUtils_VerifyX509WithRawRSAPublicKey failed"); + SEC_X509_FREE(x509); + return result; + } + + SEC_X509_FREE(x509); + return SEC_RESULT_SUCCESS; +} + +Sec_Result Pubops_ExtractRSAPubFromPUBKEYDer(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_RSARawPublicKey* pub) { + RSA* rsa = SecUtils_RSAFromDERPub(cert, cert_len); + Sec_Result result = SEC_RESULT_FAILURE; + if (rsa == NULL) { + SEC_LOG_ERROR("_SecUtils_RSAFromDERPub failed"); + SEC_RSA_FREE(rsa); + return result; + } + + Sec_Uint32ToBEBytes(RSA_size(rsa), pub->modulus_len_be); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SecUtils_BigNumToBuffer(rsa->n, pub->n, Sec_BEBytesToUint32(pub->modulus_len_be)); + SecUtils_BigNumToBuffer(rsa->e, pub->e, 4); +#else + SecUtils_BigNumToBuffer(RSA_get0_n(rsa), pub->n, Sec_BEBytesToUint32(pub->modulus_len_be)); + SecUtils_BigNumToBuffer(RSA_get0_e(rsa), pub->e, 4); +#endif + + SEC_RSA_FREE(rsa); + return SEC_RESULT_SUCCESS; +} + +Sec_Result Pubops_ExtractECCPubFromPUBKEYDer(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_ECCRawPublicKey* pub) { + EC_KEY* ec_key = SecUtils_ECCFromDERPub(cert, cert_len); + Sec_Result result = SEC_RESULT_FAILURE; + if (ec_key == NULL) { + SEC_LOG_ERROR("_SecUtils_ECCFromDERPub failed"); + SEC_ECC_FREE(ec_key); + return result; + } + + BIGNUM* x = NULL; + BIGNUM* y = NULL; + Sec_KeyType key_type; + if (SecUtils_Extract_EC_KEY_X_Y(ec_key, &x, &y, &key_type) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y failed"); + if (x != NULL) + BN_clear_free(x); + + if (y != NULL) + BN_clear_free(y); + + SEC_ECC_FREE(ec_key); + return result; + } + + pub->type = key_type; + + Sec_Uint32ToBEBytes(SecKey_GetKeyLenForKeyType(key_type), pub->key_len); + SecUtils_BigNumToBuffer(x, pub->x, Sec_BEBytesToUint32(pub->key_len)); + SecUtils_BigNumToBuffer(y, pub->y, Sec_BEBytesToUint32(pub->key_len)); + + if (x != NULL) + BN_clear_free(x); + + if (y != NULL) + BN_clear_free(y); + + SEC_ECC_FREE(ec_key); + return SEC_RESULT_SUCCESS; +} + +Sec_Result Pubops_VerifyWithPubRsa(RSA* rsa, Sec_SignatureAlgorithm alg, SEC_BYTE* digest, SEC_SIZE digest_len, + SEC_BYTE* sig, SEC_SIZE sig_len, int salt_len) { + if (rsa == NULL) { + SEC_LOG_ERROR("_SecUtils_RSAFromPubBinary failed"); + return SEC_RESULT_FAILURE; + } + + int expected_sign_len = RSA_size(rsa); + if (sig_len != expected_sign_len) { + SEC_LOG_ERROR("Invalid signature size %d, expected %d", sig_len, expected_sign_len); + return SEC_RESULT_FAILURE; + } + + Sec_DigestAlgorithm digest_alg = SecSignature_GetDigestAlgorithm(alg); + + if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST) { + //pss padding + SEC_BYTE decrypted[SEC_RSA_KEY_MAX_LEN]; + if (RSA_public_decrypt(RSA_size(rsa), sig, decrypted, rsa, RSA_NO_PADDING) == -1) { + SEC_LOG_ERROR("RSA_public_decrypt failed with error %s\n", ERR_error_string(ERR_get_error(), NULL)); + return SEC_RESULT_FAILURE; + } + + if (salt_len < 0) { + salt_len = (digest_alg == SEC_DIGESTALGORITHM_SHA1) ? 20 : 32; + } + + /* verify the data */ + int openssl_res = RSA_verify_PKCS1_PSS(rsa, digest, + (digest_alg == SEC_DIGESTALGORITHM_SHA1) ? EVP_sha1() : EVP_sha256(), + decrypted, salt_len); + if (openssl_res != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("RSA_verify_PKCS1_PSS failed"); + SEC_LOG_ERROR("%s", ERR_error_string(ERR_get_error(), NULL)); + return SEC_RESULT_FAILURE; + } + } else { + int openssl_res = RSA_verify((digest_alg == SEC_DIGESTALGORITHM_SHA1) ? NID_sha1 : NID_sha256, digest, + digest_len, sig, sig_len, rsa); + if (openssl_res != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("RSA_verify failed"); + SEC_LOG_ERROR("%s", ERR_error_string(ERR_get_error(), NULL)); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result Pubops_VerifyWithPubEcc(EC_KEY* ec_key, Sec_SignatureAlgorithm alg, SEC_BYTE* digest, SEC_SIZE digest_len, + SEC_BYTE* sig, SEC_SIZE sig_len) { + if (ec_key == NULL) { + SEC_LOG_ERROR("_SecUtils_ECCFromPubBinary failed"); + return SEC_RESULT_FAILURE; + } + + int expected_sign_len = 2 * EC_GROUP_get_degree(EC_KEY_get0_group(ec_key)) / 8; + if (sig_len != expected_sign_len) { + SEC_LOG_ERROR("Invalid signature size %d, expected %d", sig_len, expected_sign_len); + return SEC_RESULT_FAILURE; + } + + ECDSA_SIG* esig = ECDSA_SIG_new(); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + BN_bin2bn(&sig[0], SEC_ECC_NISTP256_KEY_LEN, esig->r); + BN_bin2bn(&sig[SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN, esig->s); +#else + BIGNUM* r = BN_new(); + BIGNUM* s = BN_new(); + BN_bin2bn(&sig[0], SEC_ECC_NISTP256_KEY_LEN, r); + BN_bin2bn(&sig[SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN, s); + ECDSA_SIG_set0(esig, r, s); +#endif + int openssl_res = ECDSA_do_verify(digest, (int) digest_len, esig, ec_key); + + // Automatically frees r & s. + ECDSA_SIG_free(esig); + if (openssl_res != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("ECDSA_do_verify failed"); + + if (-1 == openssl_res) { // -1 is not an "error", just a verification failure, so don't log as much + SEC_LOG_ERROR("%s", ERR_error_string(ERR_get_error(), NULL)); + } + + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result Pubops_HMAC(Sec_MacAlgorithm alg, SEC_BYTE* key, SEC_SIZE key_len, SEC_BYTE* input, SEC_SIZE input_len, + SEC_BYTE* mac, SEC_SIZE mac_len) { + switch (alg) { + case SEC_MACALGORITHM_HMAC_SHA1: + case SEC_MACALGORITHM_HMAC_SHA256: { + unsigned int osl_mac_len = mac_len; + if (HMAC(alg == SEC_MACALGORITHM_HMAC_SHA1 ? EVP_sha1() : EVP_sha256(), key, (int) key_len, input, + input_len, mac, &osl_mac_len) == NULL) { + SEC_LOG_ERROR("HMAC failed"); + SEC_LOG_ERROR("%s", ERR_error_string(ERR_get_error(), NULL)); + return SEC_RESULT_FAILURE; + } + + break; + } + + case SEC_MACALGORITHM_CMAC_AES_128: { + CMAC_CTX* cmac_ctx = CMAC_CTX_new(); + + if (CMAC_Init(cmac_ctx, &key[0], key_len, + key_len == SEC_AES_BLOCK_SIZE ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), + NULL) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("Comcast_CMAC_Init failed"); + return SEC_RESULT_FAILURE; + } + + if (CMAC_Update(cmac_ctx, &input[0], input_len) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("CMAC_Update failed"); + CMAC_CTX_free(cmac_ctx); + return SEC_RESULT_FAILURE; + } + + size_t outl = mac_len; + if (CMAC_Final(cmac_ctx, &mac[0], &outl) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("CMAC_Final failed"); + CMAC_CTX_free(cmac_ctx); + return SEC_RESULT_FAILURE; + } + + CMAC_CTX_free(cmac_ctx); + break; + } + + default: + SEC_LOG_ERROR("Unknown algorithm encountered: %d", alg); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} diff --git a/src/sec_adapter_pubops.h b/src/sec_adapter_pubops.h new file mode 100644 index 0000000..038fade --- /dev/null +++ b/src/sec_adapter_pubops.h @@ -0,0 +1,51 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_PUBOPS_H +#define SEC_ADAPTER_PUBOPS_H + +#include "sec_security.h" +#include +#include +#include +#include +#include +#include + +Sec_Result Pubops_VerifyX509WithPubEcc(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_ECCRawPublicKey* pub); + +Sec_Result Pubops_ExtractRSAPubFromX509Der(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_RSARawPublicKey* pub); + +Sec_Result Pubops_ExtractECCPubFromX509Der(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_ECCRawPublicKey* pub); + +Sec_Result Pubops_VerifyX509WithPubRsa(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_RSARawPublicKey* pub); + +Sec_Result Pubops_ExtractRSAPubFromPUBKEYDer(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_RSARawPublicKey* pub); + +Sec_Result Pubops_ExtractECCPubFromPUBKEYDer(SEC_BYTE* cert, SEC_SIZE cert_len, Sec_ECCRawPublicKey* pub); + +Sec_Result Pubops_VerifyWithPubRsa(RSA* rsa, Sec_SignatureAlgorithm alg, SEC_BYTE* digest, SEC_SIZE digest_len, + SEC_BYTE* sig, SEC_SIZE sig_len, int salt_len); + +Sec_Result Pubops_VerifyWithPubEcc(EC_KEY* ec_key, Sec_SignatureAlgorithm alg, SEC_BYTE* digest, SEC_SIZE digest_len, + SEC_BYTE* sig, SEC_SIZE sig_len); + +Sec_Result Pubops_HMAC(Sec_MacAlgorithm alg, SEC_BYTE* key, SEC_SIZE key_len, SEC_BYTE* input, SEC_SIZE input_len, + SEC_BYTE* mac, SEC_SIZE mac_len); + +#endif // SEC_ADAPTER_PUBOPS_H diff --git a/src/sec_adapter_random.c b/src/sec_adapter_random.c new file mode 100644 index 0000000..8ebdc3b --- /dev/null +++ b/src/sec_adapter_random.c @@ -0,0 +1,104 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sa.h" +#include "sec_adapter_processor.h" +#include "sec_security.h" + +struct Sec_RandomHandle_struct { + Sec_ProcessorHandle* processorHandle; +}; + +/** + * @brief Obtain a handle to the random number generator. + * + * @param processorHandle secure processor handle. + * @param algorithm random number algorithm to use. + * @param randomHandle output handle for the random number generator. + * + * @return The status of the operation. + */ +Sec_Result SecRandom_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_RandomAlgorithm algorithm, + Sec_RandomHandle** randomHandle) { + CHECK_PROCHANDLE(processorHandle) + + *randomHandle = malloc(sizeof(Sec_RandomHandle)); + if (*randomHandle == NULL) + return SEC_RESULT_FAILURE; + + (*randomHandle)->processorHandle = processorHandle; + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Generate random data. + * + * @param randomHandle random number generator handle. + * @param output pointer to the output buffer where the random data will be stored. + * @param outputSize the size of the output buffer. + * + * @return The status of the operation. + */ +Sec_Result SecRandom_Process(Sec_RandomHandle* randomHandle, SEC_BYTE* output, SEC_SIZE outputSize) { + CHECK_HANDLE(randomHandle) + int status = sa_crypto_random(output, outputSize); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Release the random object. + * + * @param randomHandle random handle. + * + * @return The status of the operation. + */ +Sec_Result SecRandom_Release(Sec_RandomHandle* randomHandle) { + SEC_FREE(randomHandle); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Utility function for filling out a random value. + * + * @param proc secure processor handle. + * @param alg random algorithm to use. + * @param output output buffer where the random value will be written. + * @param output_len number of bytes written to the output buffer. + * + * @return status of the operation. + */ +Sec_Result SecRandom_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_RandomAlgorithm alg, SEC_BYTE* output, + SEC_SIZE output_len) { + Sec_Result result; + Sec_RandomHandle* randomHandle = NULL; + + result = SecRandom_GetInstance(processorHandle, alg, &randomHandle); + if (result != SEC_RESULT_SUCCESS) + return result; + + result = SecRandom_Process(randomHandle, output, output_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecRandom_Process failed"); + SecRandom_Release(randomHandle); + return result; + } + + SecRandom_Release(randomHandle); + return result; +} diff --git a/src/sec_adapter_signature.c b/src/sec_adapter_signature.c new file mode 100644 index 0000000..f6372ef --- /dev/null +++ b/src/sec_adapter_signature.c @@ -0,0 +1,545 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_processor.h" +#include "sec_adapter_pubops.h" +#include "sec_adapter_utils.h" +#include "sec_security.h" +#include +#include + +struct Sec_SignatureHandle_struct { + Sec_ProcessorHandle* processorHandle; + Sec_SignatureAlgorithm algorithm; + Sec_SignatureMode mode; + Sec_KeyHandle* keyHandle; +}; + +static Sec_KeyContainer get_rsa_public_key_container_for_byte_length(SEC_BYTE* numBytes); + +/** + * @brief Obtain a handle to the signature calculator. + * + * @param processorHandle secure processor handle. + * @param algorithm signing algorithm. + * @param mode signing mode. + * @param keyHandle key used for signing operations. + * @param signatureHandle output signature handle. + * + * @return The status of the operation. + */ +Sec_Result SecSignature_GetInstance(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, Sec_KeyHandle* keyHandle, Sec_SignatureHandle** signatureHandle) { + CHECK_PROCHANDLE(processorHandle) + + Sec_KeyType key_type = SecKey_GetKeyType(keyHandle); + if (SecSignature_IsValidKey(key_type, algorithm, mode) != SEC_RESULT_SUCCESS) + return SEC_RESULT_INVALID_PARAMETERS; + + *signatureHandle = calloc(1, sizeof(Sec_SignatureHandle)); + if (*signatureHandle == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + (*signatureHandle)->processorHandle = processorHandle; + (*signatureHandle)->algorithm = algorithm; + (*signatureHandle)->mode = mode; + (*signatureHandle)->keyHandle = keyHandle; + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Sign/Verify Signature of the input data. + * + * @param signatureHandle signature handle. + * @param input pointer to the input buffer whose signature we are generating/verifying. + * @param inputSize the length of the input. + * @param signature buffer where signature is/will be stored. + * @param signatureSize output variable that will be set to the signature size. + * + * @return The status of the operation. + */ +Sec_Result SecSignature_Process(Sec_SignatureHandle* signatureHandle, SEC_BYTE* input, SEC_SIZE inputSize, + SEC_BYTE* signature, SEC_SIZE* signatureSize) { + CHECK_HANDLE(signatureHandle) + + if (signatureHandle->mode == SEC_SIGNATUREMODE_SIGN) { + sa_signature_algorithm signature_algorithm; + sa_sign_parameters_rsa_pss rsa_pss_parameters; + sa_sign_parameters_rsa_pkcs1v15 rsa_pkcs1v15_parameters; + sa_sign_parameters_ecdsa ecdsa_parameters; + void* parameters = NULL; + switch (signatureHandle->algorithm) { + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS: + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST: + signature_algorithm = SA_SIGNATURE_ALGORITHM_RSA_PKCS1V15; + rsa_pkcs1v15_parameters.digest_algorithm = SA_DIGEST_ALGORITHM_SHA1; + rsa_pkcs1v15_parameters.precomputed_digest = + (signatureHandle->algorithm == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST); + parameters = &rsa_pkcs1v15_parameters; + break; + + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS: + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST: + signature_algorithm = SA_SIGNATURE_ALGORITHM_RSA_PSS; + rsa_pss_parameters.digest_algorithm = SA_DIGEST_ALGORITHM_SHA1; + rsa_pss_parameters.precomputed_digest = + (signatureHandle->algorithm == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST); + rsa_pss_parameters.salt_length = SHA_DIGEST_LENGTH; + parameters = &rsa_pss_parameters; + break; + + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST: + signature_algorithm = SA_SIGNATURE_ALGORITHM_RSA_PKCS1V15; + rsa_pkcs1v15_parameters.digest_algorithm = SA_DIGEST_ALGORITHM_SHA256; + rsa_pkcs1v15_parameters.precomputed_digest = + (signatureHandle->algorithm == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST); + parameters = &rsa_pkcs1v15_parameters; + break; + + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST: + signature_algorithm = SA_SIGNATURE_ALGORITHM_RSA_PSS; + rsa_pss_parameters.digest_algorithm = SA_DIGEST_ALGORITHM_SHA256; + rsa_pss_parameters.precomputed_digest = + (signatureHandle->algorithm == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST); + rsa_pss_parameters.salt_length = SHA256_DIGEST_LENGTH; + parameters = &rsa_pss_parameters; + break; + + case SEC_SIGNATUREALGORITHM_ECDSA_NISTP256: + case SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST: + signature_algorithm = SA_SIGNATURE_ALGORITHM_ECDSA; + ecdsa_parameters.digest_algorithm = SA_DIGEST_ALGORITHM_SHA256; + ecdsa_parameters.precomputed_digest = + (signatureHandle->algorithm == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST); + parameters = &ecdsa_parameters; + break; + + default: + return SEC_RESULT_INVALID_PARAMETERS; + } + + size_t out_length = 0; + const Sec_Key* key = get_key(signatureHandle->keyHandle); + // Get the out_length since it is not given to us. + sa_status status = sa_crypto_sign(NULL, &out_length, signature_algorithm, key->handle, input, inputSize, + parameters); + CHECK_STATUS(status) + status = sa_crypto_sign(signature, &out_length, signature_algorithm, key->handle, input, inputSize, parameters); + CHECK_STATUS(status) + *signatureSize = out_length; + } else { + Sec_Result result; + SEC_BYTE digest[SEC_DIGEST_MAX_LEN]; + SEC_SIZE digest_len; + if (SecSignature_IsDigest(signatureHandle->algorithm)) { + if (SecDigest_GetDigestLenForAlgorithm(SecSignature_GetDigestAlgorithm(signatureHandle->algorithm)) != + inputSize) { + SEC_LOG_ERROR("Invalid input length"); + return SEC_RESULT_FAILURE; + } + + memcpy(digest, input, inputSize); + digest_len = inputSize; + } else { + /* calculate digest */ + result = SecDigest_SingleInput(signatureHandle->processorHandle, + SecSignature_GetDigestAlgorithm(signatureHandle->algorithm), input, + inputSize, digest, &digest_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_SingleInput failed"); + return result; + } + } + + const Sec_Key* key = get_key(signatureHandle->keyHandle); + if (SecSignature_IsRsa(signatureHandle->algorithm)) { + result = Pubops_VerifyWithPubRsa(key->rsa, signatureHandle->algorithm, + digest, digest_len, signature, *signatureSize, -1); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Pubops_VerifyWithPubRsa failed"); + return SEC_RESULT_VERIFICATION_FAILED; + } + } else if (SecSignature_IsEcc(signatureHandle->algorithm)) { + if (*signatureSize != SecSignature_GetEccSignatureSize(signatureHandle->algorithm)) { + SEC_LOG_ERROR("Incorrect ECC signature size"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType key_type = SecKey_GetKeyType(signatureHandle->keyHandle); + EC_KEY* ec_key = NULL; + if (SecKey_IsPubEcc(key_type)) { + ec_key = EC_KEY_new(); + EC_KEY_copy(ec_key, key->ec_key); + } else { + Sec_ECCRawPublicKey public_key; + result = SecKey_ExtractECCPublicKey(signatureHandle->keyHandle, &public_key); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_SingleInput failed"); + SEC_ECC_FREE(ec_key); + return result; + } + + ec_key = SecUtils_ECCFromPubBinary(&public_key); + } + + result = Pubops_VerifyWithPubEcc(ec_key, signatureHandle->algorithm, + digest, digest_len, signature, *signatureSize); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Pubops_VerifyWithPubEcc failed"); + SEC_ECC_FREE(ec_key); + return SEC_RESULT_VERIFICATION_FAILED; + } + + SEC_ECC_FREE(ec_key); + } else { + SEC_LOG_ERROR("Unimplemented signature algorithm for verify"); + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Release the signature object. + * + * @param signatureHandle cipher handle. + * + * @return The status of the operation. + */ +Sec_Result SecSignature_Release(Sec_SignatureHandle* signatureHandle) { + CHECK_HANDLE(signatureHandle) + SEC_FREE(signatureHandle); + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Checks whether the passed in key is valid for a chosen signing algorithm and mode. + * + * @param key_type key type. + * @param algorithm signing algorithm. + * @param mode signing mode. + * + * @return status of the operation. + */ +Sec_Result SecSignature_IsValidKey(Sec_KeyType key_type, + Sec_SignatureAlgorithm algorithm, Sec_SignatureMode mode) { + switch (algorithm) { + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS: + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST: + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS: + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST: + if (mode == SEC_SIGNATUREMODE_SIGN) { + if (key_type == SEC_KEYTYPE_RSA_1024 || key_type == SEC_KEYTYPE_RSA_2048 || + key_type == SEC_KEYTYPE_RSA_3072) + return SEC_RESULT_SUCCESS; + + return SEC_RESULT_FAILURE; + } else { + if (key_type == SEC_KEYTYPE_RSA_1024 || key_type == SEC_KEYTYPE_RSA_2048 || + key_type == SEC_KEYTYPE_RSA_3072 || key_type == SEC_KEYTYPE_RSA_1024_PUBLIC || + key_type == SEC_KEYTYPE_RSA_2048_PUBLIC || key_type == SEC_KEYTYPE_RSA_3072_PUBLIC) + return SEC_RESULT_SUCCESS; + + return SEC_RESULT_FAILURE; + } + + case SEC_SIGNATUREALGORITHM_ECDSA_NISTP256: + case SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST: + if (mode == SEC_SIGNATUREMODE_SIGN) { + if (key_type == SEC_KEYTYPE_ECC_NISTP256) + return SEC_RESULT_SUCCESS; + + return SEC_RESULT_FAILURE; + } else { + if (key_type == SEC_KEYTYPE_ECC_NISTP256 || key_type == SEC_KEYTYPE_ECC_NISTP256_PUBLIC) + return SEC_RESULT_SUCCESS; + + return SEC_RESULT_FAILURE; + } + + default: + return SEC_RESULT_UNIMPLEMENTED_FEATURE; + } +} + +/** + * @brief Returns TRUE if the signature algorithm is an RSA variant. + * + * @param alg signing algorithm. + * + * @return true if RSA. + */ +SEC_BOOL SecSignature_IsRsa(Sec_SignatureAlgorithm alg) { + return alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS || alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS || alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS || alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS || alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST; +} + +/** + * @brief Returns TRUE if the signature algorithm is an ECC variant. + * + * @param alg signing algorithm. + * + * @return true if ECC. + */ +SEC_BOOL SecSignature_IsEcc(Sec_SignatureAlgorithm alg) { + return alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256 || alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST; +} + +/** + * @brief Returns the size of the algorithm's ECC signature. + * + * @param alg signing algorithm. + * + * @return size in bytes or 0 if unsupported algorithm. + */ +SEC_SIZE SecSignature_GetEccSignatureSize(Sec_SignatureAlgorithm alg) { + switch (alg) { + case SEC_SIGNATUREALGORITHM_ECDSA_NISTP256: + case SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST: + return SEC_ECC_NISTP256_KEY_LEN + SEC_ECC_NISTP256_KEY_LEN; + + default: + return 0; + } +} + +/** + * @brief Obtain a digest algorithm used by a specific signing algorithm. + * + * @param alg signing algorithm. + * + * @return digest algorithm used. + */ +Sec_DigestAlgorithm SecSignature_GetDigestAlgorithm(Sec_SignatureAlgorithm alg) { + switch (alg) { + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS: + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST: + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS: + case SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST: + return SEC_DIGESTALGORITHM_SHA1; + + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS: + case SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST: + case SEC_SIGNATUREALGORITHM_ECDSA_NISTP256: + case SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST: + return SEC_DIGESTALGORITHM_SHA256; + + default: + SEC_LOG_ERROR("Unexpected alg encountered: %d", alg); + return SEC_DIGESTALGORITHM_NUM; + } +} + +/** + * @brief Signature util that handles Sec_SignatureHandle generation and release. + * + * @param processorHandle processor handle. + * @param algorithm signing algorithm. + * @param mode signing mode. + * @param keyHandle key used for signing operations. + * @param input pointer to the input buffer whose signature we are generating/verifying. + * @param inputSize the length of the input. + * @param signature buffer where signature is/will be stored. + * @param signatureSize output variable that will be set to the signature size. + * + * @return The status of the operation. + */ +Sec_Result SecSignature_SingleInput(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, Sec_KeyHandle* keyHandle, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* signature, + SEC_SIZE* signatureSize) { + Sec_Result result = SEC_RESULT_FAILURE; + Sec_SignatureHandle* signatureHandle = NULL; + + if (SecSignature_GetInstance(processorHandle, algorithm, mode, keyHandle, &signatureHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_GetInstance failed"); + if (signatureHandle != NULL) + SecSignature_Release(signatureHandle); + + return result; + } + + if (SecSignature_Process(signatureHandle, input, inputSize, signature, signatureSize) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_Process failed"); + if (signatureHandle != NULL) + SecSignature_Release(signatureHandle); + + return result; + } + + if (signatureHandle != NULL) + SecSignature_Release(signatureHandle); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecSignature_SingleInputCert(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, Sec_CertificateHandle* certificateHandle, SEC_BYTE* input, SEC_SIZE inputSize, + SEC_BYTE* signature, SEC_SIZE* signatureSize) { + Sec_KeyHandle* keyHandle = NULL; + Sec_RSARawPublicKey rsa_public_key; + Sec_ECCRawPublicKey ecc_public_key; + CHECK_PROCHANDLE(processorHandle) + + if (mode == SEC_SIGNATUREMODE_SIGN) { // Sanity check: This does not handle SIGN + SEC_LOG_ERROR("SecSignature_SingleInputCert does not support SEC_SIGNATUREMODE_SIGN"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType key_type = SecCertificate_GetKeyType(certificateHandle); + switch (key_type) { + case SEC_KEYTYPE_RSA_1024_PUBLIC: + case SEC_KEYTYPE_RSA_2048_PUBLIC: + case SEC_KEYTYPE_RSA_3072_PUBLIC: + if (SecCertificate_ExtractRSAPublicKey(certificateHandle, &rsa_public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_ExtractRSAPublicKey failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyContainer key_container = get_rsa_public_key_container_for_byte_length( + rsa_public_key.modulus_len_be); + if (SecKey_Provision(processorHandle, SEC_OBJECTID_SIG_FROM_CERT, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + key_container, (SEC_BYTE*) &rsa_public_key, sizeof(rsa_public_key)) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + + case SEC_KEYTYPE_ECC_NISTP256: + if (SecCertificate_ExtractECCPublicKey(certificateHandle, &ecc_public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_ExtractECCPublicKey failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(processorHandle, SEC_OBJECTID_SIG_FROM_CERT, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_KEYCONTAINER_RAW_ECC_NISTP256_PUBLIC, (SEC_BYTE*) &ecc_public_key, + sizeof(ecc_public_key)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + + default: + SEC_LOG_ERROR("SecSignature_SingleInputCert: Unhandled keyType %d", (int) key_type); + return SEC_RESULT_FAILURE; + } + + if (SecKey_GetInstance(processorHandle, SEC_OBJECTID_SIG_FROM_CERT, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + Sec_Result result = SecSignature_SingleInput(processorHandle, algorithm, mode, keyHandle, input, inputSize, + signature, signatureSize); + SecKey_Release(keyHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInput failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecSignature_SingleInputId(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, SEC_OBJECTID id, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* signature, + SEC_SIZE* signatureSize) { + Sec_KeyHandle* keyHandle = NULL; + + if (SecKey_GetInstance(processorHandle, id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + Sec_Result result = SecSignature_SingleInput(processorHandle, algorithm, mode, keyHandle, input, inputSize, + signature, signatureSize); + SecKey_Release(keyHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInput failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecSignature_SingleInputCertId(Sec_ProcessorHandle* processorHandle, Sec_SignatureAlgorithm algorithm, + Sec_SignatureMode mode, SEC_OBJECTID cert_id, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* signature, + SEC_SIZE* signatureSize) { + Sec_CertificateHandle* certificateHandle = NULL; + + if (SecCertificate_GetInstance(processorHandle, cert_id, &certificateHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + Sec_Result result = SecSignature_SingleInputCert(processorHandle, algorithm, mode, certificateHandle, input, + inputSize, signature, signatureSize); + SecCertificate_Release(certificateHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInput failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Check if provided algorithm takes digest as an input. + */ +SEC_BOOL SecSignature_IsDigest(Sec_SignatureAlgorithm alg) { + return alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST || alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST || alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST; +} + +SEC_BOOL SecSignature_IsRsaPss(Sec_SignatureAlgorithm alg) { + return alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS || alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST || alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST; +} + +static Sec_KeyContainer get_rsa_public_key_container_for_byte_length(SEC_BYTE* numBytes) { + switch (Sec_BEBytesToUint32(numBytes)) { + case 128: + return SEC_KEYCONTAINER_RAW_RSA_1024_PUBLIC; + + case 256: + return SEC_KEYCONTAINER_RAW_RSA_2048_PUBLIC; + + case 384: + return SEC_KEYCONTAINER_RAW_RSA_3072_PUBLIC; + + default: + SEC_LOG_ERROR("Invalid numBytes encountered: %d", numBytes); + return SEC_KEYCONTAINER_NUM; + } +} diff --git a/src/sec_adapter_store.c b/src/sec_adapter_store.c new file mode 100644 index 0000000..ddec3a9 --- /dev/null +++ b/src/sec_adapter_store.c @@ -0,0 +1,446 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_store.h" +#include + +#define SEC_STORE_MAC_KEY_INPUT "securestore" \ + "integrity" \ + "hmacSha256" \ + "aes128ecb" \ + "decrypt" + +Sec_Result SecStore_GenerateLadderInputs(Sec_ProcessorHandle* processorHandle, const char* input, const char* input2, + SEC_BYTE* output, SEC_SIZE len) { + Sec_Buffer sec_buf; + SEC_BYTE sec_buf_mem[256]; + SEC_BYTE digest[SEC_DIGEST_MAX_LEN]; + SEC_SIZE digest_len; + SEC_SIZE to_copy; + SEC_SIZE loop = 1; + SEC_BYTE loop_buf[4]; + CHECK_PROCHANDLE(processorHandle) + + SecBuffer_Init(&sec_buf, sec_buf_mem, sizeof(sec_buf_mem)); + + while (len > 0) { + SecBuffer_Reset(&sec_buf); + + Sec_Uint32ToBEBytes(loop, loop_buf); + + if (input != NULL && SEC_RESULT_SUCCESS != SecBuffer_Write(&sec_buf, (SEC_BYTE*) input, strlen(input))) { + SEC_LOG_ERROR("SecBuffer_Write failed"); + return SEC_RESULT_FAILURE; + } + + if (input2 != NULL && SEC_RESULT_SUCCESS != SecBuffer_Write(&sec_buf, (SEC_BYTE*) input2, strlen(input2))) { + SEC_LOG_ERROR("SecBuffer_Write failed"); + return SEC_RESULT_FAILURE; + } + + if (SecBuffer_Write(&sec_buf, loop_buf, sizeof(loop_buf)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBuffer_Write failed"); + return SEC_RESULT_FAILURE; + } + + if (SecDigest_SingleInput(processorHandle, SEC_DIGESTALGORITHM_SHA256, sec_buf.base, sec_buf.written, digest, + &digest_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_SingleInput failed"); + return SEC_RESULT_FAILURE; + } + + to_copy = SEC_MIN(digest_len, len); + memcpy(output, digest, to_copy); + len -= to_copy; + output += to_copy; + + ++loop; + } + + return SEC_RESULT_SUCCESS; +} + +static SEC_SIZE SecStore_CalculatePaddedDataLen(SEC_SIZE dataLen) { + return dataLen + SEC_AES_BLOCK_SIZE - (dataLen % SEC_AES_BLOCK_SIZE); +} + +SecStore_Header* SecStore_GetHeader(void* store) { + return (SecStore_Header*) store; +} + +void* SecStore_GetUserHeader(void* store) { + return (SEC_BYTE*) store + sizeof(SecStore_Header); +} + +static SEC_SIZE SecStore_GetHeaderLen(void* store) { + return Sec_BEBytesToUint32(SecStore_GetHeader(store)->header_len); +} + +SEC_SIZE SecStore_GetDataLen(void* store) { + return Sec_BEBytesToUint32(SecStore_GetHeader(store)->data_len); +} + +static SEC_SIZE SecStore_GetPaddedDataLen(void* store) { + return SecStore_CalculatePaddedDataLen(SecStore_GetDataLen(store)); +} + +static SEC_SIZE SecStore_CalculateStoreLen(SEC_SIZE header_len, SEC_SIZE data_len) { + return header_len + SecStore_CalculatePaddedDataLen(data_len) + SEC_STORE_MAC_LEN + SEC_STORE_IV_LEN; +} + +SEC_SIZE SecStore_CalculateRequiredStoreLen(SEC_SIZE user_header_len, SEC_SIZE data_len) { + return sizeof(SecStore_Header) + user_header_len + SecStore_CalculatePaddedDataLen(data_len) + SEC_STORE_MAC_LEN + + SEC_STORE_IV_LEN; +} + +SEC_SIZE SecStore_GetStoreLen(void* store) { + return SecStore_CalculateStoreLen(SecStore_GetHeaderLen(store), SecStore_GetDataLen(store)); +} + +SEC_SIZE SecStore_GetUserHeaderLen(void* store) { + return SecStore_GetHeaderLen(store) - sizeof(SecStore_Header); +} + +static SEC_BYTE* SecStore_GetMac(void* store) { + return ((SEC_BYTE*) store) + SecStore_GetStoreLen(store) - SEC_STORE_IV_LEN - SEC_STORE_MAC_LEN; +} + +static SEC_BYTE* SecStore_GetIV(void* store) { + return ((SEC_BYTE*) store) + SecStore_GetStoreLen(store) - SEC_STORE_IV_LEN; +} + +static SEC_BYTE* SecStore_GetData(void* store) { + return ((SEC_BYTE*) store) + SecStore_GetHeaderLen(store); +} + +static Sec_Result SecStore_ComputeMacKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID keyId, const char* input, + SEC_BYTE* key, SEC_SIZE key_len) { + SEC_SIZE digest_len; + SEC_SIZE written; + + if (SecDigest_GetDigestLenForAlgorithm(SEC_DIGESTALGORITHM_SHA256) != key_len) { + SEC_LOG_ERROR("Unexpected key_len: %d", key_len); + return SEC_RESULT_FAILURE; + } + + if (SecDigest_SingleInput(processorHandle, SEC_DIGESTALGORITHM_SHA256, (SEC_BYTE*) input, strlen(input), key, + &digest_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_SingleInput failed"); + return SEC_RESULT_FAILURE; + } + + if (SecCipher_SingleInputId(processorHandle, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, keyId, + NULL, key, key_len, key, key_len, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result SecStore_Encrypt(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID keyId, void* store, + SEC_SIZE storeLen) { SEC_SIZE expected_enc_data_len; + SEC_SIZE written; + + if (store == NULL) { + SEC_LOG_ERROR("Null store"); + return SEC_RESULT_FAILURE; + } + + if (storeLen < sizeof(SecStore_Header) || storeLen < SecStore_GetStoreLen(store)) { + SEC_LOG_ERROR("Invalid store length: %d", storeLen); + return SEC_RESULT_FAILURE; + } + + if (!(SEC_STORE_FLAG_IS_ENCRYPTED & SecStore_GetHeader(store)->flags)) { + SEC_LOG_ERROR("Encryption flag is not set"); + return SEC_RESULT_FAILURE; + } + + if (SecRandom_SingleInput(processorHandle, SEC_RANDOMALGORITHM_TRUE, SecStore_GetIV(store), SEC_STORE_IV_LEN) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecRandom_SingleInput failed"); + return SEC_RESULT_FAILURE; + } + + expected_enc_data_len = SecStore_GetPaddedDataLen(store) + SEC_STORE_MAC_LEN; + + if (SecCipher_SingleInputId(processorHandle, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, keyId, + SecStore_GetIV(store), SecStore_GetData(store), expected_enc_data_len, SecStore_GetData(store), + expected_enc_data_len, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + if (written != expected_enc_data_len) { + SEC_LOG_ERROR("Unexpected number of encrypted bytes written"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result SecStore_Decrypt(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID keyId, void* store, + SEC_SIZE storeLen) { + SEC_SIZE expected_enc_data_len; + SEC_SIZE written; + + if (store == NULL) { + SEC_LOG_ERROR("Null store"); + return SEC_RESULT_FAILURE; + } + + if (storeLen < sizeof(SecStore_Header) || storeLen < SecStore_GetStoreLen(store)) { + SEC_LOG_ERROR("Invalid store length: %d", storeLen); + return SEC_RESULT_FAILURE; + } + + if (!(SEC_STORE_FLAG_IS_ENCRYPTED & SecStore_GetHeader(store)->flags)) { + SEC_LOG_ERROR("This store is not encrypted"); + return SEC_RESULT_FAILURE; + } + + expected_enc_data_len = SecStore_GetPaddedDataLen(store) + SEC_STORE_MAC_LEN; + + if (SecCipher_SingleInputId(processorHandle, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, SEC_CIPHERMODE_DECRYPT, keyId, + SecStore_GetIV(store), SecStore_GetData(store), expected_enc_data_len, SecStore_GetData(store), + expected_enc_data_len, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + if (written != expected_enc_data_len) { + SEC_LOG_ERROR("Unexpected number of decrypted bytes written"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecStore_RetrieveData(Sec_ProcessorHandle* processorHandle, SEC_BOOL require_mac, void* user_header, + SEC_SIZE user_header_len, void* data, SEC_SIZE data_len, void* store, SEC_SIZE storeLen) { + Sec_Result result; + + result = SecStore_RetrieveDataWithKey(processorHandle, SEC_OBJECTID_STORE_AES_KEY, SEC_OBJECTID_STORE_MACKEYGEN_KEY, + require_mac, user_header, user_header_len, data, data_len, store, storeLen); + + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_RetrieveDataWithKey failed"); + } + + return result; +} + +Sec_Result SecStore_RetrieveDataWithKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID aesKeyId, + SEC_OBJECTID macGenId, SEC_BOOL require_mac, void* user_header, SEC_SIZE user_header_len, void* data, + SEC_SIZE data_len, void* store, SEC_SIZE storeLen) { + Sec_Result result = SEC_RESULT_FAILURE; + SEC_BYTE mac_key[SEC_STORE_MAC_LEN]; + SEC_BYTE mac[SEC_STORE_MAC_LEN]; + void* copy = NULL; + SEC_BYTE pad[SEC_AES_BLOCK_SIZE]; + CHECK_PROCHANDLE(processorHandle) + + do { + if (store == NULL) { + SEC_LOG_ERROR("Null store"); + break; + } + + if (storeLen < sizeof(SecStore_Header)) { + SEC_LOG_ERROR("Invalid store length: %d", storeLen); + break; + } + + if (memcmp(SEC_STORE_MAGIC, SecStore_GetHeader(store)->store_magic, strlen(SEC_STORE_MAGIC)) != 0) { + SEC_LOG_ERROR("Invalid store magic value"); + break; + } + + if (storeLen < SecStore_GetStoreLen(store)) { + SEC_LOG_ERROR("Invalid store length: %d", storeLen); + break; + } + + /* create a copy of the store that will be decrypted */ + copy = malloc(SecStore_GetStoreLen(store)); + if (copy == NULL) { + SEC_LOG_ERROR("Malloc failed"); + break; + } + memcpy(copy, store, SecStore_GetStoreLen(store)); + + /* decrypt container */ + if (SecStore_GetHeader(copy)->flags & SEC_STORE_FLAG_IS_ENCRYPTED) { + if (SecStore_Decrypt(processorHandle, aesKeyId, copy, SecStore_GetStoreLen(copy)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_Decrypt failed"); + break; + } + } + + /* check padding */ + memset(pad, (int) (SecStore_GetPaddedDataLen(copy) - SecStore_GetDataLen(copy)), sizeof(pad)); + if (Sec_Memcmp(pad, SecStore_GetData(copy) + SecStore_GetDataLen(copy), pad[0]) != 0) { + SEC_LOG_ERROR("Invalid pad value encountered"); + break; + } + + /* mac value */ + if (!(SecStore_GetHeader(copy)->flags & SEC_STORE_FLAG_IS_MACED)) { + if (require_mac) { + SEC_LOG_ERROR("Key container does not have a mac value"); + break; + } + } else { + if (SecStore_ComputeMacKey(processorHandle, macGenId, SEC_STORE_MAC_KEY_INPUT, mac_key, sizeof(mac_key)) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_ComputeMacKey failed"); + break; + } + + result = Pubops_HMAC(SEC_MACALGORITHM_HMAC_SHA256, mac_key, sizeof(mac_key), copy, + SecStore_GetStoreLen(copy) - SEC_STORE_MAC_LEN - SEC_STORE_IV_LEN, mac, SEC_STORE_MAC_LEN); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Pubops_HMAC failed"); + Sec_Memset(mac_key, 0, sizeof(mac_key)); + return SEC_RESULT_FAILURE; + } + + Sec_Memset(mac_key, 0, sizeof(mac_key)); + if (Sec_Memcmp(mac, SecStore_GetMac(copy), SEC_STORE_MAC_LEN) != 0) { + SEC_LOG_ERROR("Mac does not match"); + break; + } + } + + /* get user_header */ + if (user_header != NULL) { + if (user_header_len < SecStore_GetUserHeaderLen(copy)) { + SEC_LOG_ERROR("Output buffer not large enough to hold user_header"); + break; + } + + memcpy(user_header, SecStore_GetUserHeader(copy), SecStore_GetUserHeaderLen(copy)); + } + + /* get data */ + if (data != NULL) { + if (data_len < SecStore_GetDataLen(copy)) { + SEC_LOG_ERROR("Output buffer not large enough to hold data"); + break; + } + + memcpy(data, SecStore_GetData(copy), SecStore_GetDataLen(copy)); + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + Sec_Memset(mac_key, 0, sizeof(mac_key)); + if (copy != NULL) { + Sec_Memset(copy, 0, SecStore_GetStoreLen(store)); + SEC_FREE(copy); + } + + return result; +} + +Sec_Result SecStore_StoreData(Sec_ProcessorHandle* processorHandle, SEC_BOOL encrypt, SEC_BOOL gen_mac, + SEC_BYTE* user_header_magic, void* user_header, SEC_SIZE user_header_len, void* data, SEC_SIZE data_len, + void* store, SEC_SIZE storeLen) { + Sec_Result result; + + result = SecStore_StoreDataWithKey(processorHandle, SEC_OBJECTID_STORE_AES_KEY, SEC_OBJECTID_STORE_MACKEYGEN_KEY, + encrypt, gen_mac, user_header_magic, user_header, user_header_len, data, data_len, store, storeLen); + + if (result != SEC_RESULT_SUCCESS) + SEC_LOG_ERROR("SecStore_StoreDataWithKey failed"); + + return result; +} + +Sec_Result SecStore_StoreDataWithKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID aesKeyId, SEC_OBJECTID macGenId, + SEC_BOOL encrypt, SEC_BOOL gen_mac, SEC_BYTE* user_header_magic, void* user_header, SEC_SIZE user_header_len, + void* data, SEC_SIZE data_len, void* store, SEC_SIZE storeLen) { + SecStore_Header* header = NULL; + SEC_BYTE mac_key[SEC_STORE_MAC_LEN]; + SEC_BYTE pad; + CHECK_PROCHANDLE(processorHandle) + + if (store == NULL) { + SEC_LOG_ERROR("Null store"); + return SEC_RESULT_FAILURE; + } + + if (storeLen < SecStore_CalculateStoreLen(sizeof(SecStore_Header) + user_header_len, data_len)) { + SEC_LOG_ERROR("Invalid store length: %d", storeLen); + return SEC_RESULT_FAILURE; + } + + header = (SecStore_Header*) store; + + /* fill header */ + memset(header, 0, sizeof(SecStore_Header)); + memcpy(header->store_magic, SEC_STORE_MAGIC, strlen(SEC_STORE_MAGIC)); + if (gen_mac) + header->flags |= SEC_STORE_FLAG_IS_MACED; + + if (encrypt) + header->flags |= SEC_STORE_FLAG_IS_ENCRYPTED; + + Sec_Uint32ToBEBytes(data_len, header->data_len); + Sec_Uint32ToBEBytes(sizeof(SecStore_Header) + user_header_len, header->header_len); + if (user_header_magic != NULL) + memcpy(header->user_header_magic, user_header_magic, sizeof(header->user_header_magic)); + + /* store user header */ + memcpy(SecStore_GetUserHeader(store), user_header, user_header_len); + + /* store data */ + memcpy(SecStore_GetData(store), data, data_len); + + /* pad data */ + pad = SecStore_GetPaddedDataLen(store) - SecStore_GetDataLen(store); + memset(SecStore_GetData(store) + data_len, pad, pad); + + if (gen_mac) { + /* calc mac */ + if (SecStore_ComputeMacKey(processorHandle, macGenId, SEC_STORE_MAC_KEY_INPUT, mac_key, sizeof(mac_key)) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_ComputeMacKey failed"); + return SEC_RESULT_FAILURE; + } + + if (Pubops_HMAC(SEC_MACALGORITHM_HMAC_SHA256, mac_key, sizeof(mac_key), store, + SecStore_GetStoreLen(store) - SEC_STORE_MAC_LEN - SEC_STORE_IV_LEN, SecStore_GetMac(store), + SEC_STORE_MAC_LEN) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Pubops_HMAC failed"); + Sec_Memset(mac_key, 0, sizeof(mac_key)); + return SEC_RESULT_FAILURE; + } + + Sec_Memset(mac_key, 0, sizeof(mac_key)); + } + + if (encrypt && SEC_RESULT_SUCCESS != SecStore_Encrypt(processorHandle, aesKeyId, store, storeLen)) { + SEC_LOG_ERROR("SecStore_Encrypt failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} diff --git a/src/sec_adapter_store.h b/src/sec_adapter_store.h new file mode 100644 index 0000000..6813731 --- /dev/null +++ b/src/sec_adapter_store.h @@ -0,0 +1,119 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_STORE_H +#define SEC_ADAPTER_STORE_H + +#include "sec_adapter_processor.h" +#include "sec_adapter_pubops.h" + +#ifdef __cplusplus +#include +#include +extern "C" { +#else +#include +#include +#endif + +/** + * Secure store structure + * + * |----------------------|--------- + * | | Mandatory | Signed + * | Header |-----------| + * | | User def | + * ----------|----------------------| + * Encrypted | Data | + * |----------------------| + * | Padding | + * |----------------------|--------- + * | Mac | + * ----------|----------------------| + * | IV | + * |----------------------| + */ + +#define SEC_STORE_FLAG_IS_ENCRYPTED 0x01 +#define SEC_STORE_FLAG_IS_MACED 0x02 +#define SEC_STORE_MAC_LEN 32 +#define SEC_STORE_IV_LEN 16 +#define SEC_STORE_MAGIC "SECSTOR1" + +#define SEC_STORE_AES_LADDER_INPUT "securestore" \ + "encryption" \ + "aes128" \ + "vendor128" +#define SEC_STORE_MAC_LADDER_INPUT "securestore" \ + "mackeygen" \ + "aes128" \ + "vendor128" + +#define SEC_STORE_USERHEADERMAGIC_LEN 4 + +typedef struct { + /* fixed value 'SECSTOR' + ver */ + uint8_t store_magic[8]; + + /* header length - including user defined */ + uint8_t header_len[4]; + + /* data length (without padding) */ + uint8_t data_len[4]; + + /* user header magic */ + uint8_t user_header_magic[SEC_STORE_USERHEADERMAGIC_LEN]; + + /* reserved */ + uint8_t reserved[3]; + + /* flags */ + uint8_t flags; +} SecStore_Header; + +Sec_Result SecStore_GenerateLadderInputs(Sec_ProcessorHandle* processorHandle, const char* input, const char* input2, + SEC_BYTE* output, SEC_SIZE len); + +Sec_Result SecStore_RetrieveDataWithKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID aesKeyId, + SEC_OBJECTID macGenId, SEC_BOOL require_mac, void* user_header, SEC_SIZE user_header_len, void* data, + SEC_SIZE data_len, void* store, SEC_SIZE storeLen); + +Sec_Result SecStore_StoreDataWithKey(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID aesKeyId, SEC_OBJECTID macGenId, + SEC_BOOL encrypt, SEC_BOOL gen_mac, SEC_BYTE* user_header_magic, void* user_header, SEC_SIZE user_header_len, + void* data, SEC_SIZE data_len, void* store, SEC_SIZE storeLen); + +Sec_Result SecStore_StoreData(Sec_ProcessorHandle* processorHandle, SEC_BOOL encrypt, SEC_BOOL gen_mac, + SEC_BYTE* user_header_magic, void* user_header, SEC_SIZE user_header_len, void* data, SEC_SIZE data_len, + void* store, SEC_SIZE storeLen); + +SEC_SIZE SecStore_GetStoreLen(void* store); + +Sec_Result SecStore_RetrieveData(Sec_ProcessorHandle* processorHandle, SEC_BOOL require_mac, void* user_header, + SEC_SIZE user_header_len, void* data, SEC_SIZE data_len, void* store, SEC_SIZE storeLen); + +SEC_SIZE SecStore_GetDataLen(void* store); + +void* SecStore_GetUserHeader(void* store); + +SecStore_Header* SecStore_GetHeader(void* store); + +#ifdef __cplusplus +} +#endif + +#endif // SEC_ADAPTER_STORE_H diff --git a/src/sec_adapter_svp.c b/src/sec_adapter_svp.c new file mode 100644 index 0000000..41946c4 --- /dev/null +++ b/src/sec_adapter_svp.c @@ -0,0 +1,161 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_svp.h" + +// Deprecated +Sec_Result Sec_OpaqueBufferMalloc(SEC_SIZE bufLength, void** handle, void* params) { + return SecOpaqueBuffer_Malloc(bufLength, (Sec_OpaqueBufferHandle**) handle); +} + +Sec_Result SecOpaqueBuffer_Malloc(SEC_SIZE bufLength, Sec_OpaqueBufferHandle** handle) { + if (bufLength == 0) { + SEC_LOG_ERROR("Argument `length' has value of 0"); + return SEC_RESULT_FAILURE; + } + if (handle == NULL) { + SEC_LOG_ERROR("Argument `handle' has value of null"); + return SEC_RESULT_FAILURE; + } + + *handle = (Sec_OpaqueBufferHandle*) calloc(1, sizeof(Sec_OpaqueBufferHandle)); + if (*handle == NULL) { + SEC_LOG_ERROR("Calloc failed"); + return SEC_RESULT_FAILURE; + } + + sa_status status = sa_svp_buffer_alloc(&(*handle)->svp_buffer, bufLength); + if (status != SA_STATUS_OK) { + free(*handle); + CHECK_STATUS(status) + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result Sec_OpaqueBufferWrite(Sec_OpaqueBufferHandle* opaqueBufferHandle, SEC_SIZE offset, void* data, + SEC_SIZE length) { + return SecOpaqueBuffer_Write(opaqueBufferHandle, offset, data, length); +} + +Sec_Result SecOpaqueBuffer_Write(Sec_OpaqueBufferHandle* opaqueBufferHandle, SEC_SIZE offset, SEC_BYTE* data, + SEC_SIZE length) { + if (opaqueBufferHandle == NULL) { + SEC_LOG_ERROR("Invalid handle"); + return SEC_RESULT_INVALID_HANDLE; + } + + if (data == NULL) { + SEC_LOG_ERROR("Argument `data' has value of null"); + return SEC_RESULT_FAILURE; + } + + if (length == 0) { + SEC_LOG_ERROR("Argument `length' has value of 0"); + return SEC_RESULT_FAILURE; + } + + size_t out_offset = offset; + sa_status status = sa_svp_buffer_write((*opaqueBufferHandle).svp_buffer, &out_offset, data, length); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +Sec_Result Sec_OpaqueBufferFree(Sec_OpaqueBufferHandle* opaqueBufferHandle, void* params) { + return SecOpaqueBuffer_Free(opaqueBufferHandle); +} + +Sec_Result SecOpaqueBuffer_Free(Sec_OpaqueBufferHandle* opaqueBufferHandle) { + if (opaqueBufferHandle != NULL) { + + sa_svp_buffer_free(opaqueBufferHandle->svp_buffer); + SEC_FREE(opaqueBufferHandle); + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecOpaqueBuffer_Copy(Sec_OpaqueBufferHandle* outOpaqueBufferHandle, SEC_SIZE out_offset, + Sec_OpaqueBufferHandle* inOpaqueBufferHandle, SEC_SIZE in_offset, SEC_SIZE num_to_copy) { + if (outOpaqueBufferHandle == NULL || inOpaqueBufferHandle == NULL) { + SEC_LOG_ERROR("Null pointer arg encountered"); + return SEC_RESULT_FAILURE; + } + + size_t out_off = out_offset; + size_t in_off = in_offset; + sa_status status = sa_svp_buffer_copy(outOpaqueBufferHandle->svp_buffer, &out_off, inOpaqueBufferHandle->svp_buffer, + &in_off, num_to_copy); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecOpaqueBuffer_Release(Sec_OpaqueBufferHandle* opaqueBufferHandle, Sec_ProtectedMemHandle** svpHandle) { + if (svpHandle == NULL || opaqueBufferHandle == NULL) { + SEC_LOG_ERROR("Null pointer arg encountered"); + return SEC_RESULT_FAILURE; + } + + size_t out_length; + sa_status status = sa_svp_buffer_release(svpHandle, &out_length, opaqueBufferHandle->svp_buffer); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecOpaqueBuffer_Check(Sec_DigestAlgorithm digestAlgorithm, Sec_OpaqueBufferHandle* opaqueBufferHandle, + SEC_SIZE length, SEC_BYTE* expected, SEC_SIZE expectedLength) { + if (opaqueBufferHandle == NULL) { + SEC_LOG_ERROR("Null pointer arg encountered"); + return SEC_RESULT_FAILURE; + } + + if (expected == NULL) { + SEC_LOG_ERROR("Null pointer arg encountered"); + return SEC_RESULT_FAILURE; + } + + sa_digest_algorithm algorithm; + switch (digestAlgorithm) { + case SEC_DIGESTALGORITHM_SHA1: + algorithm = SA_DIGEST_ALGORITHM_SHA1; + break; + + case SEC_DIGESTALGORITHM_SHA256: + algorithm = SA_DIGEST_ALGORITHM_SHA256; + break; + + default: + return SEC_RESULT_INVALID_PARAMETERS; + } + + sa_status status = sa_svp_buffer_check(opaqueBufferHandle->svp_buffer, 0, length, algorithm, expected, + expectedLength); + CHECK_STATUS(status) + return SEC_RESULT_SUCCESS; +} + +/** + * @brief Checks secure boot configuration to verify that Secure Boot is enabled. + */ +Sec_Result SecCodeIntegrity_SecureBootEnabled(void) { + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} + +Sec_Result SecSVP_SetTime(time_t time) { + return SEC_RESULT_UNIMPLEMENTED_FEATURE; +} diff --git a/src/sec_adapter_svp.h b/src/sec_adapter_svp.h new file mode 100644 index 0000000..96058c6 --- /dev/null +++ b/src/sec_adapter_svp.h @@ -0,0 +1,30 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_SVP_H +#define SEC_ADAPTER_SVP_H + +#include "sa.h" +#include "sec_adapter_processor.h" +#include "sec_security.h" + +struct Sec_OpaqueBufferHandle_struct { + sa_svp_buffer svp_buffer; +}; + +#endif // SEC_ADAPTER_SVP_H diff --git a/src/sec_adapter_utils.c b/src/sec_adapter_utils.c new file mode 100644 index 0000000..70a2d52 --- /dev/null +++ b/src/sec_adapter_utils.c @@ -0,0 +1,1216 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_utils.h" +#include +#include + +static const SEC_BYTE base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static int is_base64(unsigned char c); + +Sec_Result SecUtils_ReadFile(const char* path, void* data, SEC_SIZE data_len, SEC_SIZE* data_read) { + FILE* f = NULL; + SEC_BYTE last_byte; + + *data_read = 0; + + f = fopen(path, "rbe"); + if (f == NULL) { + SEC_LOG_ERROR("Could not open file: %s", path); + return SEC_RESULT_FAILURE; + } + + while (ferror(f) == 0 && feof(f) == 0 && *data_read < data_len) { + *data_read += fread(data, 1, data_len - *data_read, f); + } + + if (ferror(f) != 0) { + SEC_LOG_ERROR("Ferror encountered while reading file: %s", path); + fclose(f); + f = NULL; + return SEC_RESULT_NO_SUCH_ITEM; + } + + fread(&last_byte, 1, 1, f); + + if (feof(f) == 0) { + SEC_LOG_ERROR("Data_len is too small"); + fclose(f); + f = NULL; + return SEC_RESULT_BUFFER_TOO_SMALL; + } + + fclose(f); + f = NULL; + + return SEC_RESULT_SUCCESS; +} + +static long SecUtils_GetFileLen(const char* path) { + FILE* f = NULL; + long len = -1; + + f = fopen(path, "rbe"); + if (f == NULL) { + SEC_LOG_ERROR("Could not open file: %s", path); + return len; + } + + fseek(f, 0L, SEEK_END); + len = ftell(f); + fseek(f, 0L, SEEK_SET); + + if (fclose(f) != 0) { + SEC_LOG_ERROR("Fclose failed"); + } + + return len; +} + +static Sec_Result SecUtils_VerifyFile(const char* path, void* expected, SEC_SIZE expected_len) { + SEC_BYTE* read = NULL; + SEC_SIZE read_len; + SEC_SIZE file_len; + + //allocate memory for verification + read = (SEC_BYTE*) malloc(expected_len); + if (read == NULL) { + SEC_LOG_ERROR("Malloc failed for file: %s", path); + SEC_FREE(read); + return SEC_RESULT_FAILURE; + } + + //make sure that the written file is of proper length + file_len = SecUtils_GetFileLen(path); + if (expected_len != file_len) { + SEC_LOG_ERROR("File written out (%s) is %d bytes, but expected %d", path, file_len, expected_len); + SEC_FREE(read); + return SEC_RESULT_FAILURE; + } + + //read data back in + if (SecUtils_ReadFile(path, read, expected_len, &read_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ReadFile failed for file: %s", path); + SEC_FREE(read); + return SEC_RESULT_FAILURE; + } + + //compare read data to input + if (memcmp(expected, read, expected_len) != 0) { + SEC_LOG_ERROR("Data read in does not match the data written out for file: %s", path); + SEC_FREE(read); + return SEC_RESULT_FAILURE; + } + + SEC_FREE(read); + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecUtils_WriteFile(const char* path, void* data, SEC_SIZE data_len) { + Sec_Result sec_res = SEC_RESULT_FAILURE; + FILE* f = NULL; + int fdesc; + int dir_fdesc = -1; + char* path_cpy = NULL; + + //make a copy of the path string since basedir will change it + do { + path_cpy = strdup(path); + if (path_cpy == NULL) { + SEC_LOG_ERROR("Strdup failed for file: %s", path); + break; + } + + //open file + f = fopen(path, "wbe"); + if (f == NULL) { + SEC_LOG_ERROR("Could not open file: %s, errno: %d", path, errno); + break; + } + + //get file descriptor + fdesc = fileno(f); + if (fdesc < 0) { + SEC_LOG_ERROR("Fileno failed for file: %s, errno: %d", path, errno); + break; + } + + //write contents + if (data_len != fwrite(data, 1, data_len, f)) { + SEC_LOG_ERROR("Could not write to file: %s, errno: %d", path, errno); + break; + } + + //flush + if (fflush(f) != 0) { + SEC_LOG_ERROR("Fflush failed for file: %s, errno: %d", path, errno); + break; + } + + //force sync on written file + if (fsync(fdesc) != 0) { + SEC_LOG_ERROR("Fsync failed for file: %s, errno: %d", path, errno); + break; + } + + //close file + if (fclose(f) != 0) { + SEC_LOG_ERROR("Fclose failed for file: %s, errno: %d", path, errno); + f = NULL; + break; + } + f = NULL; + + //sync parent directory + dir_fdesc = open(dirname(path_cpy), O_RDONLY | O_CLOEXEC); // NOLINT + if (dir_fdesc < 0) { + SEC_LOG_ERROR("Open parent failed for file: %s, errno: %d", path, errno); + break; + } + + if (fsync(dir_fdesc) != 0) { + SEC_LOG_ERROR("Fsync parent failed for file: %s, errno: %d", path, errno); + break; + } + + if (close(dir_fdesc) != 0) { + dir_fdesc = -1; + SEC_LOG_ERROR("Close parent failed for file: %s, errno: %d", path, errno); + break; + } + dir_fdesc = -1; + + //verify written file + if (SecUtils_VerifyFile(path, data, data_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_VerifyFile failed for file: %s", path); + break; + } + + sec_res = SEC_RESULT_SUCCESS; + } while (false); + + if (f != NULL) { + if (fclose(f) != 0) { + SEC_LOG_ERROR("Fclose failed for file: %s, errno: %d", path, errno); + } + f = NULL; + } + + if (dir_fdesc >= 0) { + if (close(dir_fdesc) != 0) { + SEC_LOG_ERROR("Close parent failed for file: %s, errno: %d", path, errno); + } + } + + SEC_FREE(path_cpy); + + return sec_res; +} + +Sec_Result SecUtils_RmFile(const char* path) { + void* zeros = NULL; + long len; + + len = SecUtils_GetFileLen(path); + if (len > 0) { + zeros = calloc(len, 1); + if (zeros != NULL) { + SecUtils_WriteFile(path, zeros, len); + free(zeros); + } else { + SEC_LOG_ERROR("Calloc failed"); + } + } + + if (unlink(path) != 0) { + SEC_LOG_ERROR("Unlink %s failed", path); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +SEC_BOOL SecUtils_FileExists(const char* path) { + FILE* f = NULL; + + f = fopen(path, "rbe"); + if (f == NULL) + return SEC_FALSE; + + fclose(f); + + return SEC_TRUE; +} + +SEC_SIZE SecUtils_LsDir(const char* path, Sec_LsDirEntry* entries, SEC_SIZE maxNumEntries) { + struct dirent* dent; + struct stat st; + DIR* srcdir; + SEC_SIZE found = 0; + char file_path[SEC_MAX_FILE_PATH_LEN]; + + srcdir = opendir(path); + + if (srcdir == NULL) { + SEC_LOG_ERROR("Opendir failed"); + return 0; + } + + while ((dent = readdir(srcdir)) != NULL) { // NOLINT + snprintf(file_path, sizeof(file_path), "%s%s", path, dent->d_name); + + if (stat(file_path, &st) < 0) { + SEC_LOG_ERROR("Fstatat failed on: %s", dent->d_name); + continue; + } + + /* store found file */ + if (entries != NULL && found < maxNumEntries) { + snprintf(entries[found].name, sizeof(entries[found].name), "%s", + dent->d_name); + entries[found].is_dir = S_ISDIR(st.st_mode); + } + + ++found; + } + + closedir(srcdir); + return found; +} + +Sec_Result SecUtils_MkDir(const char* path) { + char tmp[SEC_MAX_FILE_PATH_LEN]; + char* p = NULL; + size_t len; + + snprintf(tmp, sizeof(tmp), "%s", path); + len = strlen(tmp); + if (len == 0) { + SEC_LOG_ERROR("Empty path string"); + return SEC_RESULT_FAILURE; + } + + if (tmp[len - 1] == '/') { + tmp[len - 1] = 0; + } + + for (p = tmp + 1; *p != 0; p++) { + if (*p == '/') { + *p = 0; + if (mkdir(tmp, S_IRWXU) != 0 && errno != EEXIST) { + SEC_LOG_ERROR("Mkdir %s failed", tmp); + return SEC_RESULT_FAILURE; + } + + *p = '/'; + } + } + + if (mkdir(tmp, S_IRWXU) != 0 && errno != EEXIST) { + SEC_LOG_ERROR("Mkdir %s failed", tmp); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +SEC_SIZE SecUtils_UpdateItemList(SEC_OBJECTID* items, SEC_SIZE maxNumItems, SEC_SIZE numItems, SEC_OBJECTID item_id) { + /* if array is full, just return it */ + if (numItems >= maxNumItems) + return numItems; + + /* if item already in the list, skip it */ + if (SecUtils_ItemIndex(items, numItems, item_id) != -1) + return numItems; + + items[numItems] = item_id; + ++numItems; + + return numItems; +} + +SEC_SIZE SecUtils_UpdateItemListFromDir(SEC_OBJECTID* items, SEC_SIZE maxNumItems, SEC_SIZE numItems, const char* dir, + const char* ext) { + SEC_SIZE numEntries; + SEC_SIZE i; + Sec_LsDirEntry entries[256]; + char pattern[256]; + SEC_OBJECTID item_id; + + snprintf(pattern, sizeof(pattern), "%s%s", SEC_OBJECTID_PATTERN, ext); + + numEntries = SecUtils_LsDir(dir, entries, 256); + + for (i = 0; i < numEntries; ++i) { + if (!entries[i].is_dir && SecUtils_EndsWith(entries[i].name, ext)) { + /* obtain 64-bit item id */ + if (sscanf(entries[i].name, pattern, &item_id) != 1) { + SEC_LOG_ERROR("Sscanf failed on: %s", entries[i].name); + continue; + } + + numItems = SecUtils_UpdateItemList(items, maxNumItems, numItems, item_id); + } + } + + return numItems; +} + +SEC_BYTE SecUtils_EndsWith(const char* str, const char* end) { + SEC_SIZE lenstr; + SEC_SIZE lenend; + + if (!str || !end) + return 0; + + lenstr = strlen(str); + lenend = strlen(end); + if (lenend > lenstr) + return 0; + + return strncmp(str + lenstr - lenend, end, lenend) == 0; +} + +int SecUtils_ItemIndex(const SEC_OBJECTID* items, SEC_SIZE numItems, SEC_OBJECTID item) { + int i; + + for (i = 0; i < numItems; ++i) { + if (items[i] == item) + return i; + } + + return -1; +} + +SEC_SIZE SecUtils_X509ToDerLen(X509* x509, void* mem, SEC_SIZE mem_len) { + int written; + SEC_BYTE* ptr = (SEC_BYTE*) mem; + + if (i2d_X509(x509, NULL) >= mem_len) { + SEC_LOG_ERROR("Buffer is too small"); + return 0; + } + + written = i2d_X509(x509, &ptr); + + if (written < 0) { + SEC_LOG_ERROR("I2d_X509 failed"); + return 0; + } + + return written; +} + +EC_KEY* SecUtils_ECCFromDERPriv(const SEC_BYTE* der, SEC_SIZE der_len) { + const unsigned char* p = (const unsigned char*) der; + PKCS8_PRIV_KEY_INFO* p8 = NULL; + EVP_PKEY* evp_key = NULL; + EC_KEY* ecc = NULL; + + p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, der_len); + if (p8 != NULL) { + evp_key = EVP_PKCS82PKEY(p8); + if (evp_key == NULL) { + SEC_LOG_ERROR("EVP_PKCS82PKEY failed"); + SEC_EVPPKEY_FREE(evp_key); + PKCS8_PRIV_KEY_INFO_free(p8); + return ecc; + } + } else { + evp_key = d2i_AutoPrivateKey(NULL, &p, der_len); + if (evp_key == NULL) { + SEC_LOG_ERROR("d2i_AutoPrivateKey failed"); + SEC_EVPPKEY_FREE(evp_key); + return ecc; + } + } + + ecc = EVP_PKEY_get1_EC_KEY(evp_key); + if (ecc == NULL) { + SEC_LOG_ERROR("EVP_PKEY_get1_EC_KEY failed"); + SEC_EVPPKEY_FREE(evp_key); + if (p8 != NULL) + PKCS8_PRIV_KEY_INFO_free(p8); + + return ecc; + } + + SEC_EVPPKEY_FREE(evp_key); + if (p8 != NULL) + PKCS8_PRIV_KEY_INFO_free(p8); + + return ecc; +} + +Sec_Result SecUtils_ECCToPubBinary(EC_KEY* ec_key, Sec_ECCRawPublicKey* binary) { + BIGNUM* x = NULL; + BIGNUM* y = NULL; + + if (SecUtils_Extract_EC_KEY_X_Y(ec_key, &x, &y, NULL) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ECCToPubBinary: SecUtils_Extract_EC_KEY_X_Y failed"); + return SEC_RESULT_FAILURE; + } + + binary->type = SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + Sec_Uint32ToBEBytes(SecKey_GetKeyLenForKeyType(binary->type), binary->key_len); + SecUtils_BigNumToBuffer(x, binary->x, Sec_BEBytesToUint32(binary->key_len)); + SecUtils_BigNumToBuffer(y, binary->y, Sec_BEBytesToUint32(binary->key_len)); + + BN_free(y); + BN_free(x); + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecUtils_Base64Encode(const SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* output, SEC_SIZE max_output, + SEC_SIZE* out_len) { + int i = 0; + int j; + SEC_BYTE arr3[3]; + SEC_BYTE arr4[4]; + SEC_SIZE ret_len = 0; + + *out_len = 0; + memset(arr3, 0, 3); + memset(arr4, 0, 4); + while (input_len--) { + arr3[i++] = *(input++); + if (i == 3) { + arr4[0] = (arr3[0] & 0xfc) >> 2; + arr4[1] = ((arr3[0] & 0x03) << 4) + ((arr3[1] & 0xf0) >> 4); + arr4[2] = ((arr3[1] & 0x0f) << 2) + ((arr3[2] & 0xc0) >> 6); + arr4[3] = arr3[2] & 0x3f; + + for (i = 0; i < 4; i++) { + if (ret_len >= max_output) { + SEC_LOG_ERROR("Output buffer too small"); + return SEC_RESULT_FAILURE; + } + + output[ret_len++] = base64_chars[arr4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + arr3[j] = '\0'; + } + + arr4[0] = (arr3[0] & 0xfc) >> 2; + arr4[1] = ((arr3[0] & 0x03) << 4) + ((arr3[1] & 0xf0) >> 4); + arr4[2] = ((arr3[1] & 0x0f) << 2) + ((arr3[2] & 0xc0) >> 6); + arr4[3] = arr3[2] & 0x3f; + + for (j = 0; j < (i + 1); j++) { + if (ret_len >= max_output) { + SEC_LOG_ERROR("Output buffer too small"); + return SEC_RESULT_FAILURE; + } + + output[ret_len++] = base64_chars[arr4[j]]; + } + + while (i++ < 3) { + if (ret_len >= max_output) { + SEC_LOG_ERROR("Output buffer too small"); + return SEC_RESULT_FAILURE; + } + + output[ret_len++] = '='; + } + } + + *out_len = ret_len; + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecUtils_Base64Decode(const SEC_BYTE* input, SEC_SIZE in_len, SEC_BYTE* output, SEC_SIZE max_output, + SEC_SIZE* out_len) { + Sec_Result status = SEC_RESULT_FAILURE; + SEC_SIZE i = 0; + SEC_SIZE j = 0; + SEC_SIZE z = 0; + SEC_SIZE ret_len = 0; + SEC_SIZE curPos = 0; + SEC_BYTE arr3[3]; + SEC_BYTE arr4[4]; + + *out_len = 0; + + if (in_len <= 1) { + SEC_LOG_ERROR("Illegal base64 string"); + return SEC_RESULT_FAILURE; + } + + memset(arr3, 0, 3); + memset(arr4, 0, 4); + while (in_len-- && (input[curPos] != '=') && is_base64(input[curPos])) { + arr4[i++] = input[curPos]; + curPos++; + if (i == 4) { + for (i = 0; i < 4; i++) { + for (z = 0; z < 64; z++) { + if (base64_chars[z] == arr4[i]) { + arr4[i] = (SEC_BYTE) z; + break; + } + } + } + + arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4); + arr3[1] = ((arr4[1] & 0xf) << 4) + ((arr4[2] & 0x3c) >> 2); + arr3[2] = ((arr4[2] & 0x3) << 6) + arr4[3]; + + for (i = 0; i < 3; i++) { + if (ret_len >= max_output) { + SEC_LOG_ERROR("Output buffer too small"); + return SEC_RESULT_FAILURE; + } + output[ret_len++] = arr3[i]; + } + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + arr4[j] = 0; + } + + for (j = 0; j < 4; j++) { + for (z = 0; z < 64; z++) { + if (base64_chars[z] == arr4[j]) { + arr4[j] = z; + break; + } + } + } + + arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4); + arr3[1] = ((arr4[1] & 0xf) << 4) + ((arr4[2] & 0x3c) >> 2); + arr3[2] = ((arr4[2] & 0x3) << 6) + arr4[3]; + + for (j = 0; (j < i - 1); j++) { + if (ret_len >= max_output) { + SEC_LOG_ERROR("Output buffer too small"); + return SEC_RESULT_FAILURE; + } + output[ret_len++] = arr3[j]; + } + } + + *out_len = ret_len; + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecUtils_ECCToPrivBinary(EC_KEY* ec_key, Sec_ECCRawPrivateKey* binary) { + BIGNUM* x = NULL; + BIGNUM* y = NULL; + Sec_KeyType keyType; + + if (SecUtils_Extract_EC_KEY_X_Y(ec_key, &x, &y, &keyType) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ECCToPrivBinary: SecUtils_Extract_EC_KEY_X_Y failed"); + return SEC_RESULT_FAILURE; + } + + if (keyType != SEC_KEYTYPE_ECC_NISTP256_PUBLIC) { + SEC_LOG_ERROR("Unexpected key type encountered: %d", keyType); + return SEC_RESULT_FAILURE; + } + + binary->type = SEC_KEYTYPE_ECC_NISTP256; + Sec_Uint32ToBEBytes(SecKey_GetKeyLenForKeyType(keyType), binary->key_len); + SecUtils_BigNumToBuffer((BIGNUM*) EC_KEY_get0_private_key(ec_key), binary->prv, + Sec_BEBytesToUint32(binary->key_len)); + SecUtils_BigNumToBuffer(x, binary->x, Sec_BEBytesToUint32(binary->key_len)); + SecUtils_BigNumToBuffer(y, binary->y, Sec_BEBytesToUint32(binary->key_len)); + + BN_free(y); + BN_free(x); + return SEC_RESULT_SUCCESS; +} + +RSA* SecUtils_RSAFromDERPriv(const SEC_BYTE* der, SEC_SIZE der_len) { + const unsigned char* p = (const unsigned char*) der; + PKCS8_PRIV_KEY_INFO* p8 = NULL; + EVP_PKEY* evp_key = NULL; + RSA* rsa = NULL; + + p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, der_len); + if (p8 != NULL) { + evp_key = EVP_PKCS82PKEY(p8); + if (evp_key == NULL) { + SEC_LOG_ERROR("EVP_PKCS82PKEY failed"); + SEC_EVPPKEY_FREE(evp_key); + PKCS8_PRIV_KEY_INFO_free(p8); + return rsa; + } + } else { + evp_key = d2i_AutoPrivateKey(NULL, &p, der_len); + if (evp_key == NULL) { + SEC_LOG_ERROR("d2i_AutoPrivateKey failed"); + SEC_EVPPKEY_FREE(evp_key); + return rsa; + } + } + + rsa = EVP_PKEY_get1_RSA(evp_key); + if (rsa == NULL) { + SEC_LOG_ERROR("EVP_PKEY_get1_RSA failed"); + SEC_EVPPKEY_FREE(evp_key); + if (p8 != NULL) + PKCS8_PRIV_KEY_INFO_free(p8); + + return rsa; + } + + SEC_EVPPKEY_FREE(evp_key); + if (p8 != NULL) + PKCS8_PRIV_KEY_INFO_free(p8); + + return rsa; +} + +Sec_Result SecUtils_RSAToDERPrivKeyInfo(RSA* rsa, SEC_BYTE* output, SEC_SIZE out_len, SEC_SIZE* written) { + BIO* bio = NULL; + EVP_PKEY* evp_key = NULL; + BUF_MEM* bptr = NULL; + + evp_key = EVP_PKEY_new(); + if (EVP_PKEY_set1_RSA(evp_key, rsa) == 0) { + SEC_LOG_ERROR("EVP_PKEY_set1_RSA failed"); + SEC_EVPPKEY_FREE(evp_key); + SEC_BIO_FREE(bio); + return SEC_RESULT_FAILURE; + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + SEC_LOG_ERROR("BIO_new(BIO_s_mem()) failed"); + SEC_EVPPKEY_FREE(evp_key); + SEC_BIO_FREE(bio); + return SEC_RESULT_FAILURE; + } + + if (!i2d_PKCS8PrivateKeyInfo_bio(bio, evp_key)) { + SEC_LOG_ERROR("I2d_PKCS8_PRIV_KEY_INFO_bio failed"); + SEC_EVPPKEY_FREE(evp_key); + SEC_BIO_FREE(bio); + return SEC_RESULT_FAILURE; + } + + BIO_flush(bio); + BIO_get_mem_ptr(bio, &bptr); + + *written = bptr->length; + + if (output != NULL) { + if (out_len < bptr->length) { + SEC_LOG_ERROR("Output buffer is not large enough"); + SEC_EVPPKEY_FREE(evp_key); + SEC_BIO_FREE(bio); + return SEC_RESULT_FAILURE; + } + + memcpy(output, bptr->data, bptr->length); + } + + SEC_EVPPKEY_FREE(evp_key); + SEC_BIO_FREE(bio); + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecUtils_WrapSymetric(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID wrappingKey, + Sec_CipherAlgorithm wrappingAlg, SEC_BYTE* iv, SEC_BYTE* payload, SEC_SIZE payloadLen, SEC_BYTE* out, + SEC_SIZE out_len, SEC_SIZE* written) { + if (SecCipher_SingleInputId(processorHandle, wrappingAlg, SEC_CIPHERMODE_ENCRYPT, wrappingKey, iv, payload, + payloadLen, out, out_len, written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result SecUtils_BigNumToBuffer(const BIGNUM* bignum, SEC_BYTE* buffer, SEC_SIZE buffer_len) { + SEC_SIZE num_bytes; + + memset(buffer, 0, buffer_len); + num_bytes = BN_num_bytes(bignum); + + if (num_bytes > buffer_len) { + SEC_LOG_ERROR("Buffer not large enough. needed: %d, actual: %d", num_bytes, buffer_len); + return SEC_RESULT_FAILURE; + } + + BN_bn2bin(bignum, buffer + buffer_len - num_bytes); + return SEC_RESULT_SUCCESS; +} + +/* + * The next steps a caller might take are: + * SecUtils_BigNumToBuffer(x, public_key->x, Sec_BEBytesToUint32(public_key->key_len)); + * SecUtils_BigNumToBuffer(y, public_key->y, Sec_BEBytesToUint32(public_key->key_len)); + */ +Sec_Result SecUtils_Extract_EC_KEY_X_Y(const EC_KEY* ec_key, BIGNUM** xp, BIGNUM** yp, Sec_KeyType* keyTypep) { + const EC_GROUP* group = NULL; + const EC_POINT* ec_point = NULL; + BN_CTX* ctx = NULL; + + if (xp == NULL) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: X cannot be NULL"); + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_FAILURE; + } + + group = EC_KEY_get0_group(ec_key); + if (group == NULL) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_KEY_get0_group: %s", ERR_error_string(ERR_get_error(), NULL)); + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_FAILURE; + } + + ec_point = EC_KEY_get0_public_key(ec_key); + if (ec_point == NULL) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_KEY_get0_public_key: %s", + ERR_error_string(ERR_get_error(), NULL)); + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_FAILURE; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + SEC_LOG_ERROR("BN_CTX_new() failed"); + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_FAILURE; + } + + *xp = BN_new(); + if (*xp == NULL) { + SEC_LOG_ERROR("BN_new() failed"); + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_FAILURE; + } + + if (yp != NULL) { // if caller wants y coordinate returned + *yp = BN_new(); + if (*yp == NULL) { + SEC_LOG_ERROR("BN_new() failed"); + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_FAILURE; + } + } + + if (keyTypep != NULL) // if caller wants key type returned + { + *keyTypep = SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + } + + // Get the X coordinate and optionally the Y coordinate + if (EC_POINT_get_affine_coordinates_GFp(group, ec_point, *xp, yp != NULL ? *yp : NULL, ctx) != 1) { + BN_clear_free(*xp); + if (yp != NULL) + BN_clear_free(*yp); + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_POINT_get_affine_coordinates_GFp: %s", + ERR_error_string(ERR_get_error(), NULL)); + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_FAILURE; + } + + if (ctx != NULL) + BN_CTX_free(ctx); + + return SEC_RESULT_SUCCESS; +} + +// ec_key is the other side's public ECC key +// +// Returns the number of bytes in the encrypted output or +// -1 if there was an error +int SecUtils_ElGamal_Encrypt_Rand(EC_KEY* ec_key, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* output, + SEC_SIZE outputSize, BIGNUM* sender_rand) { + int result = -1; + BIGNUM* inputAsBN = NULL; + const EC_GROUP* group = NULL; + const EC_POINT* P = NULL; + const EC_POINT* PK_recipient = NULL; + EC_POINT* shared_secret = NULL; + EC_POINT* key_2_wrap_point = NULL; + EC_POINT* sender_share = NULL; + EC_POINT* wrapped_key = NULL; + BIGNUM* x = NULL; + BIGNUM* y = NULL; + BN_CTX* ctx = NULL; + + do { + if (inputSize != SEC_ECC_NISTP256_KEY_LEN) { + SEC_LOG_ERROR("Input size needed != One BIGNUM"); + break; + } + + if (outputSize < 4 * SEC_ECC_NISTP256_KEY_LEN) { + SEC_LOG_ERROR("Output size needed < Four BIGNUMs"); + break; + } + + // Convert the input buffer to be encrypted to a BIGNUM + inputAsBN = BN_new(); + if (inputAsBN == NULL) { + SEC_LOG_ERROR("BN_new failed"); + break; + } + if (BN_bin2bn(input, (int) inputSize, inputAsBN) == NULL) { + SEC_LOG_ERROR("BN_bin2bn failed. Error: %s", + ERR_error_string(ERR_get_error(), NULL)); + break; + } + + group = EC_KEY_get0_group(ec_key); + if (group == NULL) { + SEC_LOG_ERROR("EC_KEY_get0_group failed"); + break; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + SEC_LOG_ERROR("BN_CTX_new failed"); + break; + } + + // Convert the X coordinate to an EC Point. This takes the desired Y value in 1 bit (to choose + // which of the two possible Y values to use). This *calculates* an actual Y value for the point. + key_2_wrap_point = EC_POINT_new(group); + if (key_2_wrap_point == NULL) { + SEC_LOG_ERROR("EC_POINT_new failed"); + break; + } + + if (!EC_POINT_set_compressed_coordinates_GFp(group, key_2_wrap_point, inputAsBN, 0, ctx)) //$$$ 1=>0 on 7/8/15 + { + // Don't print an error message if the error is "point not on curve" 100A906E, but still fail + if (ERR_get_error() != 0x100A906E) // i.e. error:100A906E:lib(16):func(169):reason(110) + SEC_LOG_ERROR("Set EC_POINT_set_compressed_coordinates_GFp failed. Error: %s", + ERR_error_string(ERR_get_error(), NULL)); + break; + } + + // Calc sender's shared point 'wP' => this gets sent back to receiver + sender_share = EC_POINT_new(group); + if (sender_share == NULL) { + SEC_LOG_ERROR("EC_POINT_new failed"); + break; + } + + P = EC_GROUP_get0_generator(group); + if (P == NULL) { + SEC_LOG_ERROR("EC_GROUP_get0_generator failed"); + break; + } + + EC_POINT_mul(group, sender_share, NULL, P, sender_rand, ctx); + + // Calc sender's Shared Secret 'wRr' => this hides the key I want to send + shared_secret = EC_POINT_new(group); + if (shared_secret == NULL) { + SEC_LOG_ERROR("EC_POINT_new failed"); + break; + } + + PK_recipient = EC_KEY_get0_public_key(ec_key); + if (PK_recipient == NULL) { + SEC_LOG_ERROR("EC_KEY_get0_public_key failed"); + break; + } + + EC_POINT_mul(group, shared_secret, NULL, PK_recipient, sender_rand, ctx); + + // key_2_wrap_point is a point on the curve, we add the shared_secret + // to it and send the result, the wrapped_key, to the receiver. + wrapped_key = EC_POINT_new(group); + if (wrapped_key == NULL) { + SEC_LOG_ERROR("EC_POINT_new failed"); + break; + } + + EC_POINT_add(group, wrapped_key, key_2_wrap_point, shared_secret, ctx); + + // Dissect the wrapped point to get its coordinates + x = BN_new(); + if (x == NULL) { + SEC_LOG_ERROR("BN_new failed"); + break; + } + + y = BN_new(); + if (y == NULL) { + SEC_LOG_ERROR("BN_new failed"); + break; + } + + // Dissect shared_secret to get its coordinates and output them + EC_POINT_get_affine_coordinates_GFp(group, sender_share, x, y, ctx); + if (SecUtils_BigNumToBuffer(x, (unsigned char*) &output[0 * SEC_ECC_NISTP256_KEY_LEN], + SEC_ECC_NISTP256_KEY_LEN) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_BigNumToBuffer failed"); + break; + } + + if (SecUtils_BigNumToBuffer(y, (unsigned char*) &output[1 * SEC_ECC_NISTP256_KEY_LEN], + SEC_ECC_NISTP256_KEY_LEN) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_BigNumToBuffer failed"); + break; + } + + // Dissect wrapped_key to get its coordinates and output them + EC_POINT_get_affine_coordinates_GFp(group, wrapped_key, x, y, ctx); + + if (SecUtils_BigNumToBuffer(x, (unsigned char*) &output[2 * SEC_ECC_NISTP256_KEY_LEN], + SEC_ECC_NISTP256_KEY_LEN) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_BigNumToBuffer failed"); + break; + } + + if (SecUtils_BigNumToBuffer(y, (unsigned char*) &output[3 * SEC_ECC_NISTP256_KEY_LEN], + SEC_ECC_NISTP256_KEY_LEN) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_BigNumToBuffer failed"); + break; + } + + result = 4 * SEC_ECC_NISTP256_KEY_LEN; + } while (false); + + if (x != NULL) + BN_free(x); + if (y != NULL) + BN_free(y); + if (inputAsBN != NULL) + BN_free(inputAsBN); + if (sender_rand != NULL) + BN_free(sender_rand); + if (shared_secret != NULL) + EC_POINT_free(shared_secret); + if (sender_share != NULL) + EC_POINT_free(sender_share); + if (key_2_wrap_point != NULL) + EC_POINT_free(key_2_wrap_point); + if (wrapped_key != NULL) + EC_POINT_free(wrapped_key); + BN_CTX_free(ctx); + return result; +} + +// ec_key is the other side's public ECC key +// +// Returns the number of bytes in the encrypted output or +// -1 if there was an error +int SecUtils_ElGamal_Encrypt(EC_KEY* ec_key, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* output, + SEC_SIZE outputSize) { + // Generate random number 'w' (multiplier) for the sender + BIGNUM* sender_rand = BN_new(); + + if (sender_rand == NULL) { + SEC_LOG_ERROR("BN_new failed"); + return -1; + } + + if (BN_rand(sender_rand, 256, -1, 0) == 0) { + SEC_LOG_ERROR("BN_rand failed"); + if (sender_rand != NULL) + BN_free(sender_rand); + return -1; + } + + return SecUtils_ElGamal_Encrypt_Rand(ec_key, input, inputSize, output, outputSize, sender_rand); +} + +EC_KEY* SecUtils_ECCFromPubBinary(Sec_ECCRawPublicKey* binary) { + BN_CTX* ctx = BN_CTX_new(); + + if (binary->type != SEC_KEYTYPE_ECC_NISTP256_PUBLIC && binary->type != SEC_KEYTYPE_ECC_NISTP256) + return NULL; + + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); //create ec_key structure with NIST p256 curve; + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + EC_POINT* ec_point = EC_POINT_new(group); + BN_CTX_start(ctx); + BIGNUM* xp; + BIGNUM* yp; + + if (((xp = BN_CTX_get(ctx)) == NULL) || ((yp = BN_CTX_get(ctx)) == NULL)) { + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ec_key; + } + + EC_POINT_set_affine_coordinates_GFp(group, ec_point, + BN_bin2bn(binary->x, (int) Sec_BEBytesToUint32(binary->key_len), xp), + BN_bin2bn(binary->y, (int) Sec_BEBytesToUint32(binary->key_len), yp), ctx); + EC_KEY_set_public_key(ec_key, ec_point); + + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ec_key; +} + +Sec_Result SecUtils_FillKeyStoreUserHeader(Sec_ProcessorHandle* processorHandle, SecUtils_KeyStoreHeader* header, + Sec_KeyContainer container) { + Sec_Memset(header, 0, sizeof(SecUtils_KeyStoreHeader)); + + if (SecProcessor_GetDeviceId(processorHandle, header->device_id) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecProcessor_GetDeviceId failed"); + return SEC_RESULT_FAILURE; + } + + header->inner_kc_type = container; + return SEC_RESULT_SUCCESS; +} + +SecUtils_KeyStoreHeader* SecUtils_GetKeyStoreUserHeader(void* store) { + return (SecUtils_KeyStoreHeader*) SecStore_GetUserHeader(store); +} + +Sec_Result SecUtils_ValidateKeyStore(Sec_ProcessorHandle* processorHandle, SEC_BOOL require_mac, void* store, + SEC_SIZE store_len) { + SecUtils_KeyStoreHeader header; + SEC_BYTE device_id[SEC_DEVICEID_LEN]; + + Sec_Memset(&header, 0, sizeof(header)); + + if (store_len < sizeof(SecStore_Header) || store_len < SecStore_GetStoreLen(store)) { + SEC_LOG_ERROR("Invalid store"); + return SEC_RESULT_FAILURE; + } + + if (memcmp(SEC_UTILS_KEYSTORE_MAGIC, SecStore_GetHeader(store)->user_header_magic, + strlen(SEC_UTILS_KEYSTORE_MAGIC)) != 0) { + SEC_LOG_ERROR("Invalid key store magic value"); + return SEC_RESULT_FAILURE; + } + + if (SecStore_RetrieveData(processorHandle, require_mac, &header, sizeof(header), NULL, 0, store, store_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_RetrieveData failed"); + return SEC_RESULT_FAILURE; + } + + if (SecProcessor_GetDeviceId(processorHandle, device_id) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecProcessor_GetDeviceId failed"); + return SEC_RESULT_FAILURE; + } + + if (memcmp(device_id, header.device_id, SEC_DEVICEID_LEN) != 0) { + SEC_LOG_ERROR("Device_id does not match the key store"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result write_verification_file(Sec_ProcessorHandle* processorHandle, char* filename, SEC_BYTE* data, + SEC_SIZE data_length, SEC_BYTE* info, size_t info_length) { + SEC_BYTE digest[SHA256_DIGEST_LENGTH * 2]; + SEC_SIZE length = 0; + + if (SecDigest_SingleInput(processorHandle, SEC_DIGESTALGORITHM_SHA256, data, data_length, digest, + &length) != SEC_RESULT_SUCCESS || + length != SHA256_DIGEST_LENGTH) { + SEC_LOG_ERROR("Unable to calculate verification digest"); + return SEC_RESULT_FAILURE; + } + + if (info != NULL) { + if (SecDigest_SingleInput(processorHandle, SEC_DIGESTALGORITHM_SHA256, info, info_length, + digest + SHA256_DIGEST_LENGTH, &length) != SEC_RESULT_SUCCESS || + length != SHA256_DIGEST_LENGTH) { + SEC_LOG_ERROR("Unable to calculate verification digest"); + return SEC_RESULT_FAILURE; + } + } else { + memset(digest + SHA256_DIGEST_LENGTH, 0, SHA256_DIGEST_LENGTH); + } + + if (SecUtils_WriteFile(filename, digest, SHA256_DIGEST_LENGTH * 2) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Could not write verification file"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result verify_verification_file(Sec_ProcessorHandle* processorHandle, char* filename, SEC_BYTE* data, + SEC_SIZE data_length, SEC_BYTE* info, size_t info_length) { + SEC_BYTE digest[SHA256_DIGEST_LENGTH * 2]; + SEC_SIZE length; + if (SecUtils_ReadFile(filename, digest, sizeof(digest), &length) != SEC_RESULT_SUCCESS || + length != sizeof(digest)) { + SEC_LOG_ERROR("Could not read verification file"); + return SEC_RESULT_VERIFICATION_FAILED; + } + + SEC_BYTE digest_result[SHA256_DIGEST_LENGTH]; + if (SecDigest_SingleInput(processorHandle, SEC_DIGESTALGORITHM_SHA256, data, data_length, digest_result, + &length) != SEC_RESULT_SUCCESS || + length != SHA256_DIGEST_LENGTH) { + SEC_LOG_ERROR("Unable to calculate verification digest"); + return SEC_RESULT_VERIFICATION_FAILED; + } + + if (memcmp(digest_result, digest, SHA256_DIGEST_LENGTH) != 0) { + SEC_LOG_ERROR("verification mismatch on data file"); + return SEC_RESULT_VERIFICATION_FAILED; + } + + if (info != NULL) { + if (SecDigest_SingleInput(processorHandle, SEC_DIGESTALGORITHM_SHA256, info, info_length, + digest_result, &length) != SEC_RESULT_SUCCESS || + length != SHA256_DIGEST_LENGTH) { + SEC_LOG_ERROR("Unable to calculate verification digest"); + return SEC_RESULT_VERIFICATION_FAILED; + } + + if (memcmp(digest_result, digest + SHA256_DIGEST_LENGTH, SHA256_DIGEST_LENGTH) != 0) { + SEC_LOG_ERROR("verification mismatch on info file"); + return SEC_RESULT_VERIFICATION_FAILED; + } + } + + return SEC_RESULT_SUCCESS; +} + +static int is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} diff --git a/src/sec_adapter_utils.h b/src/sec_adapter_utils.h new file mode 100644 index 0000000..dbf9e8a --- /dev/null +++ b/src/sec_adapter_utils.h @@ -0,0 +1,208 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_ADAPTER_UTILS_H_ +#define SEC_ADAPTER_UTILS_H_ + +#include "sec_adapter_store.h" +#include "sec_security.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +#include +#include +extern "C" { +#else +#include +#include +#endif + +#define SEC_INVALID_EPOCH ((SEC_SIZE) -1) + +typedef struct { + uint8_t inner_kc_type; + uint8_t reserved[7]; + uint8_t device_id[SEC_DEVICEID_LEN]; +} SecUtils_KeyStoreHeader; + +#define SEC_UTILS_KEYSTORE_MAGIC "KST0" + +/** + * @brief Read data from a file into a specified buffer. + * + * @param path file path + * @param data output data buffer where the file contents will be written + * @param data_len length of the output buffer + * @param data_read actual number of bytes written + * + * @return status of the operation + */ +Sec_Result SecUtils_ReadFile(const char* path, void* data, SEC_SIZE data_len, SEC_SIZE* data_read); + +/** + * @brief Write the input data into a specified file. + * + * @param path output file path + * @param data data to write + * @param data_len length of input data + * + * @return status of the operation + */ +Sec_Result SecUtils_WriteFile(const char* path, void* data, SEC_SIZE data_len); + +/** + * @brief create a specified directory. + * @param path directory path + */ +Sec_Result SecUtils_MkDir(const char* path); + +/** + * @brief Remove a specified file. + * + * @param path of the file to remove + */ +Sec_Result SecUtils_RmFile(const char* path); + +/** + * @brief Checks whether the specified file exists. + * + * @param path file path + * + * @return 1 if the file exists, 0 if it does not + */ +SEC_BOOL SecUtils_FileExists(const char* path); + +typedef struct { + char name[SEC_MAX_FILE_PATH_LEN]; + SEC_BYTE is_dir; +} Sec_LsDirEntry; + +/** + * @brief Obtain directory entries from a specified dir. + * + * @param path path of the directory to list + * @param entries pointer to the entry array. If NULL, the entries info will not be filled in, but the number + * of items will still be returned + * @param maxNumEntries The maximum number of entries to fill. + * + * @return number of directory entries in a specified dir + */ +SEC_SIZE SecUtils_LsDir(const char* path, Sec_LsDirEntry* entries, SEC_SIZE maxNumEntries); + +/** + * @brief Checks whether the specified strings ends with the other string. + */ +SEC_BYTE SecUtils_EndsWith(const char* str, const char* end); + +/** + * @brief obtain the index of the item in a list. + */ +int SecUtils_ItemIndex(const SEC_OBJECTID* items, SEC_SIZE numItems, SEC_OBJECTID item); + +/** + * @brief insert new item into the list if it does not exist. + */ +SEC_SIZE SecUtils_UpdateItemList(SEC_OBJECTID* items, SEC_SIZE maxNumItems, SEC_SIZE numItems, SEC_OBJECTID item_id); + +/** + * @brief insert new items into the list from the specified directory. + */ +SEC_SIZE SecUtils_UpdateItemListFromDir(SEC_OBJECTID* items, SEC_SIZE maxNumItems, SEC_SIZE numItems, const char* dir, + const char* ext); + +SEC_SIZE SecUtils_X509ToDerLen(X509* x509, void* mem, SEC_SIZE mem_len); + +/** + * @brief Convert the given epoch to iso formatted string. + */ +char* SecUtils_Epoch2IsoTime(SEC_SIZE epoch, char* iso_time, SEC_SIZE iso_time_size); + +/** + * @brief Convert the given iso time string to epoch value. + */ +SEC_SIZE SecUtils_IsoTime2Epoch(const char* iso_time); + +EC_KEY* SecUtils_ECCFromDERPriv(const SEC_BYTE* der, SEC_SIZE der_len); + +Sec_Result SecUtils_ECCToPubBinary(EC_KEY* ec_key, Sec_ECCRawPublicKey* binary); + +/** + * @brief Base64 encode the input string. + */ +Sec_Result SecUtils_Base64Encode(const SEC_BYTE* input, SEC_SIZE input_len, SEC_BYTE* output, SEC_SIZE max_output, + SEC_SIZE* out_len); + +/** + * @brief base64 decode the input string. + */ +Sec_Result SecUtils_Base64Decode(const SEC_BYTE* input, SEC_SIZE in_len, SEC_BYTE* output, SEC_SIZE max_output, + SEC_SIZE* out_len); + +/** + * @brief Write OpenSSL EC_KEY object into a private key binary blob + * + * The private key also contains the public key + */ +Sec_Result SecUtils_ECCToPrivBinary(EC_KEY* ec_key, Sec_ECCRawPrivateKey* binary); + +RSA* SecUtils_RSAFromDERPriv(const SEC_BYTE* der, SEC_SIZE der_len); + +Sec_Result SecUtils_RSAToDERPrivKeyInfo(RSA* rsa, SEC_BYTE* output, SEC_SIZE out_len, SEC_SIZE* written); + +Sec_Result SecUtils_WrapSymetric(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID wrappingKey, + Sec_CipherAlgorithm wrappingAlg, SEC_BYTE* iv, SEC_BYTE* payload, SEC_SIZE payloadLen, SEC_BYTE* out, + SEC_SIZE out_len, SEC_SIZE* written); + +Sec_Result SecUtils_BigNumToBuffer(const BIGNUM* bignum, SEC_BYTE* buffer, SEC_SIZE buffer_len); + +Sec_Result SecUtils_Extract_EC_KEY_X_Y(const EC_KEY* ec_key, BIGNUM** xp, BIGNUM** yp, Sec_KeyType* keyTypep); + +int SecUtils_ElGamal_Encrypt_Rand(EC_KEY* ec_key, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* output, + SEC_SIZE outputSize, BIGNUM* sender_rand); + +int SecUtils_ElGamal_Encrypt(EC_KEY* ec_key, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* output, + SEC_SIZE outputSize); + +EC_KEY* SecUtils_ECCFromPubBinary(Sec_ECCRawPublicKey* binary); + +Sec_Result SecUtils_FillKeyStoreUserHeader(Sec_ProcessorHandle* processorHandle, SecUtils_KeyStoreHeader* header, + Sec_KeyContainer container); + +SecUtils_KeyStoreHeader* SecUtils_GetKeyStoreUserHeader(void* store); + +Sec_Result SecUtils_ValidateKeyStore(Sec_ProcessorHandle* processorHandle, SEC_BOOL require_mac, void* store, + SEC_SIZE store_len); + +Sec_Result write_verification_file(Sec_ProcessorHandle* processorHandle, char* filename, SEC_BYTE* data, + SEC_SIZE data_length, SEC_BYTE* info, size_t info_length); + +Sec_Result verify_verification_file(Sec_ProcessorHandle* processorHandle, char* filename, SEC_BYTE* data, + SEC_SIZE data_length, SEC_BYTE* info, size_t info_length); + +#ifdef __cplusplus +} +#endif + +#endif // SEC_ADAPTER_UTILS_H_ diff --git a/src/sec_adapter_utils_time.c b/src/sec_adapter_utils_time.c new file mode 100644 index 0000000..d59aa5a --- /dev/null +++ b/src/sec_adapter_utils_time.c @@ -0,0 +1,48 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_utils.h" + +#define SEC_ISO_TIME_FORMAT "%Y-%m-%dT%H:%M:%S" + +char* SecUtils_Epoch2IsoTime(SEC_SIZE epoch, char* iso_time, SEC_SIZE iso_time_size) { + time_t in_time = (time_t) epoch; + struct tm ts; + memset(iso_time, 0, iso_time_size); + gmtime_r(&in_time, &ts); + if (strftime(iso_time, iso_time_size, SEC_ISO_TIME_FORMAT "Z", &ts) == 0) { + memset(iso_time, 0, iso_time_size); + } + + return iso_time; +} + +SEC_SIZE SecUtils_IsoTime2Epoch(const char* iso_time) { + struct tm _tm = {0}; + char* strptimeResult = NULL; + SEC_SIZE epoch = SEC_INVALID_EPOCH; + + strptimeResult = strptime(iso_time, SEC_ISO_TIME_FORMAT, &_tm); + if (strptimeResult == NULL || *strptimeResult != 'Z') { + SEC_LOG_ERROR("Parse error for iso time '%s'", iso_time); + return epoch; + } + + epoch = (SEC_SIZE) (mktime(&_tm)); + return epoch; +} diff --git a/test/main/cpp/bundle.cpp b/test/main/cpp/bundle.cpp new file mode 100644 index 0000000..e12a9b2 --- /dev/null +++ b/test/main/cpp/bundle.cpp @@ -0,0 +1,129 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bundle.h" +#include "sec_adapter_utils.h" +#include "test_ctx.h" + +Sec_Result testBundleProvision(SEC_OBJECTID id, Sec_StorageLoc loc, SEC_SIZE size) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector bundle = TestCtx::random(size); + + Sec_BundleHandle* bundleHandle; + if ((bundleHandle = ctx.provisionBundle(id, loc, bundle)) == nullptr) { + SEC_LOG_ERROR("TestCtx.provisionBundle failed"); + return SEC_RESULT_FAILURE; + } + + //get bundle size + SEC_SIZE written; + if (SecBundle_Export(bundleHandle, nullptr, 0, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBundle_Export failed"); + return SEC_RESULT_FAILURE; + } + + //export bundle + std::vector out; + out.resize(written); + if (SecBundle_Export(bundleHandle, &out[0], size, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBundle_Export failed"); + return SEC_RESULT_FAILURE; + } + + out.resize(written); + + if (out != bundle) { + SEC_LOG_ERROR("Exported bundle does not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testBundleProvisionNoSha(SEC_OBJECTID id) { + TestCtx ctx; + if (ctx.init("/tmp/sec_api_test_global", "/tmp/sec_api_test_app") != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector bundle = TestCtx::random(256); + + Sec_BundleHandle* bundleHandle; + if ((bundleHandle = ctx.provisionBundle(id, SEC_STORAGELOC_FILE, bundle)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionBundle failed"); + return SEC_RESULT_FAILURE; + } + + ctx.releaseBundle(bundleHandle); + + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + "/tmp/sec_api_test_app/", id); SecUtils_RmFile(file_name_verification); + if ((bundleHandle = ctx.getBundle(id)) == nullptr) { + SEC_LOG_ERROR("ctx.getBundle failed"); + return SEC_RESULT_FAILURE; + } + + //get bundle size + SEC_SIZE written; + if (SecBundle_Export(bundleHandle, nullptr, 0, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBundle_Export failed"); + return SEC_RESULT_FAILURE; + } + + //export bundle + std::vector out; + out.resize(written); + if (SecBundle_Export(bundleHandle, &out[0], 256, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBundle_Export failed"); + return SEC_RESULT_FAILURE; + } + + out.resize(written); + + if (out != bundle) { + SEC_LOG_ERROR("Exported bundle does not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testBundleProvisionNoAppDir(SEC_OBJECTID id, SEC_SIZE size) { + TestCtx ctx; + if (ctx.init("/tmp", nullptr) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector bundle = TestCtx::random(size); + + if (SecBundle_Provision(ctx.proc(), id, SEC_STORAGELOC_FILE, static_cast(&bundle[0]), bundle.size()) == + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBundle_Provision succeeded, but expected to fail"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/bundle.h b/test/main/cpp/bundle.h new file mode 100644 index 0000000..26e0c41 --- /dev/null +++ b/test/main/cpp/bundle.h @@ -0,0 +1,30 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BUNDLE_H +#define BUNDLE_H + +#include "sec_security.h" + +Sec_Result testBundleProvision(SEC_OBJECTID id, Sec_StorageLoc loc, SEC_SIZE size); + +Sec_Result testBundleProvisionNoSha(SEC_OBJECTID id); + +Sec_Result testBundleProvisionNoAppDir(SEC_OBJECTID id, SEC_SIZE size); + +#endif // BUNDLE_H diff --git a/test/main/cpp/cert.cpp b/test/main/cpp/cert.cpp new file mode 100644 index 0000000..ba6a1dd --- /dev/null +++ b/test/main/cpp/cert.cpp @@ -0,0 +1,298 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "cert.h" +#include "sec_adapter_utils.h" +#include "test_creds.h" +#include "test_ctx.h" + +static X509* DerToX509(SEC_BYTE* der, SEC_SIZE der_len) { + BIO* bio; + X509* x509; + + bio = BIO_new_mem_buf(der, static_cast(der_len)); + x509 = d2i_X509_bio(bio, nullptr); + SEC_BIO_FREE(bio); + + if (x509 == nullptr) { + SEC_LOG_ERROR("d2i_X509_bio failed"); + } + + return x509; +} + +Sec_Result testCertProvision(SEC_OBJECTID id, TestCert cert, Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (ctx.provisionCert(id, loc, cert) == nullptr) { + SEC_LOG_ERROR("TestCtx.provisionCert failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCertExport(SEC_OBJECTID id, TestCert cert, Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_CertificateHandle* certificateHandle; + if ((certificateHandle = ctx.provisionCert(id, loc, cert)) == nullptr) { + SEC_LOG_ERROR("TestCtx.provisionCert failed"); + return SEC_RESULT_FAILURE; + } + + SEC_SIZE written; + if (SecCertificate_Export(certificateHandle, nullptr, 0, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_Export failed"); + return SEC_RESULT_FAILURE; + } + + std::vector out; + out.resize(written); + if (SecCertificate_Export(certificateHandle, &out[0], out.size(), &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBundle_Export failed"); + return SEC_RESULT_FAILURE; + } + + X509* x509 = DerToX509(&out[0], out.size()); + if (x509 == nullptr) { + SEC_LOG_ERROR("DerToX509 failed"); + return SEC_RESULT_FAILURE; + } + SEC_X509_FREE(x509); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCertExportNoSha(SEC_OBJECTID id, TestCert cert) { + TestCtx ctx; + if (ctx.init("/tmp/sec_api_test_global", "/tmp/sec_api_test_app") != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_CertificateHandle* certificateHandle; + if ((certificateHandle = ctx.provisionCert(id, SEC_STORAGELOC_FILE, cert)) == nullptr) { + SEC_LOG_ERROR("TestCtx.provisionCert failed"); + return SEC_RESULT_FAILURE; + } + + ctx.releaseCert(certificateHandle); + + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + "/tmp/sec_api_test_app/", id); + SecUtils_RmFile(file_name_verification); + if ((certificateHandle = ctx.getCert(id)) == nullptr) { + SEC_LOG_ERROR("ctx.getCert failed"); + return SEC_RESULT_FAILURE; + } + + SEC_SIZE written; + if (SecCertificate_Export(certificateHandle, nullptr, 0, &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_Export failed"); + return SEC_RESULT_FAILURE; + } + + std::vector out; + out.resize(written); + if (SecCertificate_Export(certificateHandle, &out[0], out.size(), &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_Export failed"); + return SEC_RESULT_FAILURE; + } + + X509* x509 = DerToX509(&out[0], out.size()); + if (x509 == nullptr) { + SEC_LOG_ERROR("_DerToX509 failed"); + return SEC_RESULT_FAILURE; + } + SEC_X509_FREE(x509); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCertVerify(SEC_OBJECTID id_cert, TestCert cert, SEC_OBJECTID id_key, TestKey key, Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_CertificateHandle* certificateHandle; + if ((certificateHandle = ctx.provisionCert(id_cert, SEC_STORAGELOC_RAM, cert)) == nullptr) { + SEC_LOG_ERROR("TestCtx.provisionCert failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id_key, loc, key, TESTKC_RAW)) == nullptr) { + SEC_LOG_ERROR("TestCtx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsEcc(TestCreds::getKeyType(key)) != 0) { + Sec_ECCRawPublicKey pub_key; + if (SecCertificate_ExtractECCPublicKey(certificateHandle, &pub_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_ExtractECCPublicKey failed"); + return SEC_RESULT_FAILURE; + } + + if (SecCertificate_VerifyWithRawECCPublicKey(certificateHandle, &pub_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_VerifyWithRawECCPublicKey failed"); + return SEC_RESULT_FAILURE; + } + } else { + Sec_RSARawPublicKey pub_key; + if (SecCertificate_ExtractRSAPublicKey(certificateHandle, &pub_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_ExtractRSAPublicKey failed"); + return SEC_RESULT_FAILURE; + } + + if (SecCertificate_VerifyWithRawRSAPublicKey(certificateHandle, &pub_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_VerifyWithRawRSAPublicKey failed"); + return SEC_RESULT_FAILURE; + } + } + + if (SecCertificate_Verify(certificateHandle, keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_Verify failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCertSignWithPkcs7(SEC_OBJECTID id_cert, TestCert cert, SEC_OBJECTID id_key, TestKey key, + Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_CertificateHandle* certificateHandle; + if ((certificateHandle = ctx.provisionCert(id_cert, SEC_STORAGELOC_RAM, cert)) == nullptr) { + SEC_LOG_ERROR("TestCtx.provisionCert failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id_key, loc, key, TESTKC_RAW)) == nullptr) { + SEC_LOG_ERROR("TestCtx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + X509* x509Cert = nullptr; + RSA* rsa; + EVP_PKEY* evp; + BIO* bio = nullptr; + BIO* out = nullptr; + PKCS7* pkcs7 = nullptr; + int length; + Sec_Result result; + std::vector input = TestCtx::random(SEC_AES_BLOCK_SIZE); + unsigned char* message = nullptr; + unsigned char* messagePtr; + + do { + rsa = SecKey_ToEngineRSAWithCert(keyHandle, certificateHandle); + evp = EVP_PKEY_new(); + if (EVP_PKEY_assign(evp, EVP_PKEY_RSA, rsa) != 1) { + SEC_LOG_ERROR("EVP_PKEY_assign failed"); + result = SEC_RESULT_FAILURE; + break; + } + + rsa = nullptr; + + x509Cert = SecCertificate_ToX509(certificateHandle); + if (x509Cert == nullptr) { + SEC_LOG_ERROR("SecCertificate_ToX509 failed"); + result = SEC_RESULT_FAILURE; + break; + } + + /* signed message */ + bio = BIO_new_mem_buf(input.data(), static_cast(input.size())); + if (bio == nullptr) { + SEC_LOG_ERROR("BIO_new_mem_buf failed"); + result = SEC_RESULT_FAILURE; + break; + } + + pkcs7 = PKCS7_sign(x509Cert, evp, nullptr, bio, PKCS7_BINARY); + if (pkcs7 == nullptr) { + SEC_LOG_ERROR("PKCS7_sign failed: %s", ERR_error_string(ERR_get_error(), NULL)); + result = SEC_RESULT_FAILURE; + break; + } + + length = i2d_PKCS7(pkcs7, nullptr); + if (length < 0) { + SEC_LOG_ERROR("i2d_PKCS7 failed"); + result = SEC_RESULT_FAILURE; + break; + } + + message = static_cast(malloc(length)); + messagePtr = message; + length = i2d_PKCS7(pkcs7, &messagePtr); + if (length < 0) { + SEC_LOG_ERROR("i2d_PKCS7 failed"); + result = SEC_RESULT_FAILURE; + break; + } + + out = BIO_new(BIO_s_mem()); + if (PKCS7_verify(pkcs7, nullptr, nullptr, nullptr, out, PKCS7_NOVERIFY) != 1) { + SEC_LOG_ERROR("PKCS7_verify failed"); + result = SEC_RESULT_FAILURE; + break; + } + + BUF_MEM* bptr; + BIO_ctrl(out, BIO_C_GET_BUF_MEM_PTR, 0, &bptr); + if (memcmp(bptr->data, input.data(), input.size()) != 0) { + SEC_LOG_ERROR("data mismatch"); + result = SEC_RESULT_FAILURE; + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + SEC_RSA_FREE(rsa); + SEC_EVPPKEY_FREE(evp); + SEC_X509_FREE(x509Cert); + SEC_BIO_FREE(bio); + SEC_BIO_FREE(out); + if (pkcs7 != nullptr) + PKCS7_free(pkcs7); + + if (message != nullptr) + free(message); + return result; +} diff --git a/test/main/cpp/cert.h b/test/main/cpp/cert.h new file mode 100644 index 0000000..eab03cc --- /dev/null +++ b/test/main/cpp/cert.h @@ -0,0 +1,36 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CERT_H +#define CERT_H + +#include "sec_security.h" +#include "test_creds.h" + +Sec_Result testCertProvision(SEC_OBJECTID id, TestCert cert, Sec_StorageLoc loc); + +Sec_Result testCertExport(SEC_OBJECTID id, TestCert cert, Sec_StorageLoc loc); + +Sec_Result testCertExportNoSha(SEC_OBJECTID id, TestCert cert); + +Sec_Result testCertVerify(SEC_OBJECTID id_cert, TestCert cert, SEC_OBJECTID id_key, TestKey key, Sec_StorageLoc loc); + +Sec_Result testCertSignWithPkcs7(SEC_OBJECTID id_cert, TestCert cert, SEC_OBJECTID id_key, TestKey key, + Sec_StorageLoc loc); + +#endif // CERT_H diff --git a/test/main/cpp/cipher.cpp b/test/main/cpp/cipher.cpp new file mode 100644 index 0000000..c82c83b --- /dev/null +++ b/test/main/cpp/cipher.cpp @@ -0,0 +1,1373 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "cipher.h" +#include "digest.h" +#include "test_ctx.h" +#include +#include +#include + +#define BUFFER_SIZE 4096 +#define SUBSAMPLE_SIZE 256 + +static std::vector opensslAesCbc(TestKey key, Sec_CipherMode mode, bool padding, SEC_BYTE* iv, + const std::vector& input) { + + std::vector openssl_key = TestCreds::asOpenSslAes(key); + if (openssl_key.empty()) { + SEC_LOG_ERROR("TestCreds::asOpenSslAes failed"); + return {}; + } + const EVP_CIPHER* evp_cipher; + if (openssl_key.size() == 16) + evp_cipher = EVP_aes_128_cbc(); + else + evp_cipher = EVP_aes_256_cbc(); + + std::shared_ptr p_evp_ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); + + if (EVP_CipherInit_ex(p_evp_ctx.get(), evp_cipher, nullptr, nullptr, nullptr, + (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) ? 1 : 0) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherInit failed"); + return {}; + } + + if (EVP_CIPHER_CTX_set_padding(p_evp_ctx.get(), padding ? 1 : 0) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CIPHER_CTX_set_padding failed"); + return {}; + } + + if (EVP_CipherInit_ex(p_evp_ctx.get(), nullptr, nullptr, &openssl_key[0], iv, + (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) ? 1 : 0) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherInit failed"); + return {}; + } + + std::vector output; + output.resize(input.size() + SEC_AES_BLOCK_SIZE); + + SEC_SIZE written = 0; + int outlen = 0; + + if (EVP_CipherUpdate(p_evp_ctx.get(), &output[0], &outlen, &input[0], static_cast(input.size())) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherUpdate failed"); + return {}; + } + written += outlen; + outlen = 0; + + if (EVP_CipherFinal_ex(p_evp_ctx.get(), &output[written], &outlen) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherFinal failed"); + return {}; + } + + written += outlen; + output.resize(written); + return output; +} + +std::vector opensslAesEcb(const std::vector& openssl_key, Sec_CipherMode mode, SEC_BOOL padding, + SEC_BYTE* iv, const std::vector& input) { + std::vector output; + const EVP_CIPHER* evp_cipher; + + if (openssl_key.size() == 16) { + evp_cipher = EVP_aes_128_ecb(); + } else { + evp_cipher = EVP_aes_256_ecb(); + } + + std::shared_ptr p_evp_ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); + if (EVP_CipherInit_ex(p_evp_ctx.get(), evp_cipher, nullptr, nullptr, nullptr, + (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) ? 1 : 0) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherInit failed"); + return {}; + } + + if (EVP_CIPHER_CTX_set_padding(p_evp_ctx.get(), padding) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CIPHER_CTX_set_padding failed"); + return {}; + } + + if (EVP_CipherInit_ex(p_evp_ctx.get(), nullptr, nullptr, &openssl_key[0], iv, + (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) ? 1 : 0) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherInit failed"); + return {}; + } + + output.resize(input.size() + SEC_AES_BLOCK_SIZE); + + SEC_SIZE written = 0; + int outlen = 0; + if (EVP_CipherUpdate(p_evp_ctx.get(), &output[0], &outlen, &input[0], static_cast(input.size())) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherUpdate failed"); + return {}; + } + written += outlen; + outlen = 0; + + if (EVP_CipherFinal_ex(p_evp_ctx.get(), &output[written], &outlen) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherFinal failed"); + return {}; + } + + written += outlen; + output.resize(written); + + return output; +} + +std::vector opensslAesEcb(TestKey key, Sec_CipherMode mode, bool padding, SEC_BYTE* iv, + const std::vector& input) { + std::vector output; + std::vector openssl_key = TestCreds::asOpenSslAes(key); + const EVP_CIPHER* evp_cipher; + + if (openssl_key.size() == 16) { + evp_cipher = EVP_aes_128_ecb(); + } else { + evp_cipher = EVP_aes_256_ecb(); + } + + std::shared_ptr p_evp_ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); + if (EVP_CipherInit_ex(p_evp_ctx.get(), evp_cipher, nullptr, nullptr, nullptr, + (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) ? 1 : 0) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherInit failed"); + return {}; + } + + if (EVP_CIPHER_CTX_set_padding(p_evp_ctx.get(), padding ? 1 : 0) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CIPHER_CTX_set_padding failed"); + return {}; + } + + if (EVP_CipherInit_ex(p_evp_ctx.get(), nullptr, nullptr, &openssl_key[0], iv, + (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) ? 1 : 0) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherInit failed"); + return {}; + } + + output.resize(input.size() + SEC_AES_BLOCK_SIZE); + + SEC_SIZE written = 0; + int outlen = 0; + if (EVP_CipherUpdate(p_evp_ctx.get(), &output[0], &outlen, &input[0], static_cast(input.size())) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherUpdate failed"); + return {}; + } + written += outlen; + outlen = 0; + + if (EVP_CipherFinal_ex(p_evp_ctx.get(), &output[written], &outlen) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherFinal failed"); + return {}; + } + + written += outlen; + output.resize(written); + return output; +} + +static std::vector opensslAesCtr(TestKey key, Sec_CipherMode mode, SEC_BYTE* iv, + const std::vector& input) { + + std::vector openssl_key = TestCreds::asOpenSslAes(key); + SEC_BYTE ivToUse[SEC_AES_BLOCK_SIZE]; + memcpy(ivToUse, iv, SEC_AES_BLOCK_SIZE); + + std::vector output; + output.resize(input.size()); + + std::shared_ptr evp_ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); + EVP_CIPHER_CTX_init(evp_ctx.get()); + if (EVP_CipherInit_ex(evp_ctx.get(), (openssl_key.size() == 16) ? EVP_aes_128_ctr() : EVP_aes_256_ctr(), nullptr, + &openssl_key[0], ivToUse, + (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) ? 1 : 0) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherInit_ex failed"); + return {}; + } + + int out_len = 0; + if (EVP_CipherUpdate(evp_ctx.get(), &output[0], &out_len, &input[0], static_cast(input.size())) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherUpdate failed"); + return {}; + } + + if (EVP_CipherFinal_ex(evp_ctx.get(), &output[out_len], &out_len) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherFinal failed"); + return {}; + } + + return output; +} + +std::vector opensslAesGcm(const std::vector& key, Sec_CipherMode mode, SEC_BYTE* iv, SEC_BYTE* aad, + SEC_SIZE aad_length, SEC_BYTE* tag, SEC_SIZE tag_length, const std::vector& input) { + + SEC_BYTE ivToUse[SEC_AES_BLOCK_SIZE]; + memcpy(ivToUse, iv, SEC_AES_BLOCK_SIZE); + + std::vector output; + output.resize(input.size()); + + std::shared_ptr evp_ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); + + // init cipher + const EVP_CIPHER* cipher = (key.size() == 16) ? EVP_aes_128_gcm() : EVP_aes_256_gcm(); + if (EVP_EncryptInit_ex(evp_ctx.get(), cipher, nullptr, nullptr, nullptr) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_EncryptInit_ex failed"); + return {}; + } + + // set iv length + if (EVP_CIPHER_CTX_ctrl(evp_ctx.get(), EVP_CTRL_GCM_SET_IVLEN, 12, nullptr) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CIPHER_CTX_ctrl failed"); + return {}; + } + + // init key and iv + if (EVP_EncryptInit_ex(evp_ctx.get(), cipher, nullptr, key.data(), iv) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_EncryptInit_ex failed"); + return {}; + } + + // turn off padding + if (EVP_CIPHER_CTX_set_padding(evp_ctx.get(), 0) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CIPHER_CTX_set_padding failed"); + return {}; + } + + int out_length = static_cast(input.size()); + if (aad != nullptr) { + if (EVP_EncryptUpdate(evp_ctx.get(), nullptr, &out_length, aad, static_cast(aad_length)) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_EncryptUpdate failed"); + return {}; + } + } + + if (EVP_CipherUpdate(evp_ctx.get(), &output[0], &out_length, &input[0], static_cast(input.size())) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EVP_CipherUpdate failed"); + return {}; + } + + if (tag != nullptr) { + // get tag + if (EVP_EncryptFinal_ex(evp_ctx.get(), nullptr, &out_length) != 1) { + SEC_LOG_ERROR("EVP_EncryptFinal_ex failed"); + return {}; + } + + uint8_t local_tag[16]; + if (EVP_CIPHER_CTX_ctrl(evp_ctx.get(), EVP_CTRL_GCM_GET_TAG, sizeof(local_tag), local_tag) != 1) { + return {}; + } + + memcpy(tag, local_tag, tag_length); + } + + return output; +} + +static std::vector opensslRsaCrypt(TestKey key, Sec_CipherAlgorithm algorithm, Sec_CipherMode mode, + const std::vector& input) { + + std::shared_ptr rsa(TestCreds::asOpenSslRsa(key), RSA_free); + if (rsa == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslRsa failed"); + return {}; + } + + int padding; + if (algorithm == SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING) { + padding = RSA_PKCS1_PADDING; + } else { + padding = RSA_PKCS1_OAEP_PADDING; + } + + int openssl_res; + std::vector output; + output.resize(RSA_size(rsa.get())); + + if (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) { + openssl_res = RSA_public_encrypt(static_cast(input.size()), &input[0], &output[0], rsa.get(), padding); + } else { + openssl_res = RSA_private_decrypt(static_cast(input.size()), &input[0], &output[0], rsa.get(), padding); + } + + if (openssl_res < 0) { + SEC_LOG_ERROR("%s", ERR_error_string(ERR_get_error(), nullptr)); + return {}; + } + + output.resize(openssl_res); + + return output; +} + +std::vector cipherOpenSSL(TestKey key, Sec_CipherAlgorithm alg, Sec_CipherMode mode, SEC_BYTE* iv, + const std::vector& input) { + + switch (alg) { + case SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING: + return opensslAesCbc(key, mode, alg == SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, iv, input); + + case SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING: + case SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING: + return opensslAesEcb(key, mode, alg == SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, iv, input); + + case SEC_CIPHERALGORITHM_AES_CTR: + return opensslAesCtr(key, mode, iv, input); + + case SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING: + case SEC_CIPHERALGORITHM_RSA_OAEP_PADDING: + return opensslRsaCrypt(key, alg, mode, input); + + default: + break; + } + + SEC_LOG_ERROR("Unimplemented"); + return {}; +} + +std::vector cipherSecApi(TestCtx* ctx, Sec_KeyHandle* keyHandle, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, const std::vector& iv, const std::vector& input, + const std::vector& inputSizes, SEC_BOOL inplace) { + + std::vector output = input; + output.resize(input.size() + BUFFER_SIZE); + + SEC_SIZE inputProcessed = 0; + SEC_SIZE outputWritten = 0; + SEC_SIZE written = 0; + + Sec_CipherHandle* cipherHandle = ctx->acquireCipher(alg, mode, keyHandle, const_cast(&iv[0])); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return {}; + } + + for (unsigned int i = 0; i < inputSizes.size() - 1; ++i) { + if (inputSizes[i] > 0) { + Sec_Result result = SecCipher_Process(cipherHandle, + const_cast(inplace == SEC_TRUE ? &output[inputProcessed] : &input[inputProcessed]), + inputSizes[i], SEC_FALSE, &output[outputWritten], output.size() - outputWritten, &written); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + outputWritten += written; + } + + inputProcessed += inputSizes[i]; + } + + //last input + Sec_Result result = SecCipher_Process(cipherHandle, + const_cast(inplace == SEC_TRUE ? &output[inputProcessed] : &input[inputProcessed]), + input.size() - inputProcessed, SEC_TRUE, &output[outputWritten], output.size() - outputWritten, &written); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + outputWritten += written; + output.resize(outputWritten); + ctx->releaseCipher(cipherHandle); + return output; +} + +std::vector cipherSecApiSingle(TestCtx* ctx, Sec_KeyHandle* keyHandle, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, const std::vector& iv, const std::vector& input, SEC_BOOL inplace) { + + std::vector output = input; + output.resize(input.size() + BUFFER_SIZE); + + SEC_SIZE written = 0; + + Sec_CipherHandle* cipherHandle = ctx->acquireCipher(alg, mode, keyHandle, const_cast(&iv[0])); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return {}; + } + + if (SecCipher_Process(cipherHandle, const_cast(inplace == SEC_TRUE ? &output[0] : &input[0]), + input.size(), SEC_TRUE, &output[0], output.size(), &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + output.resize(written); + + ctx->releaseCipher(cipherHandle); + + return output; +} + +std::vector cipherSecApiSingle(TestCtx* ctx, Sec_CipherHandle* cipherHandle, const std::vector& iv, + const std::vector& input, SEC_BOOL inplace) { + + std::vector output = input; + output.resize(input.size() + BUFFER_SIZE); + + SEC_SIZE written = 0; + + if (!iv.empty()) { + if (SecCipher_UpdateIV(cipherHandle, const_cast(&iv[0])) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_UpdateIV failed"); + return {}; + } + } + + Sec_Result result = SecCipher_Process(cipherHandle, + const_cast(inplace == SEC_TRUE ? &output[0] : &input[0]), input.size(), SEC_FALSE, &output[0], + output.size(), &written); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + output.resize(written); + + return output; +} + +Sec_Result testCipherSingle(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, SEC_SIZE inputSize, SEC_BOOL inplace) { + + std::vector inputSizes; + inputSizes.resize(1); + inputSizes[0] = inputSize; + + return testCipherMult(id, key, kc, loc, alg, mode, inputSizes, inplace); +} + +Sec_Result testCtrRollover(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherMode mode, + SEC_SIZE inputSize, SEC_BOOL inplace) { + + std::vector inputSizes; + inputSizes.resize(3); + inputSizes[0] = 16; + inputSize -= inputSizes[0]; + inputSizes[1] = 16; + inputSize -= inputSizes[1]; + inputSizes[2] = inputSize; + + return testCipherMult(id, key, kc, loc, SEC_CIPHERALGORITHM_AES_CTR, mode, inputSizes, inplace, SEC_TRUE); +} + +Sec_Result testCipherSingle(SEC_OBJECTID id, TestKey pub, TestKey priv, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg, Sec_CipherMode mode, SEC_SIZE inputSize, SEC_BOOL inplace) { + + std::vector inputSizes; + inputSizes.resize(1); + inputSizes[0] = inputSize; + + return testCipherMult(id, pub, priv, kc, loc, alg, mode, inputSizes, inplace); +} + +Sec_Result testCipherMult(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, const std::vector& inputSizes, SEC_BOOL inplace, + SEC_BOOL testCtrRollover) { + + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + std::vector openssl_key = TestCreds::asOpenSslAes(key); + TestCtx::printHex("key", openssl_key); + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + if (alg == SEC_CIPHERALGORITHM_AES_CTR && testCtrRollover == SEC_TRUE) { + //set iv to rollover + memset(&iv[8], 0xff, 8); + } + + TestCtx::printHex("iv", iv); + + //mode + bool testEncrypt = (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM); + + //gen clear input + std::vector clear = TestCtx::random(TestCtx::coalesceInputSizes(inputSizes)); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted; + if (testEncrypt) { + encrypted = cipherSecApi(&ctx, keyHandle, alg, SEC_CIPHERMODE_ENCRYPT, iv, clear, inputSizes, inplace); + } else { + //use openssl to encrypt + encrypted = cipherOpenSSL(key, alg, SEC_CIPHERMODE_ENCRYPT, &iv[0], clear); + } + + TestCtx::printHex("encrypted", encrypted); + + //decrypt + std::vector decrypted; + if (testEncrypt) { + //use openssl to decrypt + decrypted = cipherOpenSSL(key, alg, SEC_CIPHERMODE_DECRYPT, &iv[0], encrypted); + } else { + //use sec api to decrypt + decrypted = cipherSecApi(&ctx, keyHandle, alg, SEC_CIPHERMODE_DECRYPT, iv, encrypted, inputSizes, inplace); + } + + TestCtx::printHex("decrypted", decrypted); + + //check if results match + if (clear != decrypted) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCipherMult(SEC_OBJECTID id, TestKey pub, TestKey priv, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg, Sec_CipherMode mode, const std::vector& inputSizes, SEC_BOOL inplace) { + + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + //mode + bool testEncrypt = (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM); + + Sec_KeyHandle* keyHandle; + if (testEncrypt) { + if ((keyHandle = ctx.provisionKey(id, loc, pub, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + } else { + if ((keyHandle = ctx.provisionKey(id, loc, priv, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + } + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv", iv); + + //gen clear input + std::vector clear = TestCtx::random(TestCtx::coalesceInputSizes(inputSizes)); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted; + if (testEncrypt) { + encrypted = cipherSecApi(&ctx, keyHandle, alg, SEC_CIPHERMODE_ENCRYPT, iv, clear, inputSizes, inplace); + } else { + //use openssl to encrypt + encrypted = cipherOpenSSL(pub, alg, SEC_CIPHERMODE_ENCRYPT, &iv[0], clear); + } + + TestCtx::printHex("encrypted", encrypted); + + //decrypt + std::vector decrypted; + if (testEncrypt) { + //use openssl to decrypt + decrypted = cipherOpenSSL(priv, alg, SEC_CIPHERMODE_DECRYPT, &iv[0], encrypted); + } else { + //use sec api to decrypt + decrypted = cipherSecApi(&ctx, keyHandle, alg, SEC_CIPHERMODE_DECRYPT, iv, encrypted, inputSizes, inplace); + } + + TestCtx::printHex("decrypted", decrypted); + + //check if results match + if (clear != decrypted) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result cipherEncDecSingle(TestCtx* ctx, SEC_OBJECTID id, Sec_CipherAlgorithm alg, SEC_SIZE inputSize, + SEC_BOOL inplace) { + + std::vector inputSizes; + inputSizes.resize(1); + inputSizes[0] = inputSize; + + Sec_Result result = cipherEncDecMult(ctx, id, alg, inputSizes, inplace); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecMult failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result cipherEncDecSingle(TestCtx* ctx, SEC_OBJECTID id_pub, SEC_OBJECTID id_priv, Sec_CipherAlgorithm alg, + SEC_SIZE inputSize, SEC_BOOL inplace) { + + std::vector inputSizes; + inputSizes.resize(1); + inputSizes[0] = inputSize; + + Sec_Result result = cipherEncDecMult(ctx, id_pub, id_priv, alg, inputSizes, inplace); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecMult failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result cipherEncDecMult(TestCtx* ctx, SEC_OBJECTID id, Sec_CipherAlgorithm alg, + const std::vector& inputSizes, SEC_BOOL inplace) { + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv", iv); + + //gen clear input + std::vector clear = TestCtx::random(TestCtx::coalesceInputSizes(inputSizes)); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted = cipherSecApi(ctx, ctx->getKey(id), alg, SEC_CIPHERMODE_ENCRYPT, iv, clear, + inputSizes, inplace); + if (encrypted.empty()) { + SEC_LOG_ERROR("CipherSecApi failed"); + return SEC_RESULT_FAILURE; + } + TestCtx::printHex("encrypted", encrypted); + + //decrypt + std::vector decrypted = cipherSecApi(ctx, ctx->getKey(id), alg, SEC_CIPHERMODE_DECRYPT, iv, encrypted, + inputSizes, inplace); + if (decrypted.empty()) { + SEC_LOG_ERROR("CipherSecApi failed"); + return SEC_RESULT_FAILURE; + } + + TestCtx::printHex("decrypted", decrypted); + + //check if results match + if (clear != decrypted) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result cipherEncDecMult(TestCtx* ctx, SEC_OBJECTID id_pub, SEC_OBJECTID id_priv, Sec_CipherAlgorithm alg, + const std::vector& inputSizes, SEC_BOOL inplace) { + + //gen clear input + std::vector clear = TestCtx::random(TestCtx::coalesceInputSizes(inputSizes)); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted = cipherSecApi(ctx, ctx->getKey(id_pub), alg, SEC_CIPHERMODE_ENCRYPT, + {}, clear, inputSizes, inplace); + if (encrypted.empty()) { + SEC_LOG_ERROR("CipherSecApi failed"); + return SEC_RESULT_FAILURE; + } + + TestCtx::printHex("encrypted", encrypted); + + //decrypt + std::vector decrypted = cipherSecApi(ctx, ctx->getKey(id_priv), alg, SEC_CIPHERMODE_DECRYPT, + {}, encrypted, inputSizes, inplace); + if (decrypted.empty()) { + SEC_LOG_ERROR("CipherSecApi failed"); + return SEC_RESULT_FAILURE; + } + + TestCtx::printHex("decrypted", decrypted); + + //check if results match + if (clear != decrypted) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCipherBandwidth(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, SEC_SIZE inputSize, SEC_SIZE intervalS) { + + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv", iv); + + //mode + bool testEncrypt = (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM); + + //gen clear input + std::vector clear = TestCtx::random(inputSize); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted; + time_t start_t = 0; + time_t end_t = 0; + int loops = 0; + if (testEncrypt) { + start_t = time(nullptr); + end_t = start_t; + + while ((end_t - start_t) < static_cast(intervalS)) { + encrypted = cipherSecApiSingle(&ctx, keyHandle, alg, SEC_CIPHERMODE_ENCRYPT, iv, clear, SEC_FALSE); + ++loops; + end_t = time(nullptr); + } + } else { + //use openssl to encrypt + encrypted = cipherOpenSSL(key, alg, SEC_CIPHERMODE_ENCRYPT, &iv[0], clear); + } + + TestCtx::printHex("encrypted", encrypted); + + //decrypt + std::vector decrypted; + if (testEncrypt) { + //use openssl to decrypt + decrypted = cipherOpenSSL(key, alg, SEC_CIPHERMODE_DECRYPT, &iv[0], encrypted); + } else { + start_t = time(nullptr); + end_t = start_t; + + while ((end_t - start_t) < static_cast(intervalS)) { + decrypted = cipherSecApiSingle(&ctx, keyHandle, alg, SEC_CIPHERMODE_DECRYPT, iv, encrypted, SEC_FALSE); + ++loops; + end_t = time(nullptr); + } + } + + TestCtx::printHex("decrypted", decrypted); + + //check if results match + if (clear != decrypted) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + //print timing data + SEC_PRINT("Data processed: %d MB\n", (inputSize * loops) / (1024 * 1024)); + SEC_PRINT("Time elapsed: %d s\n", end_t - start_t); + if (end_t != start_t) { + SEC_PRINT("Bandwidth: %d MB/s\n", + ((inputSize * loops) / (1024 * 1024)) / (end_t - start_t)); + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCipherBandwidthSingleCipher(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg, Sec_CipherMode mode, SEC_SIZE inputSize, + SEC_SIZE intervalS) { + + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv", iv); + + //mode + bool testEncrypt = (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM); + + //gen clear input + std::vector clear = TestCtx::random(inputSize); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted; + time_t start_t = 0; + time_t end_t = 0; + int loops = 0; + if (testEncrypt) { + start_t = time(nullptr); + end_t = start_t; + + Sec_CipherHandle* cipherHandle = ctx.acquireCipher(alg, mode, keyHandle, &iv[0]); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return SEC_RESULT_FAILURE; + } + + while ((end_t - start_t) < static_cast(intervalS)) { + encrypted = cipherSecApiSingle(&ctx, cipherHandle, iv, clear, SEC_FALSE); + ++loops; + end_t = time(nullptr); + } + } else { + //use openssl to encrypt + encrypted = cipherOpenSSL(key, alg, SEC_CIPHERMODE_ENCRYPT, &iv[0], clear); + } + + //decrypt + std::vector decrypted; + if (testEncrypt) { + //use openssl to decrypt + decrypted = cipherOpenSSL(key, alg, SEC_CIPHERMODE_DECRYPT, &iv[0], encrypted); + } else { + start_t = time(nullptr); + end_t = start_t; + + Sec_CipherHandle* cipherHandle = ctx.acquireCipher(alg, mode, keyHandle, &iv[0]); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return SEC_RESULT_FAILURE; + } + + while ((end_t - start_t) < static_cast(intervalS)) { + decrypted = cipherSecApiSingle(&ctx, cipherHandle, iv, encrypted, SEC_FALSE); + ++loops; + end_t = time(nullptr); + } + } + + //print timing data + SEC_PRINT("Data processed: %d MB\n", (inputSize * loops) / (1024 * 1024)); + SEC_PRINT("Time elapsed: %d s\n", end_t - start_t); + if (end_t != start_t) { + SEC_PRINT("Bandwidth: %d MB/s\n", + ((inputSize * loops) / (1024 * 1024)) / (end_t - start_t)); + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCipherUpdateIV(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, SEC_SIZE inputSize, SEC_BOOL inplace) { + + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //gen ivs + std::vector iv1 = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv1", iv1); + std::vector iv2 = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv2", iv2); + + //mode + bool testEncrypt = (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM); + + //gen clear input + std::vector clear = TestCtx::random(inputSize); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted1; + std::vector encrypted2; + if (testEncrypt) { + Sec_CipherHandle* cipherHandle = ctx.acquireCipher(alg, SEC_CIPHERMODE_ENCRYPT, keyHandle, &iv1[0]); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return SEC_RESULT_FAILURE; + } + + encrypted1 = cipherSecApiSingle(&ctx, cipherHandle, iv1, clear, SEC_FALSE); + if (encrypted1.empty()) { + SEC_LOG_ERROR("CipherSecApiSingle failed"); + return SEC_RESULT_FAILURE; + } + encrypted2 = cipherSecApiSingle(&ctx, cipherHandle, iv2, clear, SEC_FALSE); + if (encrypted2.empty()) { + SEC_LOG_ERROR("CipherSecApiSingle failed"); + return SEC_RESULT_FAILURE; + } + } else { + //use openssl to encrypt + encrypted1 = cipherOpenSSL(key, alg, SEC_CIPHERMODE_ENCRYPT, &iv1[0], clear); + if (encrypted1.empty()) { + SEC_LOG_ERROR("CipherOpenSSL failed"); + return SEC_RESULT_FAILURE; + } + encrypted2 = cipherOpenSSL(key, alg, SEC_CIPHERMODE_ENCRYPT, &iv2[0], clear); + if (encrypted2.empty()) { + SEC_LOG_ERROR("CipherOpenSSL failed"); + return SEC_RESULT_FAILURE; + } + } + + TestCtx::printHex("encrypted1", encrypted1); + TestCtx::printHex("encrypted2", encrypted2); + + //decrypt + std::vector decrypted1; + std::vector decrypted2; + if (testEncrypt) { + //use openssl to decrypt + decrypted1 = cipherOpenSSL(key, alg, SEC_CIPHERMODE_DECRYPT, &iv1[0], encrypted1); + if (decrypted1.empty()) { + SEC_LOG_ERROR("CipherOpenSSL failed"); + return SEC_RESULT_FAILURE; + } + decrypted2 = cipherOpenSSL(key, alg, SEC_CIPHERMODE_DECRYPT, &iv2[0], encrypted2); + if (decrypted2.empty()) { + SEC_LOG_ERROR("CipherOpenSSL failed"); + return SEC_RESULT_FAILURE; + } + } else { + //use sec api to decrypt + Sec_CipherHandle* cipherHandle = ctx.acquireCipher(alg, SEC_CIPHERMODE_DECRYPT, keyHandle, &iv1[0]); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return SEC_RESULT_FAILURE; + } + + decrypted1 = cipherSecApiSingle(&ctx, cipherHandle, iv1, encrypted1, SEC_FALSE); + if (decrypted1.empty()) { + SEC_LOG_ERROR("CipherSecApiSingle failed"); + return SEC_RESULT_FAILURE; + } + decrypted2 = cipherSecApiSingle(&ctx, cipherHandle, iv2, encrypted2, SEC_FALSE); + if (decrypted2.empty()) { + SEC_LOG_ERROR("CipherSecApiSingle failed"); + return SEC_RESULT_FAILURE; + } + } + + TestCtx::printHex("decrypted1", decrypted1); + TestCtx::printHex("decrypted2", decrypted2); + + //check if results match + if (clear != decrypted1 || clear != decrypted2 || encrypted1 == encrypted2) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +std::vector cipherSecApiCtrSubBlock(TestCtx* ctx, Sec_KeyHandle* keyHandle, Sec_CipherMode mode, + const std::vector& iv, const std::vector& input, SEC_BOOL inplace) { + + std::vector output = input; + output.resize(input.size() + BUFFER_SIZE); + + SEC_SIZE inputProcessed = 0; + SEC_SIZE outputWritten = 0; + SEC_SIZE written = 0; + + Sec_CipherHandle* cipherHandle = ctx->acquireCipher(SEC_CIPHERALGORITHM_AES_CTR, mode, keyHandle, + const_cast(&iv[0])); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return {}; + } + + //calculate the offset and make sure it is not on the SEC_AES_BLOCK_SIZE boundary + SEC_SIZE split_offset = input.size() / 2; + if (split_offset % SEC_AES_BLOCK_SIZE == 0) { + split_offset -= 1; + } + + SEC_PRINT("init ctr: %d\n", Sec_BEBytesToUint64(const_cast(&iv[8]))); + uint64_t init_counter = Sec_BEBytesToUint64(const_cast(&iv[8])); + + if (SecCipher_Process(cipherHandle, const_cast(inplace == SEC_TRUE ? &output[0] : &input[0]), + split_offset, SEC_FALSE, &output[0], output.size(), &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + outputWritten += written; + inputProcessed += split_offset; + + //set the iv + uint64_t counter; + counter = init_counter + split_offset / SEC_AES_BLOCK_SIZE; + Sec_Uint64ToBEBytes(counter, const_cast(&iv[8])); + + SEC_PRINT("updated ctr: %d\n", Sec_BEBytesToUint64(const_cast(&iv[8]))); + + /* TODO + if (SecCipher_UpdateIV(cipherHandle, (SEC_BYTE*) &iv[0]) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_UpdateIV failed"); + return {}; + } + */ + + //last input + Sec_Result result = SecCipher_ProcessCtrWithDataShift(cipherHandle, + const_cast(inplace == SEC_TRUE ? &output[inputProcessed] : &input[inputProcessed]), + input.size() - inputProcessed, &output[outputWritten], output.size() - outputWritten, &written, + split_offset % SEC_AES_BLOCK_SIZE); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + outputWritten += written; + + output.resize(outputWritten); + + ctx->releaseCipher(cipherHandle); + + return output; +} + +Sec_Result testProcessCtrWithDataShift(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherMode mode, + SEC_BOOL inplace) { +#if 0 // Feature not implemented in SecApi 2 Adapter + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle *keyHandle = nullptr; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv", iv); + + /* TODO + //set the counter to ff to test rollover + memset(&iv[8], 0xff, 8); + */ + + //mode + SEC_BOOL testEncrypt = (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM); + + //gen clear input + std::vector clear = TestCtx::random(SEC_AES_BLOCK_SIZE * 3); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted; + std::vector ivCopy = iv; + if (testEncrypt) { + encrypted = cipherSecApiCtrSubBlock(&ctx, keyHandle, SEC_CIPHERMODE_ENCRYPT, ivCopy, clear, inplace); + } else { + //use openssl to encrypt + encrypted = cipherOpenSSL(key, SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, &ivCopy[0], clear); + } + + TestCtx::printHex("encrypted", encrypted); + TestCtx::printHex("iv", iv); + + //decrypt + std::vector decrypted; + if (testEncrypt) { + //use openssl to decrypt + decrypted = cipherOpenSSL(key, SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, &iv[0], encrypted); + } else { + //use sec api to decrypt + decrypted = cipherSecApiCtrSubBlock(&ctx, keyHandle, SEC_CIPHERMODE_DECRYPT, iv, encrypted, inplace); + } + + TestCtx::printHex("decrypted", decrypted); + + //check if results match + if (clear != decrypted) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } +#endif + return SEC_RESULT_SUCCESS; +} + +Sec_Result testProcessOpaqueWithMap(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg, SEC_SIZE subsampleCount, SEC_SIZE bytesOfClearData) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle = nullptr; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv", iv); + + //gen clear input + std::vector clear = TestCtx::random(SUBSAMPLE_SIZE * subsampleCount); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted; + std::vector ivCopy = iv; + + //use openssl to encrypt + std::vector temp; + for (size_t i = 0; i < subsampleCount; i++) { + temp.insert(temp.end(), + clear.begin() + static_cast(i * SUBSAMPLE_SIZE + bytesOfClearData), + clear.begin() + static_cast((i + 1) * SUBSAMPLE_SIZE)); + } + + std::vector encryptedTemp = cipherOpenSSL(key, alg, SEC_CIPHERMODE_ENCRYPT, &ivCopy[0], temp); + SEC_SIZE bytesOfProtectedData = SUBSAMPLE_SIZE - bytesOfClearData; + for (size_t i = 0; i < subsampleCount; i++) { + encrypted.insert(encrypted.end(), + clear.begin() + static_cast(i * SUBSAMPLE_SIZE), + clear.begin() + static_cast(i * SUBSAMPLE_SIZE + bytesOfClearData)); + encrypted.insert(encrypted.end(), + encryptedTemp.begin() + static_cast(i * bytesOfProtectedData), + encryptedTemp.begin() + static_cast((i + 1) * bytesOfProtectedData)); + } + + TestCtx::printHex("encrypted", encrypted); + TestCtx::printHex("iv", iv); + + Sec_CipherHandle* cipherHandle = ctx.acquireCipher(alg, SEC_CIPHERMODE_DECRYPT, keyHandle, &iv[0]); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return SEC_RESULT_FAILURE; + } + + auto* map = new SEC_MAP[subsampleCount]; + if (map == nullptr) { + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + for (SEC_SIZE i = 0; i < subsampleCount; i++) { + map[i].clear = bytesOfClearData; + map[i].encrypted = SUBSAMPLE_SIZE - bytesOfClearData; + } + + //decrypt + std::vector decrypted; + Sec_OpaqueBufferHandle* opaqueBufferHandle; + SEC_SIZE bytesWritten = 0; + Sec_Result result = SecCipher_ProcessOpaqueWithMap(cipherHandle, iv.data(), encrypted.data(), encrypted.size(), + SEC_TRUE, map, subsampleCount, &opaqueBufferHandle, &bytesWritten); + if (result != SEC_RESULT_SUCCESS) { + delete[] map; + SEC_LOG_ERROR("SecCipher_ProcessOpaqueWithMap failed"); + return result; + } + + //check if results match + auto expected = digestOpenSSL(SEC_DIGESTALGORITHM_SHA256, clear); + result = SecOpaqueBuffer_Check(SEC_DIGESTALGORITHM_SHA256, opaqueBufferHandle, clear.size(), expected.data(), + expected.size()); + delete[] map; + SecOpaqueBuffer_Free(opaqueBufferHandle); + return result; +} + +Sec_Result testProcessOpaqueWithMapVariable(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle = nullptr; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + size_t subsampleCount = 5; + size_t bytesOfClearDataCtr[5] = {0, 16, 20, 50, 256}; + size_t bytesOfClearDataCbc[5] = {0, 16, 32, 48, 256}; + size_t* bytesOfClearData = + (alg == SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING) ? bytesOfClearDataCbc : bytesOfClearDataCtr; + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("iv", iv); + + //gen clear input + std::vector clear = TestCtx::random(SUBSAMPLE_SIZE * subsampleCount); + TestCtx::printHex("clear", clear); + + //encrypt + std::vector encrypted; + std::vector ivCopy = iv; + + //use openssl to encrypt + std::vector temp; + for (size_t i = 0; i < subsampleCount; i++) { + temp.insert(temp.end(), + clear.begin() + static_cast(i * SUBSAMPLE_SIZE + bytesOfClearData[i]), + clear.begin() + static_cast((i + 1) * SUBSAMPLE_SIZE)); + } + + std::vector encryptedTemp = cipherOpenSSL(key, alg, SEC_CIPHERMODE_ENCRYPT, &ivCopy[0], temp); + int64_t pos = 0; + for (size_t i = 0; i < subsampleCount; i++) { + SEC_SIZE bytesOfProtectedData = SUBSAMPLE_SIZE - bytesOfClearData[i]; + encrypted.insert(encrypted.end(), + clear.begin() + static_cast(i * SUBSAMPLE_SIZE), + clear.begin() + static_cast(i * SUBSAMPLE_SIZE + bytesOfClearData[i])); + encrypted.insert(encrypted.end(), + encryptedTemp.begin() + pos, + encryptedTemp.begin() + pos + bytesOfProtectedData); + pos += bytesOfProtectedData; + } + + TestCtx::printHex("encrypted", encrypted); + TestCtx::printHex("iv", iv); + + Sec_CipherHandle* cipherHandle = ctx.acquireCipher(alg, SEC_CIPHERMODE_DECRYPT, keyHandle, &iv[0]); + if (cipherHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireCipher failed"); + return SEC_RESULT_FAILURE; + } + + auto* map = new SEC_MAP[subsampleCount]; + if (map == nullptr) { + SEC_LOG_ERROR("malloc failed"); + return SEC_RESULT_FAILURE; + } + + for (SEC_SIZE i = 0; i < subsampleCount; i++) { + map[i].clear = bytesOfClearData[i]; + map[i].encrypted = SUBSAMPLE_SIZE - bytesOfClearData[i]; + } + + //decrypt + std::vector decrypted; + Sec_OpaqueBufferHandle* opaqueBufferHandle; + SEC_SIZE bytesWritten = 0; + Sec_Result result = SecCipher_ProcessOpaqueWithMap(cipherHandle, iv.data(), encrypted.data(), encrypted.size(), + SEC_TRUE, map, subsampleCount, &opaqueBufferHandle, &bytesWritten); + if (result != SEC_RESULT_SUCCESS) { + delete[] map; + SEC_LOG_ERROR("SecCipher_ProcessOpaqueWithMap failed"); + return result; + } + + //check if results match + auto expected = digestOpenSSL(SEC_DIGESTALGORITHM_SHA256, clear); + result = SecOpaqueBuffer_Check(SEC_DIGESTALGORITHM_SHA256, opaqueBufferHandle, clear.size(), expected.data(), + expected.size()); + delete[] map; + SecOpaqueBuffer_Free(opaqueBufferHandle); + return result; +} + +Sec_Result aesKeyCheck(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID id, SEC_BYTE* key, SEC_SIZE key_len) { + SEC_PRINT("--- aes key check ---\n"); + + std::vector clear = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("clear", clear); + + std::vector cipher_secapi; + cipher_secapi.resize(SEC_AES_BLOCK_SIZE); + SEC_SIZE cipher_secapi_len; + + if (SecCipher_SingleInputId(processorHandle, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, id, + nullptr, &clear[0], clear.size(), &cipher_secapi[0], cipher_secapi.size(), &cipher_secapi_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + cipher_secapi.resize(cipher_secapi_len); + TestCtx::printHex("cipher_secapi", cipher_secapi); + + std::vector openssl_key = std::vector(key, key + key_len); + + std::vector cipher_ssl = opensslAesEcb(openssl_key, SEC_CIPHERMODE_ENCRYPT, SEC_FALSE, nullptr, clear); + + TestCtx::printHex("cipher_ssl", cipher_ssl); + + SEC_PRINT("---------------------\n"); + + //check if results match + if (cipher_secapi != cipher_ssl) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/cipher.h b/test/main/cpp/cipher.h new file mode 100644 index 0000000..afc80ff --- /dev/null +++ b/test/main/cpp/cipher.h @@ -0,0 +1,84 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CIPHER_H +#define CIPHER_H + +#include "sec_security.h" +#include "test_creds.h" + +Sec_Result testCipherSingle(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, SEC_SIZE inputSize, SEC_BOOL inplace = SEC_FALSE); + +Sec_Result testCipherSingle(SEC_OBJECTID id, TestKey pub, TestKey priv, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg, Sec_CipherMode mode, SEC_SIZE inputSize, SEC_BOOL inplace = SEC_FALSE); + +Sec_Result testCipherMult(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, const std::vector& inputSizes, SEC_BOOL inplace = SEC_FALSE, + SEC_BOOL testCtrRollover = SEC_FALSE); + +Sec_Result testCipherMult(SEC_OBJECTID id, TestKey pub, TestKey priv, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg, Sec_CipherMode mode, const std::vector& inputSizes, + SEC_BOOL inplace = SEC_FALSE); + +Sec_Result testCipherBandwidth(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, SEC_SIZE inputSize, SEC_SIZE intervalS); + +Sec_Result testCipherBandwidthSingleCipher(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg, Sec_CipherMode mode, SEC_SIZE inputSize, SEC_SIZE intervalS); + +Sec_Result cipherEncDecSingle(TestCtx* ctx, SEC_OBJECTID id, Sec_CipherAlgorithm alg, SEC_SIZE inputSize, + SEC_BOOL inplace = SEC_FALSE); + +Sec_Result cipherEncDecMult(TestCtx* ctx, SEC_OBJECTID id, Sec_CipherAlgorithm alg, + const std::vector& inputSizes, SEC_BOOL inplace = SEC_FALSE); + +Sec_Result cipherEncDecSingle(TestCtx* ctx, SEC_OBJECTID id_pub, SEC_OBJECTID id_priv, Sec_CipherAlgorithm alg, + SEC_SIZE inputSize, SEC_BOOL inplace = SEC_FALSE); + +Sec_Result cipherEncDecMult(TestCtx* ctx, SEC_OBJECTID id_pub, SEC_OBJECTID id_priv, Sec_CipherAlgorithm alg, + const std::vector& inputSizes, SEC_BOOL inplace = SEC_FALSE); + +Sec_Result testCipherUpdateIV(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherAlgorithm alg, + Sec_CipherMode mode, SEC_SIZE inputSize, SEC_BOOL inplace); + +Sec_Result testProcessCtrWithDataShift(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherMode mode, + SEC_BOOL inplace); + +std::vector opensslAesEcb(TestKey key, Sec_CipherMode mode, bool padding, SEC_BYTE* iv, + const std::vector& input); + +std::vector opensslAesEcb(const std::vector& key, Sec_CipherMode mode, SEC_BOOL padding, + SEC_BYTE* iv, const std::vector& input); + +std::vector opensslAesGcm(const std::vector& key, Sec_CipherMode mode, SEC_BYTE* iv, SEC_BYTE* aad, + SEC_SIZE aad_length, SEC_BYTE* tag, SEC_SIZE tag_length, + const std::vector& input); + +Sec_Result aesKeyCheck(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID id, SEC_BYTE* key, SEC_SIZE key_len); + +Sec_Result testCtrRollover(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_CipherMode mode, + SEC_SIZE inputSize, SEC_BOOL inplace); + +Sec_Result testProcessOpaqueWithMap(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg, SEC_SIZE subsampleCount, SEC_SIZE bytesOfClearData); + +Sec_Result testProcessOpaqueWithMapVariable(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm alg); + +#endif // CIPHER_H diff --git a/test/main/cpp/concurrent.cpp b/test/main/cpp/concurrent.cpp new file mode 100644 index 0000000..e7443fc --- /dev/null +++ b/test/main/cpp/concurrent.cpp @@ -0,0 +1,131 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "concurrent.h" // NOLINT +#include "cipher.h" +#include "key.h" + +struct Vendor128Args { // NOLINT(altera-struct-pack-align) + SEC_OBJECTID id; + Sec_Result result; +}; + +void* concurrent_vendor128(void* arg) { + auto* args = static_cast(arg); + + args->result = testKeyDeriveKeyLadderAes128( + args->id, + SEC_KEYTYPE_AES_128, + SEC_STORAGELOC_RAM, + SEC_KEYLADDERROOT_UNIQUE, + SEC_TRUE); + + return nullptr; +} + +Sec_Result testConcurrentVendor128(SEC_SIZE numThreads) { + + std::vector threads; + std::vector args; + threads.resize(numThreads); + args.resize(numThreads); + + SEC_PRINT("Spawning %d threads\n", numThreads); + for (unsigned int i = 0; i < threads.size(); ++i) { + args[i].id = SEC_OBJECTID_USER_BASE + i; + + pthread_create(&threads[i], nullptr, concurrent_vendor128, &args[i]); + } + + SEC_PRINT("Waiting for threads to complete\n"); + for (auto& thread : threads) { + pthread_join(thread, nullptr); + } + + SEC_PRINT("Threads completed\n"); + + //check results + SEC_PRINT("Checking results\n"); + for (auto& arg : args) { + if (arg.result != SEC_RESULT_SUCCESS) { + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +struct RsaArgs { + SEC_OBJECTID id; + TestKey pub; + TestKey priv; + TestKc kc; + + Sec_Result result; +} __attribute__((aligned(32))); + +void* concurrent_rsa(void* arg) { + auto* args = static_cast(arg); + + args->result = testCipherSingle( + args->id, + args->pub, + args->priv, + args->kc, + SEC_STORAGELOC_RAM, + SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING, + SEC_CIPHERMODE_DECRYPT, + SEC_AES_BLOCK_SIZE); + + return nullptr; +} + +Sec_Result testConcurrentRsa(TestKey pub, TestKey priv, TestKc kc, SEC_SIZE numThreads) { + + std::vector threads; + std::vector args; + threads.resize(numThreads); + args.resize(numThreads); + + SEC_PRINT("Spawning %d threads\n", numThreads); + for (unsigned int i = 0; i < threads.size(); ++i) { + args[i].id = SEC_OBJECTID_USER_BASE + i; + args[i].pub = pub; + args[i].priv = priv; + args[i].kc = kc; + + pthread_create(&threads[i], nullptr, concurrent_rsa, &args[i]); + } + + SEC_PRINT("Waiting for threads to complete\n"); + for (auto& thread : threads) { + pthread_join(thread, nullptr); + } + + SEC_PRINT("Threads completed\n"); + + //check results + SEC_PRINT("Checking results\n"); + for (auto& arg : args) { + if (arg.result != SEC_RESULT_SUCCESS) { + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/concurrent.h b/test/main/cpp/concurrent.h new file mode 100644 index 0000000..8431037 --- /dev/null +++ b/test/main/cpp/concurrent.h @@ -0,0 +1,29 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CONCURRENT_H +#define CONCURRENT_H + +#include "sec_security.h" +#include "test_creds.h" + +Sec_Result testConcurrentVendor128(SEC_SIZE numThreads); + +Sec_Result testConcurrentRsa(TestKey pub, TestKey priv, TestKc kc, SEC_SIZE numThreads); + +#endif // CONCURRENT_H diff --git a/test/main/cpp/digest.cpp b/test/main/cpp/digest.cpp new file mode 100644 index 0000000..1269b79 --- /dev/null +++ b/test/main/cpp/digest.cpp @@ -0,0 +1,188 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "digest.h" +#include "test_ctx.h" +#include + +std::vector digestOpenSSL(Sec_DigestAlgorithm alg, const std::vector& input) { + std::vector digest; + + switch (alg) { + case SEC_DIGESTALGORITHM_SHA1: + digest.resize(20); + SHA1(&input[0], input.size(), &digest[0]); + return digest; + + case SEC_DIGESTALGORITHM_SHA256: + digest.resize(32); + SHA256(&input[0], input.size(), &digest[0]); + return digest; + + default: + break; + } + + SEC_LOG_ERROR("Unimplemented"); + return {}; +} + +std::vector digestSecApi(TestCtx* ctx, Sec_DigestAlgorithm alg, const std::vector& input, + const std::vector& inputSizes) { + + std::vector output; + output.resize(SEC_DIGEST_MAX_LEN); + + SEC_SIZE inputProcessed = 0; + SEC_SIZE written = 0; + + Sec_DigestHandle* digestHandle = ctx->acquireDigest(alg); + if (digestHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireDigest failed"); + return {}; + } + + for (unsigned int inputSize : inputSizes) { + if (inputSize > 0) { + if (SecDigest_Update(digestHandle, const_cast(&input[inputProcessed]), inputSize) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_Update failed"); + return {}; + } + } + + inputProcessed += inputSize; + } + + //last input + if (ctx->releaseDigest(digestHandle, &output[0], &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + output.resize(written); + + return output; +} + +std::vector digestSecApi(TestCtx* ctx, Sec_DigestAlgorithm alg, Sec_KeyHandle* keyHandle) { + + std::vector output; + output.resize(SEC_DIGEST_MAX_LEN); + + SEC_SIZE written = 0; + + Sec_DigestHandle* digestHandle = ctx->acquireDigest(alg); + if (digestHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireDigest failed"); + return {}; + } + + if (SecDigest_UpdateWithKey(digestHandle, keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_Update failed"); + return {}; + } + + if (ctx->releaseDigest(digestHandle, &output[0], &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + output.resize(written); + + return output; +} + +Sec_Result testDigestOverKey(Sec_DigestAlgorithm alg, SEC_OBJECTID id, TestKey key, Sec_StorageLoc loc) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle *keyHandle; + + if (TestCreds::supports(CAPABILITY_DIGEST_OVER_HWKEY)) { + if ((keyHandle = ctx.provisionKey(id, loc, key, TESTKC_RAW)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + } else { + if ((keyHandle = ctx.provisionKey(id, loc, key, TESTKC_RAW, SEC_TRUE)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + } + + //gen clear input + std::vector clear = TestCreds::asOpenSslAes(key); + TestCtx::printHex("key", clear); + + //digest + std::vector digestSA = digestSecApi(&ctx, alg, keyHandle); + TestCtx::printHex("digestSecApi", digestSA); + + std::vector digestOS = digestOpenSSL(alg, clear); + TestCtx::printHex("digestOpenssl", digestOS); + + //check if results match + if (digestSA != digestOS) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testDigestSingle(Sec_DigestAlgorithm alg, SEC_SIZE inputSize) { + std::vector inputSizes; + inputSizes.resize(1); + inputSizes[0] = inputSize; + + return testDigestMult(alg, inputSizes); +} + +Sec_Result testDigestMult(Sec_DigestAlgorithm alg, const std::vector& inputSizes) { + + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + //gen clear input + std::vector clear = TestCtx::random(TestCtx::coalesceInputSizes(inputSizes)); + TestCtx::printHex("clear", clear); + + //digest + std::vector digestSA = digestSecApi(&ctx, alg, clear, inputSizes); + TestCtx::printHex("digestSecApi", digestSA); + + std::vector digestOS = digestOpenSSL(alg, clear); + TestCtx::printHex("digestOpenssl", digestOS); + + //check if results match + if (digestSA != digestOS) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/digest.h b/test/main/cpp/digest.h new file mode 100644 index 0000000..8d38f62 --- /dev/null +++ b/test/main/cpp/digest.h @@ -0,0 +1,34 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DIGEST_H +#define DIGEST_H + +#include "sec_security.h" +#include "test_creds.h" +#include + +Sec_Result testDigestSingle(Sec_DigestAlgorithm alg, SEC_SIZE inputSize); + +Sec_Result testDigestMult(Sec_DigestAlgorithm alg, const std::vector& inputSizes); + +Sec_Result testDigestOverKey(Sec_DigestAlgorithm alg, SEC_OBJECTID id, TestKey key, Sec_StorageLoc loc); + +std::vector digestOpenSSL(Sec_DigestAlgorithm alg, const std::vector& input); + +#endif // DIGEST_H diff --git a/test/main/cpp/exchange.cpp b/test/main/cpp/exchange.cpp new file mode 100644 index 0000000..29e5d97 --- /dev/null +++ b/test/main/cpp/exchange.cpp @@ -0,0 +1,663 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "exchange.h" // NOLINT +#include "cipher.h" +#include "mac.h" +#include "sec_adapter_utils.h" +#include "test_ctx.h" + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#include +#endif + +// Some of the values here are derived from RFC 3526 which is +// Copyright (C) The Internet Society (2003). All Rights Reserved. +static SEC_BYTE g_dh_p[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, + 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, + 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, + 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, + 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, + 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, + 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, + 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, + 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, + 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, + 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36, + 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, + 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, + 0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, + 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08, + 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b, + 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, + 0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, + 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7c, + 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10, + 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xaa, 0xc4, 0x2d, 0xad, 0x33, 0x17, 0x0d, + 0x04, 0x50, 0x7a, 0x33, 0xa8, 0x55, 0x21, 0xab, 0xdf, 0x1c, 0xba, 0x64, + 0xec, 0xfb, 0x85, 0x04, 0x58, 0xdb, 0xef, 0x0a, 0x8a, 0xea, 0x71, 0x57, + 0x5d, 0x06, 0x0c, 0x7d, 0xb3, 0x97, 0x0f, 0x85, 0xa6, 0xe1, 0xe4, 0xc7, + 0xab, 0xf5, 0xae, 0x8c, 0xdb, 0x09, 0x33, 0xd7, 0x1e, 0x8c, 0x94, 0xe0, + 0x4a, 0x25, 0x61, 0x9d, 0xce, 0xe3, 0xd2, 0x26, 0x1a, 0xd2, 0xee, 0x6b, + 0xf1, 0x2f, 0xfa, 0x06, 0xd9, 0x8a, 0x08, 0x64, 0xd8, 0x76, 0x02, 0x73, + 0x3e, 0xc8, 0x6a, 0x64, 0x52, 0x1f, 0x2b, 0x18, 0x17, 0x7b, 0x20, 0x0c, + 0xbb, 0xe1, 0x17, 0x57, 0x7a, 0x61, 0x5d, 0x6c, 0x77, 0x09, 0x88, 0xc0, + 0xba, 0xd9, 0x46, 0xe2, 0x08, 0xe2, 0x4f, 0xa0, 0x74, 0xe5, 0xab, 0x31, + 0x43, 0xdb, 0x5b, 0xfc, 0xe0, 0xfd, 0x10, 0x8e, 0x4b, 0x82, 0xd1, 0x20, + 0xa9, 0x3a, 0xd2, 0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +static SEC_BYTE g_dh_g[] = { + 0x02, +}; + +static EC_KEY* ECCFromPubBinary(Sec_ECCRawPublicKey* binary) { + BN_CTX* ctx = BN_CTX_new(); + + if (binary->type != SEC_KEYTYPE_ECC_NISTP256_PUBLIC && binary->type != SEC_KEYTYPE_ECC_NISTP256) + return nullptr; + + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); //create ec_key structure with NIST p256 curve; + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + EC_POINT* ec_point = EC_POINT_new(group); + BN_CTX_start(ctx); + BIGNUM* xp; + BIGNUM* yp; + do { + if (((xp = BN_CTX_get(ctx)) == nullptr) || ((yp = BN_CTX_get(ctx)) == nullptr)) + break; + + EC_POINT_set_affine_coordinates_GFp(group, ec_point, + BN_bin2bn(binary->x, static_cast(Sec_BEBytesToUint32(binary->key_len)), xp), + BN_bin2bn(binary->y, static_cast(Sec_BEBytesToUint32(binary->key_len)), yp), ctx); + EC_KEY_set_public_key(ec_key, ec_point); + } while (false); + + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return ec_key; +} + +static Sec_KeyType GroupToKeyType(const EC_GROUP* group) { + if (nullptr == group) + return SEC_KEYTYPE_NUM; + switch (EC_GROUP_get_curve_name(group)) { + case NID_X9_62_prime256v1: + return SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + case 0: + default: + return SEC_KEYTYPE_NUM; + } +} + +static Sec_Result BigNumToBuffer(const BIGNUM* bignum, SEC_BYTE* buffer, SEC_SIZE buffer_len) { + SEC_SIZE num_bytes; + + memset(buffer, 0, buffer_len); + num_bytes = BN_num_bytes(bignum); + + if (num_bytes > buffer_len) { + SEC_LOG_ERROR("Buffer not large enough. needed: %d, actual: %d", num_bytes, buffer_len); + return SEC_RESULT_FAILURE; + } + + BN_bn2bin(bignum, buffer + buffer_len - num_bytes); + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result Extract_EC_KEY_X_Y(const EC_KEY* ec_key, BIGNUM** xp, BIGNUM** yp, Sec_KeyType* keyTypep) { + const EC_GROUP* group; + const EC_POINT* ec_point; + BN_CTX* ctx = nullptr; + Sec_Result result = SEC_RESULT_FAILURE; + + do { + if (xp == nullptr) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: X cannot be NULL"); + break; + } + + group = EC_KEY_get0_group(ec_key); + if (group == nullptr) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_KEY_get0_group: %s", + ERR_error_string(ERR_get_error(), nullptr)); + break; + } + + ec_point = EC_KEY_get0_public_key(ec_key); + if (ec_point == nullptr) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_KEY_get0_public_key: %s", + ERR_error_string(ERR_get_error(), nullptr)); + break; + } + + ctx = BN_CTX_new(); + if (ctx == nullptr) { + SEC_LOG_ERROR("BN_CTX_new() failed"); + break; + } + + *xp = BN_new(); + if (*xp == nullptr) { + SEC_LOG_ERROR("BN_new() failed"); + break; + } + + if (nullptr != yp) { // if caller wants y coordinate returned + *yp = BN_new(); + if (*yp == nullptr) { + SEC_LOG_ERROR("BN_new() failed"); + break; + } + } + + if (nullptr != keyTypep) { // if caller wants key type returned + *keyTypep = GroupToKeyType(group); + } + + // Get the X coordinate and optionally the Y coordinate + if (EC_POINT_get_affine_coordinates_GFp(group, ec_point, *xp, yp != nullptr ? *yp : nullptr, ctx) != 1) { + BN_clear_free(*xp); + if (nullptr != yp) + BN_clear_free(*yp); + + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_POINT_get_affine_coordinates_GFp: %s", + ERR_error_string(ERR_get_error(), nullptr)); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (nullptr != ctx) + BN_CTX_free(ctx); + + return result; +} + +static Sec_Result ECCToPubBinary(EC_KEY* ec_key, Sec_ECCRawPublicKey* binary) { + BIGNUM* x = nullptr; + BIGNUM* y = nullptr; + Sec_KeyType keyType; + + if (Extract_EC_KEY_X_Y(ec_key, &x, &y, &keyType) != SEC_RESULT_SUCCESS) { + + SEC_LOG_ERROR("_Extract_EC_KEY_X_Y failed"); + return SEC_RESULT_FAILURE; + } + + binary->type = keyType; + Sec_Uint32ToBEBytes(SecKey_GetKeyLenForKeyType(keyType), binary->key_len); + BigNumToBuffer(x, binary->x, Sec_BEBytesToUint32(binary->key_len)); + BigNumToBuffer(y, binary->y, Sec_BEBytesToUint32(binary->key_len)); + + BN_free(y); + BN_free(x); + return SEC_RESULT_SUCCESS; +} + +static DH* DH_create(SEC_BYTE* p, SEC_SIZE p_len, SEC_BYTE* g, SEC_SIZE g_len) { + DH* dh; + + if ((dh = DH_new()) == nullptr) { + SEC_LOG_ERROR("DH_new failed"); + return nullptr; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + dh->p = BN_bin2bn(p, static_cast(p_len), nullptr); + dh->g = BN_bin2bn(g, static_cast(g_len), nullptr); + + if ((dh->p == nullptr) || (dh->g == nullptr)) { + SEC_LOG_ERROR("BN_bin2bn failed"); + DH_free(dh); + return nullptr; + } + + dh->length = static_cast(p_len) * 8L; +#else + BIGNUM* bnp = BN_bin2bn(p, static_cast(p_len), nullptr); + BIGNUM* bng = BN_bin2bn(g, static_cast(g_len), nullptr); + DH_set0_pqg(dh, bnp, nullptr, bng); +#endif + + return dh; +} + +static Sec_Result DH_generate_key(DH* dh, SEC_BYTE* publicKey, SEC_SIZE pubKeySize, SEC_SIZE* out_len) { + if (DH_generate_key(dh) == 0) { + SEC_LOG_ERROR("DH_generate_key failed"); + DH_free(dh); + return SEC_RESULT_FAILURE; + } + + SEC_SIZE modulus_size = DH_size(dh); + if (pubKeySize < modulus_size) { + SEC_LOG_ERROR("Buffer to small"); + return SEC_RESULT_FAILURE; + } + + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + int temp_len = BN_bn2bin(dh->pub_key, publicKey); +#else + const BIGNUM* pub_key = nullptr; + DH_get0_key(dh, &pub_key, nullptr); + + int temp_len = BN_bn2bin(pub_key, publicKey); +#endif + if (temp_len <= 0) { + SEC_LOG_ERROR("DH_compute_key failed"); + return SEC_RESULT_FAILURE; + } + + if (temp_len < modulus_size) { + memmove(publicKey + modulus_size - temp_len, publicKey, temp_len); + memset(publicKey, 0, modulus_size - temp_len); + } + + *out_len = modulus_size; + return SEC_RESULT_SUCCESS; +} + +static Sec_Result DH_compute(DH* dh, SEC_BYTE* pub_key, SEC_SIZE pub_key_len, SEC_BYTE* key, SEC_SIZE key_len, + SEC_SIZE* written) { + SEC_SIZE modulus_size = DH_size(dh); + if (key_len < modulus_size) { + SEC_LOG_ERROR("Key_len is not large enough to hold the computed DH key: %d", DH_size(dh)); + return SEC_RESULT_FAILURE; + } + + BIGNUM* pub_key_bn = BN_bin2bn(pub_key, static_cast(pub_key_len), nullptr); + if (pub_key_bn == nullptr) { + SEC_LOG_ERROR("BN_bin2bn failed"); + return SEC_RESULT_FAILURE; + } + + int temp_len = DH_compute_key(key, pub_key_bn, dh); + BN_free(pub_key_bn); + + if (temp_len <= 0) { + SEC_LOG_ERROR("DH_compute_key failed"); + return SEC_RESULT_FAILURE; + } + + if (temp_len < modulus_size) { + memmove(key + modulus_size - temp_len, key, temp_len); + memset(key, 0, modulus_size - temp_len); + } + + *written = modulus_size; + return SEC_RESULT_SUCCESS; +} + +static Sec_Result hkdf(SEC_BYTE* key, SEC_SIZE key_len, SEC_BYTE* out, const SEC_SIZE* out_len, bool use_salt) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + /* Extract */ + const EVP_MD* evp_md = EVP_sha256(); + + SEC_BYTE prk[SEC_MAC_MAX_LEN]; + SEC_SIZE prk_len; + + if (HMAC(evp_md, use_salt ? "salt" : "", use_salt ? 4 : 0, key, key_len, prk, &prk_len) == nullptr) { + SEC_LOG_ERROR("HMAC failed"); + return SEC_RESULT_FAILURE; + } + + /* Expand */ + size_t digest_length = SHA256_DIGEST_LENGTH; + size_t r = *out_len / digest_length + ((*out_len % digest_length == 0) ? 0 : 1); + SEC_BYTE t[SEC_MAC_MAX_LEN]; + unsigned int t_len = 0; + + Sec_Result result = SEC_RESULT_SUCCESS; + for (size_t i = 1; i <= r; i++) { + SEC_BYTE loop = i; + SEC_SIZE cp_len; + + if (i == r) { + SEC_SIZE mod = *out_len % digest_length; + cp_len = (mod == 0) ? digest_length : mod; + } else { + cp_len = digest_length; + } + + HMAC_CTX _ctx; + HMAC_CTX* ctx = &_ctx; + HMAC_CTX_init(ctx); + if (HMAC_Init_ex(ctx, prk, static_cast(prk_len), evp_md, nullptr) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("HMAC_Init_ex failed"); + result = SEC_RESULT_FAILURE; + break; + } + + if (t_len > 0 && OPENSSL_SUCCESS != HMAC_Update(ctx, t, t_len)) { + SEC_LOG_ERROR("HMAC_Update failed"); + result = SEC_RESULT_FAILURE; + break; + } + + if (HMAC_Update(ctx, (unsigned char*) "label", 5) != OPENSSL_SUCCESS) { // NOLINT + SEC_LOG_ERROR("HMAC_Update failed"); + result = SEC_RESULT_FAILURE; + break; + } + + if (HMAC_Update(ctx, &loop, 1) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("HMAC_Update failed"); + result = SEC_RESULT_FAILURE; + break; + } + + if (HMAC_Final(ctx, t, &t_len) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("HMAC_Final failed"); + result = SEC_RESULT_FAILURE; + break; + } + + HMAC_CTX_cleanup(ctx); + + memcpy(out + (i - 1) * digest_length, t, cp_len); + } + + Sec_Memset(prk, 0, sizeof(prk)); + Sec_Memset(t, 0, sizeof(t)); + return result; +#else + EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); + + if (EVP_PKEY_derive_init(pctx) <= 0) { + EVP_PKEY_CTX_free(pctx); + return SEC_RESULT_FAILURE; + } + + if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0) { + EVP_PKEY_CTX_free(pctx); + return SEC_RESULT_FAILURE; + } + + if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, use_salt ? "salt" : nullptr, use_salt ? 4 : 0) <= 0) { + EVP_PKEY_CTX_free(pctx); + return SEC_RESULT_FAILURE; + } + + if (EVP_PKEY_CTX_set1_hkdf_key(pctx, key, key_len) <= 0) { + EVP_PKEY_CTX_free(pctx); + return SEC_RESULT_FAILURE; + } + + if (EVP_PKEY_CTX_add1_hkdf_info(pctx, "label", 5) <= 0) { + EVP_PKEY_CTX_free(pctx); + return SEC_RESULT_FAILURE; + } + + size_t length = *out_len; + if (EVP_PKEY_derive(pctx, out, &length) <= 0) { + EVP_PKEY_CTX_free(pctx); + return SEC_RESULT_FAILURE; + } + + EVP_PKEY_CTX_free(pctx); + return SEC_RESULT_SUCCESS; +#endif +} + +Sec_Result testKeyExchangeDH(SEC_OBJECTID idComputed, Sec_StorageLoc loc, Sec_KeyType typeComputed, bool useSalt) { + + TestCtx ctx; + Sec_KeyExchangeHandle* keyExchangeHandle = nullptr; + DH* dh = nullptr; + Sec_Result result = SEC_RESULT_FAILURE; + + Sec_DHParameters dh_params; + memcpy(dh_params.p, g_dh_p, sizeof(g_dh_p)); + dh_params.pLen = sizeof(g_dh_p); + memcpy(dh_params.g, g_dh_g, sizeof(g_dh_g)); + dh_params.gLen = sizeof(g_dh_g); + + SEC_BYTE pub_secapi[dh_params.pLen]; + SEC_BYTE pub_test[dh_params.pLen]; + SEC_BYTE ss_test[dh_params.pLen]; + SEC_SIZE ss_len; + SEC_BYTE derived_key[SecKey_GetKeyLenForKeyType(typeComputed)]; + SEC_SIZE derived_key_len = sizeof(derived_key); + SEC_SIZE out_len; + SEC_OBJECTID hkdf_key_id = SEC_OBJECTID_INVALID; + + do { + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + break; + } + + result = SecKeyExchange_GetInstance(ctx.proc(), SEC_KEYEXCHANGE_DH, &dh_params, &keyExchangeHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKeyExchange_GetInstance failed"); + break; + } + + result = SecKeyExchange_GenerateKeys(keyExchangeHandle, pub_secapi, sizeof(pub_secapi)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKeyExchange_GenerateKeys failed"); + break; + } + + //create other side info + dh = DH_create(g_dh_p, sizeof(g_dh_p), g_dh_g, sizeof(g_dh_g)); + if (dh == nullptr) { + SEC_LOG_ERROR("_DH_create failed"); + break; + } + + result = DH_generate_key(dh, pub_test, sizeof(pub_test), &out_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_DH_generate_key failed"); + break; + } + + //compute shared secret + result = SecKeyExchange_ComputeSecret(keyExchangeHandle, pub_test, out_len, typeComputed, idComputed, loc); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKeyExchange_ComputeSecret failed"); + break; + } + + hkdf_key_id = SecKey_ObtainFreeObjectId(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_TOP); + if (hkdf_key_id == SEC_OBJECTID_INVALID) { + SEC_LOG_ERROR("SecKeyExchange_ComputeSecret failed"); + break; + } + + result = SecKey_Derive_HKDF_BaseKey(ctx.proc(), hkdf_key_id, typeComputed, loc, SEC_MACALGORITHM_HMAC_SHA256, + (SEC_BYTE*) (useSalt == SEC_TRUE ? "salt" : nullptr), useSalt == SEC_TRUE ? 4 : 0, // NOLINT + (SEC_BYTE*) "label", 5, idComputed); // NOLINT + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_HKDF_BaseKey failed"); + break; + } + + result = DH_compute(dh, pub_secapi, sizeof(pub_secapi), ss_test, sizeof(ss_test), &ss_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_DH_compute failed"); + break; + } + + result = hkdf(ss_test, ss_len, derived_key, &derived_key_len, useSalt); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_DH_compute failed"); + break; + } + + //test enc/dec or mac + if (SecKey_IsAES(typeComputed) == SEC_TRUE) { + result = aesKeyCheck(ctx.proc(), hkdf_key_id, derived_key, derived_key_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + break; + } + } else { + result = macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, hkdf_key_id, derived_key, derived_key_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + break; + } + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyExchangeHandle != nullptr) + SecKeyExchange_Release(keyExchangeHandle); + + if (hkdf_key_id != SEC_OBJECTID_INVALID) + SecKey_Delete(ctx.proc(), hkdf_key_id); + + if (dh != nullptr) + DH_free(dh); + + return result; +} + +Sec_Result testKeyExchangeECDH(SEC_OBJECTID idComputed, Sec_StorageLoc loc, Sec_KeyType typeComputed, + bool useSalt) { + TestCtx ctx; + Sec_KeyExchangeHandle* keyExchangeHandle = nullptr; + EC_KEY* priv_test = nullptr; + EC_KEY* pub_secapi_key = nullptr; + Sec_Result result = SEC_RESULT_FAILURE; + + Sec_ECCRawPublicKey pub_secapi; + Sec_ECCRawPublicKey pub_test; + SEC_BYTE ss_test[32]; + SEC_SIZE ss_len; + SEC_OBJECTID hkdf_key_id = SEC_OBJECTID_INVALID; + SEC_BYTE derived_key[SecKey_GetKeyLenForKeyType(typeComputed)]; + SEC_SIZE derived_key_len = sizeof(derived_key); + + Sec_ECDHParameters ecdh_params; + ecdh_params.curve = NISTP256; + + do { + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + break; + } + + result = SecKeyExchange_GetInstance(ctx.proc(), SEC_KEYEXCHANGE_ECDH, &ecdh_params, &keyExchangeHandle); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKeyExchange_GetInstance failed"); + break; + } + + result = SecKeyExchange_GenerateKeys(keyExchangeHandle, reinterpret_cast(&pub_secapi), + sizeof(pub_secapi)); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKeyExchange_GenerateKeys failed"); + break; + } + + //create other side info + if ((priv_test = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == nullptr) { + SEC_LOG_ERROR("EC_KEY_new_by_curve_name failed"); + break; + } + + if (EC_KEY_generate_key(priv_test) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("EC_KEY_generate_key failed"); + break; + } + + if (ECCToPubBinary(priv_test, &pub_test) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_ECCToPubBinary failed"); + break; + } + + //compute shared secret + result = SecKeyExchange_ComputeSecret(keyExchangeHandle, reinterpret_cast(&pub_test), + sizeof(pub_test), typeComputed, idComputed, loc); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKeyExchange_ComputeSecret failed"); + break; + } + + pub_secapi_key = ECCFromPubBinary(&pub_secapi); + if (pub_secapi_key == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromPubBinary failed"); + break; + } + + /* Derive the shared secret */ + ss_len = ECDH_compute_key(ss_test, sizeof(ss_test), EC_KEY_get0_public_key(pub_secapi_key), priv_test, nullptr); + if (ss_len <= 0) { + SEC_LOG_ERROR("ECDH_compute_key failed"); + break; + } + + hkdf_key_id = SecKey_ObtainFreeObjectId(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_TOP); + if (hkdf_key_id == SEC_OBJECTID_INVALID) { + SEC_LOG_ERROR("SecKeyExchange_ComputeSecret failed"); + break; + } + + result = SecKey_Derive_HKDF_BaseKey(ctx.proc(), hkdf_key_id, typeComputed, loc, SEC_MACALGORITHM_HMAC_SHA256, + (unsigned char*) (useSalt == SEC_TRUE ? "salt" : nullptr), useSalt == SEC_TRUE ? 4 : 0, // NOLINT + (unsigned char*) "label", 5, idComputed); // NOLINT + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_HKDF_BaseKey failed"); + break; + } + + result = hkdf(ss_test, ss_len, derived_key, &derived_key_len, useSalt); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_DH_compute failed"); + break; + } + + //test enc/dec or mac + if (SecKey_IsAES(typeComputed) == SEC_TRUE) { + result = aesKeyCheck(ctx.proc(), hkdf_key_id, derived_key, derived_key_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + break; + } + } else { + result = macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, hkdf_key_id, derived_key, derived_key_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + break; + } + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyExchangeHandle != nullptr) { + SecKeyExchange_Release(keyExchangeHandle); + } + + if (hkdf_key_id != SEC_OBJECTID_INVALID) + SecKey_Delete(ctx.proc(), hkdf_key_id); + + SEC_ECC_FREE(priv_test); + SEC_ECC_FREE(pub_secapi_key); + + return result; +} diff --git a/test/main/cpp/exchange.h b/test/main/cpp/exchange.h new file mode 100644 index 0000000..31f7159 --- /dev/null +++ b/test/main/cpp/exchange.h @@ -0,0 +1,30 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef EXCHANGE_H +#define EXCHANGE_H + +#include "sec_security.h" +#include "test_creds.h" +#include + +Sec_Result testKeyExchangeDH(SEC_OBJECTID idComputed, Sec_StorageLoc loc, Sec_KeyType typeComputed, bool useSalt); + +Sec_Result testKeyExchangeECDH(SEC_OBJECTID idComputed, Sec_StorageLoc loc, Sec_KeyType typeComputed, bool useSalt); + +#endif // EXCHANGE_H diff --git a/test/main/cpp/jtype.cpp b/test/main/cpp/jtype.cpp new file mode 100644 index 0000000..7499006 --- /dev/null +++ b/test/main/cpp/jtype.cpp @@ -0,0 +1,471 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "jtype.h" // NOLINT +#include "cipher.h" +#include "mac.h" +#include "sec_adapter_utils.h" +#include "sec_security_comcastids.h" +#include "test_ctx.h" +#include + +#define BUFFER_SIZE 4096 + +std::string toB64(const SEC_BYTE* data, SEC_SIZE len) { + std::string res; + SEC_SIZE res_len; + res.resize(SEC_KEYCONTAINER_MAX_LEN); + + if (SecUtils_Base64Encode(data, len, (SEC_BYTE*) res.data(), res.size(), &res_len) != // NOLINT + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSrv_B64Encode failed"); + return ""; + } + + res.resize(res_len); + + return res; +} + +std::string createJTypeHeader(const char* kid, const char* alg) { + std::string res; + + res += R"({"kid":")"; + res += kid; + res += R"(","alg":")"; + res += alg; + res += "\"}"; + + return toB64((SEC_BYTE*) res.c_str(), res.size()); // NOLINT +} + +std::string createJTypeBodyV1(const char* contentKey, const char* contentKeyId, const char* contentKeyRights, + SEC_BOOL cacheable, int contentKeyUsage, const char* contentKeyNotBefore, const char* contentKeyNotOnOrAfter) { + std::string res; + char tmp[BUFFER_SIZE]; + + res += R"({"contentKeyNotOnOrAfter":")"; + res += contentKeyNotOnOrAfter; + + res += R"(","contentKey":")"; + res += contentKey; + + res += R"(","contentKeyId":")"; + res += contentKeyId; + + res += R"(","contentKeyRights":")"; + res += contentKeyRights; + + res += R"(","contentKeyCacheable":)"; + res += (cacheable == SEC_TRUE ? "true" : "false"); + + sprintf(tmp, "%d", contentKeyUsage); + + res += ",\"contentKeyUsage\":"; + res += tmp; + + res += R"(,"contentKeyNotBefore":")"; + res += contentKeyNotBefore; + + res += "\"}"; + + return toB64((SEC_BYTE*) res.c_str(), res.size()); // NOLINT +} + +std::string createJTypeBodyV2(const char* contentKey, const char* contentKeyId, const char* contentKeyRights, + SEC_BOOL cacheable, int contentKeyUsage, const char* contentKeyNotBefore, const char* contentKeyNotOnOrAfter, + int cklen, const char* alg, const char* iv) { + std::string res; + char tmp[BUFFER_SIZE]; + + res += "{"; + + res += "\"contentKeyContainerVersion\":2"; + + res += R"(,"contentKeyNotOnOrAfter":")"; + res += contentKeyNotOnOrAfter; + + res += R"(","contentKey":")"; + res += contentKey; + + res += R"(","contentKeyId":")"; + res += contentKeyId; + + res += R"(","contentKeyRights":")"; + res += contentKeyRights; + + res += R"(","contentKeyCacheable":)"; + res += (cacheable == SEC_TRUE ? "true" : "false"); + + sprintf(tmp, "%d", contentKeyUsage); + + res += ",\"contentKeyUsage\":"; + res += tmp; + + res += R"(,"contentKeyNotBefore":")"; + res += contentKeyNotBefore; + + res += R"(","contentKeyLength":)"; + sprintf(tmp, "%d", cklen); + res += tmp; + res += ""; + + res += R"(,"contentKeyTransportAlgorithm":")"; + res += alg; + + if (iv != nullptr) { + res += R"(","contentKeyTransportIv":")"; + res += iv; + } + + res += "\"}"; + + return toB64((SEC_BYTE*) res.c_str(), res.size()); // NOLINT +} + +std::string createContentKeyV1(TestKey contentKey, TestKey encryptionKey) { + std::vector conK = TestCreds::asOpenSslAes(contentKey); + if (conK.empty()) { + SEC_LOG_ERROR("TestCreds::asOpenSslAes failed"); + return {}; + } + + if (conK.size() != 16) { + SEC_LOG_ERROR("V1 Jtype cannot support keys that are not 128 bits"); + return {}; + } + + std::vector encK = TestCreds::asOpenSslAes(encryptionKey); + if (encK.empty()) { + SEC_LOG_ERROR("TestCreds::asOpenSslAes failed"); + return {}; + } + + std::vector encConK = opensslAesEcb(encryptionKey, SEC_CIPHERMODE_ENCRYPT, SEC_FALSE, nullptr, conK); + if (encConK.empty()) { + SEC_LOG_ERROR("OpensslAesEcb failed"); + return {}; + } + + return toB64(encConK.data(), encConK.size()); +} + +std::string createContentKeyV2(TestKey contentKey, TestKey encryptionKey, Sec_CipherAlgorithm alg, SEC_BYTE* iv) { + std::vector conK = TestCreds::asOpenSslAes(contentKey); + if (conK.empty()) { + SEC_LOG_ERROR("TestCreds::asOpenSslAes failed"); + return {}; + } + + std::vector encK = TestCreds::asOpenSslAes(encryptionKey); + if (encK.empty()) { + SEC_LOG_ERROR("TestCreds::asOpenSslAes failed"); + return {}; + } + + std::vector encConK; + + if (alg == SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING) { + encConK = opensslAesEcb(encryptionKey, SEC_CIPHERMODE_ENCRYPT, SEC_FALSE, iv, conK); + if (encConK.empty()) { + SEC_LOG_ERROR("OpensslAesEcb failed"); + return {}; + } + } else if (alg == SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING) { + encConK = opensslAesEcb(encryptionKey, SEC_CIPHERMODE_ENCRYPT, SEC_TRUE, iv, conK); + if (encConK.empty()) { + SEC_LOG_ERROR("OpensslAesEcb failed"); + return {}; + } + } else { + SEC_LOG_ERROR("Unexpected algorithm encountered: %d", alg); + } + + return toB64(encConK.data(), encConK.size()); +} + +std::string createJTypeMac(const std::string& header, const std::string& body, TestKey macKey) { + std::string data = header + "." + body; + std::vector input((SEC_BYTE*) data.data(), (SEC_BYTE*) (data.data() + data.size())); // NOLINT + std::vector mac = macOpenSSL(SEC_MACALGORITHM_HMAC_SHA256, macKey, input); + return toB64(mac.data(), mac.size()); +} + +std::string createJTypeContainer(const char* kid, const char* macalg, TestKey contentKey, TestKey encryptionKey, + const char* contentKeyId, const char* contentKeyRights, SEC_BOOL cacheable, int contentKeyUsage, + const char* contentKeyNotBefore, const char* contentKeyNotOnOrAfter, TestKey macKey, int version, + const char* alg) { + + std::string header_b64 = createJTypeHeader(kid, macalg); + if (header_b64.empty()) { + SEC_LOG_ERROR("CreateJTypeHeader failed"); + return {}; + } + + std::string body_b64; + if (version == 1) { + std::string encConK = createContentKeyV1(contentKey, encryptionKey); + if (encConK.empty()) { + SEC_LOG_ERROR("CreateContentKeyV1 failed"); + return {}; + } + + body_b64 = createJTypeBodyV1(encConK.c_str(), contentKeyId, contentKeyRights, cacheable, contentKeyUsage, + contentKeyNotBefore, contentKeyNotOnOrAfter); + if (body_b64.empty()) { + SEC_LOG_ERROR("CreateJTypeBody failed"); + return {}; + } + } else if (version == 2) { + Sec_CipherAlgorithm salg; + if (strcmp(alg, "aesEcbNone") == 0) { + salg = SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING; + } else if (strcmp(alg, "aesEcbPkcs5") == 0) { + salg = SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING; + } else { + SEC_LOG_ERROR("Unknown algorithm encountered: %s", alg); + return {}; + } + + std::string encConK = createContentKeyV2(contentKey, encryptionKey, salg, nullptr); + if (encConK.empty()) { + SEC_LOG_ERROR("CreateContentKeyV2 failed"); + return {}; + } + + std::vector conK = TestCreds::asOpenSslAes(contentKey); + if (conK.empty()) { + SEC_LOG_ERROR("TestCreds::asOpenSslAes failed"); + return {}; + } + + body_b64 = createJTypeBodyV2(encConK.c_str(), contentKeyId, contentKeyRights, cacheable, contentKeyUsage, + contentKeyNotBefore, contentKeyNotOnOrAfter, static_cast(conK.size()), alg, nullptr); + if (body_b64.empty()) { + SEC_LOG_ERROR("CreateJTypeBody failed"); + return {}; + } + } else { + SEC_LOG_ERROR("Unknown version encountered: %d", version); + return {}; + } + + std::string mac_b64 = createJTypeMac(header_b64, body_b64, macKey); + if (mac_b64.empty()) { + SEC_LOG_ERROR("CreateJTypeMac failed"); + return {}; + } + + return header_b64 + "." + body_b64 + "." + mac_b64; +} + +Sec_Result testProvisionJType(TestKey contentKey, TestKey encryptionKey, TestKc encKc, TestKey macKey, TestKc macKc, + int version, const char* alg) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, encryptionKey, + "9c621060-3a17-4813-8dcb-2e9187aaa903", createDefaultRights(TestCreds::getKeyType(contentKey)).c_str(), + SEC_FALSE, 1, "2010-12-09T19:53:06Z", "2037-12-09T19:53:06Z", macKey, version, alg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + //provision encryption key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY, SEC_STORAGELOC_RAM, encryptionKey, encKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //provision maccing key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY, SEC_STORAGELOC_RAM, macKey, macKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //provsion j-type key + Sec_Result result = SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_JTYPE, + reinterpret_cast(&jtype[0]), jtype.size()); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testExportKey(TestKey contentKey, TestKey encryptionKey, TestKc encKc, TestKey macKey, TestKc macKc, + Sec_CipherAlgorithm alg, SEC_SIZE input_len, int version, const char* calg) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, encryptionKey, + "9c621060-3a17-4813-8dcb-2e9187aaa903", createDefaultRights(TestCreds::getKeyType(contentKey)).c_str(), + SEC_TRUE, 1, "2010-12-09T19:53:06Z", "2037-12-09T19:53:06Z", + macKey, version, calg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + //provision encryption key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY, SEC_STORAGELOC_RAM, encryptionKey, encKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //provision maccing key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY, SEC_STORAGELOC_RAM, macKey, macKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //provsion j-type key + Sec_Result result = SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_JTYPE, + reinterpret_cast(&jtype[0]), jtype.size()); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if (SecKey_GetInstance(ctx.proc(), SEC_OBJECTID_USER_BASE, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + //get properties from j-type + Sec_KeyProperties jtype_props; + if (SecKey_GetProperties(keyHandle, &jtype_props) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetProperties failed"); + return SEC_RESULT_FAILURE; + } + + //export j-type key + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + return SEC_RESULT_FAILURE; + } + exported_key.resize(exported_len); + + //provision exported + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, + &exported_key[0], exported_key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* exportedKeyHandle; + if (SecKey_GetInstance(ctx.proc(), SEC_OBJECTID_USER_BASE, &exportedKeyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + //grab properties from exported + Sec_KeyProperties exported_props; + if (SecKey_GetProperties(exportedKeyHandle, &exported_props) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetProperties failed"); + return SEC_RESULT_FAILURE; + } + + if (memcmp(&jtype_props, &exported_props, sizeof(Sec_KeyProperties)) != 0) { + SEC_LOG_ERROR("Key properties on jtype and exported container do not match"); + return SEC_RESULT_FAILURE; + } + + //test exported encryption + if (cipherEncDecSingle(&ctx, SEC_OBJECTID_USER_BASE, alg, input_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + SecKey_Release(keyHandle); + SecKey_Release(exportedKeyHandle); + return SEC_RESULT_SUCCESS; +} + +std::string createDefaultRights(Sec_KeyType kt) { + SEC_BYTE allow_all_rights[] = { + SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_DTCP_ALLOWED, + SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED, + SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED, + SEC_KEYOUTPUTRIGHT_ANALOG_OUTPUT_ALLOWED}; + return toB64(allow_all_rights, sizeof(allow_all_rights)); +} + +Sec_Result testDecryptJType(TestKey contentKey, TestKey encryptionKey, TestKc encKc, TestKey macKey, TestKc macKc, + Sec_CipherAlgorithm alg, SEC_SIZE input_len, int version, const char* calg) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, encryptionKey, + "9c621060-3a17-4813-8dcb-2e9187aaa903", + createDefaultRights(TestCreds::getKeyType(contentKey)).c_str(), + SEC_FALSE, 1, "2010-12-09T19:53:06Z", "2037-12-09T19:53:06Z", macKey, + version, calg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + Sec_StorageLoc loc = SEC_STORAGELOC_RAM; + + //provision encryption key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY, loc, encryptionKey, encKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //provision maccing key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY, loc, macKey, macKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //provision jtype key + Sec_Result result = SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_JTYPE, + reinterpret_cast(&jtype[0]), jtype.size()); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + //test encryption + if (cipherEncDecSingle(&ctx, SEC_OBJECTID_USER_BASE, alg, input_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/jtype.h b/test/main/cpp/jtype.h new file mode 100644 index 0000000..fb64ab6 --- /dev/null +++ b/test/main/cpp/jtype.h @@ -0,0 +1,42 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef JTYPE_H +#define JTYPE_H + +#include "sec_security.h" +#include "test_creds.h" +#include + +Sec_Result testProvisionJType(TestKey contentKey, TestKey encryptionKey, TestKc encKc, TestKey macKey, TestKc macKc, + int version, const char* valg); + +Sec_Result testDecryptJType(TestKey contentKey, TestKey encryptionKey, TestKc encKc, TestKey macKey, TestKc macKc, + Sec_CipherAlgorithm alg, SEC_SIZE input_len, int version, const char* calg); + +Sec_Result testExportKey(TestKey contentKey, TestKey encryptionKey, TestKc encKc, TestKey macKey, TestKc macKc, + Sec_CipherAlgorithm alg, SEC_SIZE input_len, int version, const char* calg); + +std::string createJTypeContainer(const char* kid, const char* macalg, TestKey contentKey, TestKey encryptionKey, + const char* contentKeyId, const char* contentKeyRights, SEC_BOOL cacheable, int contentKeyUsage, + const char* contentKeyNotBefore, const char* contentKeyNotOnOrAfter, TestKey macKey, int version, + const char* alg); + +std::string createDefaultRights(Sec_KeyType kt); + +#endif // JTYPE_H diff --git a/test/main/cpp/key.cpp b/test/main/cpp/key.cpp new file mode 100644 index 0000000..66f588f --- /dev/null +++ b/test/main/cpp/key.cpp @@ -0,0 +1,1283 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "key.h" // NOLINT +#include "cipher.h" +#include "sec_adapter_store.h" +#include "sec_adapter_utils.h" +#include "test_ctx.h" +#include +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#include +#endif + +static int Sec_DisablePassphrasePrompt(char* buf, int size, int rwflag, void* u) { + return 0; +} + +static Sec_Result BigNumToBuffer(const BIGNUM* bignum, SEC_BYTE* buffer, SEC_SIZE buffer_len) { + SEC_SIZE num_bytes; + + memset(buffer, 0, buffer_len); + num_bytes = BN_num_bytes(bignum); + + if (num_bytes > buffer_len) { + SEC_LOG_ERROR("Buffer not large enough. needed: %d, actual: %d", num_bytes, buffer_len); + return SEC_RESULT_FAILURE; + } + + BN_bn2bin(bignum, buffer + buffer_len - num_bytes); + + return SEC_RESULT_SUCCESS; +} + +static void RSAToPubBinary(RSA* rsa, Sec_RSARawPublicKey* binary) { + Sec_Uint32ToBEBytes(RSA_size(rsa), binary->modulus_len_be); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + BigNumToBuffer(rsa->n, binary->n, Sec_BEBytesToUint32(binary->modulus_len_be)); + BigNumToBuffer(rsa->e, binary->e, 4); +#else + const BIGNUM* n = nullptr; + const BIGNUM* e = nullptr; + RSA_get0_key(rsa, &n, &e, nullptr); + BigNumToBuffer(const_cast(n), binary->n, Sec_BEBytesToUint32(binary->modulus_len_be)); + BigNumToBuffer(const_cast(e), binary->e, 4); +#endif +} + +static Sec_Result aesKeyCheck(Sec_ProcessorHandle* processorHandle, SEC_OBJECTID id_first, SEC_OBJECTID id_second) { + SEC_PRINT("--- aes key check ---\n"); + + std::vector clear = TestCtx::random(SEC_AES_BLOCK_SIZE); + TestCtx::printHex("clear", clear); + + std::vector cipher_first; + cipher_first.resize(SEC_AES_BLOCK_SIZE); + SEC_SIZE cipher_first_len; + + if (SecCipher_SingleInputId(processorHandle, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, + id_first, nullptr, &clear[0], clear.size(), &cipher_first[0], cipher_first.size(), &cipher_first_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + cipher_first.resize(cipher_first_len); + TestCtx::printHex("cipher_first", cipher_first); + + std::vector cipher_second; + cipher_second.resize(SEC_AES_BLOCK_SIZE); + SEC_SIZE cipher_second_len; + + if (SecCipher_SingleInputId(processorHandle, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, + id_second, nullptr, &clear[0], clear.size(), &cipher_second[0], cipher_second.size(), + &cipher_second_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + cipher_second.resize(cipher_second_len); + TestCtx::printHex("cipher_second", cipher_second); + + SEC_PRINT("---------------------\n"); + + //check if results match + if (cipher_first != cipher_second) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_Result macCheck(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm alg, SEC_OBJECTID id_first, + SEC_OBJECTID id_second) { + std::vector clear = TestCtx::random(256); + TestCtx::printHex("clear", clear); + + std::vector mac_first; + mac_first.resize(SEC_MAC_MAX_LEN); + SEC_SIZE mac_first_len; + if (SecMac_SingleInputId(processorHandle, alg, id_first, &clear[0], clear.size(), &mac_first[0], &mac_first_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + mac_first.resize(mac_first_len); + TestCtx::printHex("mac_first", mac_first); + + std::vector mac_second; + mac_second.resize(SEC_MAC_MAX_LEN); + SEC_SIZE mac_second_len; + if (SecMac_SingleInputId(processorHandle, alg, id_first, &clear[0], clear.size(), &mac_second[0], + &mac_second_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + mac_second.resize(mac_second_len); + TestCtx::printHex("macSecApi", mac_second); + + //check if results match + if (mac_first != mac_second) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testStore(SEC_BOOL encrypt, SEC_BOOL mac) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector data = TestCtx::random(20); + TestCtx::printHex("data: ", data); + + //fill header + SecUtils_KeyStoreHeader keystore_header; + if (SecUtils_FillKeyStoreUserHeader(ctx.proc(), &keystore_header, SEC_KEYCONTAINER_RAW_HMAC_160) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_FillKeyStoreUserHeader failed"); + return SEC_RESULT_FAILURE; + } + + //write store + std::vector store; + store.resize(SEC_KEYCONTAINER_MAX_LEN); + Sec_Result result = SecStore_StoreData(ctx.proc(), encrypt, mac, (SEC_BYTE*) SEC_UTILS_KEYSTORE_MAGIC, // NOLINT + &keystore_header, sizeof(keystore_header), &data[0], data.size(), &store[0], store.size()); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_StoreData failed"); + return SEC_RESULT_FAILURE; + } + + store.resize(SecStore_GetStoreLen(&store[0])); + TestCtx::printHex("store: ", store); + + //read from store + SecUtils_KeyStoreHeader keystore_header2; + std::vector extracted_data; + extracted_data.resize(SEC_KEYCONTAINER_MAX_LEN); + if (SecStore_RetrieveData(ctx.proc(), mac, &keystore_header2, sizeof(keystore_header2), &extracted_data[0], + extracted_data.size(), &store[0], store.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_RetrieveData failed"); + return SEC_RESULT_FAILURE; + } + + extracted_data.resize(SecStore_GetDataLen(&store[0])); + TestCtx::printHex("extracted_data: ", extracted_data); + + if (data != extracted_data) { + SEC_LOG_ERROR("Extracted data does not match what was put into the store"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testStoreProvision(SEC_OBJECTID id, SEC_BOOL encrypt, SEC_BOOL mac) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector data = TestCtx::random(20); + TestCtx::printHex("data: ", data); + + //fill header + SecUtils_KeyStoreHeader keystore_header; + if (SecUtils_FillKeyStoreUserHeader(ctx.proc(), &keystore_header, SEC_KEYCONTAINER_RAW_HMAC_160) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_FillKeyStoreUserHeader failed"); + return SEC_RESULT_FAILURE; + } + + //write store + std::vector store; + store.resize(SEC_KEYCONTAINER_MAX_LEN); + if (SecStore_StoreData(ctx.proc(), encrypt, mac, (SEC_BYTE*) SEC_UTILS_KEYSTORE_MAGIC, &keystore_header, // NOLINT + sizeof(keystore_header), &data[0], data.size(), &store[0], store.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_StoreData failed"); + return SEC_RESULT_FAILURE; + } + store.resize(SecStore_GetStoreLen(&store[0])); + TestCtx::printHex("store: ", store); + + //provision store + if (SecKey_Provision(ctx.proc(), id, SEC_STORAGELOC_RAM_SOFT_WRAPPED, SEC_KEYCONTAINER_STORE, &store[0], + store.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyProvision(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (ctx.provisionKey(id, loc, key, kc) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyProvisionDouble(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, TestKey key2, TestKc kc2, + Sec_StorageLoc loc2) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle = ctx.provisionKey(id, loc, key, kc); + if (keyHandle == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + ctx.releaseKey(keyHandle); + + keyHandle = ctx.provisionKey(SEC_OBJECTID_USER_BASE, loc2, key2, kc2); + if (keyHandle == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyGetKeyInfo(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle = ctx.provisionKey(id, loc, key, kc); + if (keyHandle == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType kt = SecKey_GetKeyType(keyHandle); + if (kt < 0 || kt >= SEC_KEYTYPE_NUM) { + SEC_LOG_ERROR("Invalid key type"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_GetKeyLen(keyHandle) == 0) { + SEC_LOG_ERROR("Invalid key length"); + return SEC_RESULT_FAILURE; + } + + if (ctx.proc() != SecKey_GetProcessor(keyHandle)) { + SEC_LOG_ERROR("SecKey_GetProcessor failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyNoSha(SEC_OBJECTID id, TestKey key, TestKc kc) { + TestCtx ctx; + if (ctx.init("/tmp/sec_api_test_global", "/tmp/sec_api_test_app") != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle = ctx.provisionKey(id, SEC_STORAGELOC_FILE, key, kc); + if (keyHandle == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + ctx.releaseKey(keyHandle); + + char file_name_verification[SEC_MAX_FILE_PATH_LEN]; + snprintf(file_name_verification, sizeof(file_name_verification), SEC_VERIFICATION_FILENAME_PATTERN, + "/tmp/sec_api_test_app/", id); + SecUtils_RmFile(file_name_verification); + if (ctx.getKey(id) != nullptr) { + SEC_LOG_ERROR("ctx.getKey was supposed to fail but didn't"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +static Sec_KeyType GroupToKeyType(const EC_GROUP* group) { + if (nullptr == group) + return SEC_KEYTYPE_NUM; + switch (EC_GROUP_get_curve_name(group)) { + case NID_X9_62_prime256v1: + return SEC_KEYTYPE_ECC_NISTP256_PUBLIC; + case 0: + default: + return SEC_KEYTYPE_NUM; + } +} + +static Sec_Result Extract_EC_KEY_X_Y(const EC_KEY* ec_key, BIGNUM** xp, BIGNUM** yp, Sec_KeyType* keyTypep) { + const EC_GROUP* group; + const EC_POINT* ec_point = nullptr; + BN_CTX* ctx = nullptr; + Sec_Result result = SEC_RESULT_FAILURE; + + do { + if (xp == nullptr) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: X cannot be NULL"); + break; + } + + group = EC_KEY_get0_group(ec_key); + if (group == nullptr) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_KEY_get0_group: %s", + ERR_error_string(ERR_get_error(), NULL)); + break; + } + + ec_point = EC_KEY_get0_public_key(ec_key); + if (ec_point == nullptr) { + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_KEY_get0_public_key: %s", + ERR_error_string(ERR_get_error(), NULL)); + break; + } + + ctx = BN_CTX_new(); + if (ctx == nullptr) { + SEC_LOG_ERROR("BN_CTX_new() failed"); + break; + } + + *xp = BN_new(); + if (*xp == nullptr) { + SEC_LOG_ERROR("BN_new() failed"); + break; + } + + if (nullptr != yp) { // if caller wants y coordinate returned + *yp = BN_new(); + if (*yp == nullptr) { + SEC_LOG_ERROR("BN_new() failed"); + break; + } + } + + if (nullptr != keyTypep) { // if caller wants key type returned + *keyTypep = GroupToKeyType(group); + } + + // Get the X coordinate and optionally the Y coordinate + if (EC_POINT_get_affine_coordinates_GFp(group, ec_point, *xp, yp != nullptr ? *yp : nullptr, ctx) != 1) { + BN_clear_free(*xp); + if (nullptr != yp) + BN_clear_free(*yp); + + SEC_LOG_ERROR("SecUtils_ExtractEcc_Key_X_Y: EC_POINT_get_affine_coordinates_GFp: %s", + ERR_error_string(ERR_get_error(), NULL)); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (nullptr != ctx) + BN_CTX_free(ctx); + + return result; +} + +static Sec_Result ECCToPubBinary(EC_KEY* ec_key, Sec_ECCRawPublicKey* binary) { + BIGNUM* x = nullptr; + BIGNUM* y = nullptr; + Sec_KeyType keyType; + + if (Extract_EC_KEY_X_Y(ec_key, &x, &y, &keyType) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("_Extract_EC_KEY_X_Y failed"); + return SEC_RESULT_FAILURE; + } + + binary->type = keyType; + Sec_Uint32ToBEBytes(SecKey_GetKeyLenForKeyType(keyType), binary->key_len); + BigNumToBuffer(x, binary->x, Sec_BEBytesToUint32(binary->key_len)); + BigNumToBuffer(y, binary->y, Sec_BEBytesToUint32(binary->key_len)); + + BN_free(y); + BN_free(x); + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyExtractPublicKey(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle = ctx.provisionKey(id, loc, key, kc); + if (keyHandle == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsEcc(TestCreds::getKeyType(key)) == SEC_TRUE) { + Sec_ECCRawPublicKey public_key; + memset(&public_key, 0, sizeof(public_key)); + if (SecKey_ExtractECCPublicKey(keyHandle, &public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractECCPublicKey failed"); + return SEC_RESULT_FAILURE; + } + + std::vector secapi(reinterpret_cast(&public_key), + (reinterpret_cast(&public_key)) + sizeof(Sec_ECCRawPublicKey)); + + TestCtx::printHex("secapi", secapi); + + if (kc != TESTKC_GENERATED) { + EC_KEY* ec = TestCreds::asOpenSslEcKey(key); + if (ec == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslEc failed"); + return SEC_RESULT_FAILURE; + } + + memset(&public_key, 0, sizeof(public_key)); + ECCToPubBinary(ec, &public_key); + SEC_ECC_FREE(ec); + + std::vector openssl(reinterpret_cast(&public_key), + (reinterpret_cast(&public_key)) + sizeof(Sec_ECCRawPublicKey)); + TestCtx::printHex("openssl", openssl); + + if (secapi != openssl) { + return SEC_RESULT_FAILURE; + } + } + } else { + Sec_RSARawPublicKey public_key; + memset(&public_key, 0, sizeof(public_key)); + if (SecKey_ExtractRSAPublicKey(keyHandle, &public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractRSAPublicKey failed"); + return SEC_RESULT_FAILURE; + } + + std::vector secapi(reinterpret_cast(&public_key), + (reinterpret_cast(&public_key)) + sizeof(Sec_RSARawPublicKey)); + + TestCtx::printHex("secapi", secapi); + + RSA* rsa = TestCreds::asOpenSslRsa(key); + if (rsa == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslRsa failed"); + return SEC_RESULT_FAILURE; + } + + memset(&public_key, 0, sizeof(public_key)); + RSAToPubBinary(rsa, &public_key); + SEC_RSA_FREE(rsa); + + std::vector openssl(reinterpret_cast(&public_key), + (reinterpret_cast(&public_key)) + sizeof(Sec_RSARawPublicKey)); + TestCtx::printHex("openssl", openssl); + + if (secapi != openssl) { + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyGenerate(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, bool testEncDec) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Generate(ctx.proc(), id, keyType, loc) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Generate failed"); + return SEC_RESULT_FAILURE; + } + + if (testEncDec) { + if (cipherEncDecSingle(&ctx, id, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + } + + if (keyType == SEC_KEYTYPE_ECC_NISTP256) { + Sec_KeyHandle* keyHandle; + if (SecKey_GetInstance(ctx.proc(), id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + SecKey_Delete(ctx.proc(), id); + return SEC_RESULT_FAILURE; + } + + Sec_ECCRawPublicKey public_key; + if (SecKey_ExtractECCPublicKey(keyHandle, &public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractECCPublicKey failed"); + SecKey_Release(keyHandle); + SecKey_Delete(ctx.proc(), id); + return SEC_RESULT_FAILURE; + } + + SecKey_Release(keyHandle); + } + + SecKey_Delete(ctx.proc(), id); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyDeriveHKDF(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, Sec_MacAlgorithm macAlgorithm, + bool testEncDec, bool useSalt) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector nonce = TestCtx::random(SEC_NONCE_LEN); + TestCtx::printHex("nonce", nonce); + std::vector salt = TestCtx::random(25); + TestCtx::printHex("salt", salt); + std::vector info = TestCtx::random(17); + TestCtx::printHex("info", info); + + if (SecKey_Derive_HKDF(ctx.proc(), id, keyType, loc, macAlgorithm, &nonce[0], useSalt ? &salt[0] : nullptr, + useSalt ? salt.size() : 0, &info[0], info.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_HKDF failed"); + return SEC_RESULT_FAILURE; + } + + if (testEncDec) { + if (cipherEncDecSingle(&ctx, id, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + } + + SecKey_Delete(ctx.proc(), id); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyDeriveConcatKDF(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, + Sec_DigestAlgorithm digestAlgorithm, bool testEncDec) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector nonce = TestCtx::random(SEC_NONCE_LEN); + TestCtx::printHex("nonce", nonce); + std::vector otherInfo = TestCtx::random(17); + TestCtx::printHex("otherInfo", otherInfo); + + if (SecKey_Derive_ConcatKDF(ctx.proc(), id, keyType, loc, digestAlgorithm, &nonce[0], &otherInfo[0], + otherInfo.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_ConcatKDF failed"); + return SEC_RESULT_FAILURE; + } + + if (testEncDec) { + if (cipherEncDecSingle(&ctx, id, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + } + + SecKey_Delete(ctx.proc(), id); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyDeriveVendorAes128(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, + Sec_MacAlgorithm macAlgorithm, bool testEncDec) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector input = TestCtx::random(25); + TestCtx::printHex("input", input); + + if (SecKey_Derive_VendorAes128(ctx.proc(), id, loc, &input[0], input.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_VendorAes128 failed"); + return SEC_RESULT_FAILURE; + } + + if (testEncDec) { + if (cipherEncDecSingle(&ctx, id, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + } + + SecKey_Delete(ctx.proc(), id); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyDeriveKeyLadderAes128(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, + Sec_KeyLadderRoot root, bool testEncDec) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector> inputs; + inputs.resize(SecProcessor_GetKeyLadderMaxDepth(ctx.proc(), root)); + + if (inputs.empty()) { + SEC_LOG_ERROR("Key ladder not available"); + return SEC_RESULT_FAILURE; + } + + for (unsigned int i = 0; i < inputs.size(); ++i) { + inputs[i] = TestCtx::random(SEC_AES_BLOCK_SIZE); + + char buf[8]; + sprintf(buf, "%d", i); + + std::string name; + name += "input["; + name += buf; + name += "]"; + TestCtx::printHex(name.c_str(), inputs[i]); + } + + size_t inputs_size = inputs.size(); + Sec_Result result = SecKey_Derive_KeyLadderAes128(ctx.proc(), id, loc, root, + inputs_size > 0 ? &(inputs[0])[0] : nullptr, + inputs_size > 1 ? &(inputs[1])[0] : nullptr, + inputs_size > 2 ? &(inputs[2])[0] : nullptr, + inputs_size > 3 ? &(inputs[3])[0] : nullptr); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_KeyLadderAes128 failed"); + return SEC_RESULT_FAILURE; + } + + if (testEncDec) { + if (cipherEncDecSingle(&ctx, id, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + } + + SecKey_Delete(ctx.proc(), id); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyComputeBaseKeyDigest(SEC_OBJECTID id, Sec_DigestAlgorithm alg) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector nonce = TestCtx::random(SEC_NONCE_LEN); + TestCtx::printHex("nonce", nonce); + + std::vector digest; + digest.resize(SEC_DIGEST_MAX_LEN); + SEC_SIZE digestLen; + + if (SecKey_ComputeBaseKeyDigest(ctx.proc(), &nonce[0], alg, &digest[0], &digestLen) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ComputeBaseKeyDigest failed"); + return SEC_RESULT_FAILURE; + } + + digest.resize(digestLen); + TestCtx::printHex("digest", digest); + + return SEC_RESULT_SUCCESS; +} + +static EC_KEY* ECCFromDERPriv(const SEC_BYTE* der, SEC_SIZE der_len) { + const auto* p = der; + PKCS8_PRIV_KEY_INFO* p8 = nullptr; + EVP_PKEY* evp_key = nullptr; + EC_KEY* ecc = nullptr; + + do { + p8 = d2i_PKCS8_PRIV_KEY_INFO(nullptr, &p, der_len); + if (p8 != nullptr) { + evp_key = EVP_PKCS82PKEY(p8); + if (evp_key == nullptr) { + SEC_LOG_ERROR("EVP_PKCS82PKEY failed"); + break; + } + } else { + evp_key = d2i_AutoPrivateKey(nullptr, &p, der_len); + if (evp_key == nullptr) { + SEC_LOG_ERROR("d2i_AutoPrivateKey failed"); + break; + } + } + + ecc = EVP_PKEY_get1_EC_KEY(evp_key); + if (ecc == nullptr) { + SEC_LOG_ERROR("EVP_PKEY_get1_EC_KEY failed"); + break; + } + } while (false); + + SEC_EVPPKEY_FREE(evp_key); + + if (p8 != nullptr) { + PKCS8_PRIV_KEY_INFO_free(p8); + } + + return ecc; +} + +static EC_KEY* ECCFromPEMPub(SEC_BYTE* pem, SEC_SIZE pem_len) { + BIO* bio = nullptr; + EC_KEY* ec_key = nullptr; + + bio = BIO_new_mem_buf(pem, static_cast(pem_len)); + do { + ec_key = PEM_read_bio_EC_PUBKEY(bio, &ec_key, Sec_DisablePassphrasePrompt, nullptr); + + if (ec_key == nullptr) { + SEC_LOG_ERROR("Invalid ECC key container"); + break; + } + } while (false); + + SEC_BIO_FREE(bio); + + return ec_key; +} + +static EC_KEY* ECCFromDERPub(const SEC_BYTE* der, SEC_SIZE der_len) { + const auto* p = der; + EC_KEY* ec_key = nullptr; + do { + ec_key = d2i_EC_PUBKEY(&ec_key, &p, der_len); + + if (ec_key == nullptr) { + SEC_LOG_ERROR("Invalid ECC key container"); + break; + } + } while (false); + + return ec_key; +} + +static EC_KEY* ECCFromPrivBinary(Sec_ECCRawPrivateKey* binary) { + BN_CTX* ctx = BN_CTX_new(); + + // Note that SEC_KEYTYPE_ECC_NISTP256_PUBLIC is not acceptable, + // because it won't have a private key value + if (binary->type != SEC_KEYTYPE_ECC_NISTP256) + return nullptr; + + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); //create ec_key structure with NIST p256 curve; + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + EC_POINT* ec_point; + do { + ec_point = EC_POINT_new(group); + BN_CTX_start(ctx); + BIGNUM* xp; + BIGNUM* yp; + BIGNUM* prvp; + if (((xp = BN_CTX_get(ctx)) == nullptr) || ((yp = BN_CTX_get(ctx)) == nullptr) || + ((prvp = BN_CTX_get(ctx)) == nullptr)) + break; + + EC_POINT_set_affine_coordinates_GFp(group, ec_point, + BN_bin2bn(binary->x, static_cast(Sec_BEBytesToUint32(binary->key_len)), xp), + BN_bin2bn(binary->y, static_cast(Sec_BEBytesToUint32(binary->key_len)), yp), ctx); + EC_KEY_set_public_key(ec_key, ec_point); + + EC_KEY_set_private_key(ec_key, + BN_bin2bn(binary->prv, static_cast(Sec_BEBytesToUint32(binary->key_len)), prvp)); + } while (false); + + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return ec_key; +} + +static EC_KEY* ECCFromPubBinary(Sec_ECCRawPublicKey* binary) { + BN_CTX* ctx = BN_CTX_new(); + + if (binary->type != SEC_KEYTYPE_ECC_NISTP256_PUBLIC && binary->type != SEC_KEYTYPE_ECC_NISTP256) + return nullptr; + + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); //create ec_key structure with NIST p256 curve; + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + EC_POINT* ec_point; + do { + ec_point = EC_POINT_new(group); + BN_CTX_start(ctx); + BIGNUM* xp; + BIGNUM* yp; + + if (((xp = BN_CTX_get(ctx)) == nullptr) || ((yp = BN_CTX_get(ctx)) == nullptr)) + break; + + EC_POINT_set_affine_coordinates_GFp(group, ec_point, + BN_bin2bn(binary->x, static_cast(Sec_BEBytesToUint32(binary->key_len)), xp), + BN_bin2bn(binary->y, static_cast(Sec_BEBytesToUint32(binary->key_len)), yp), ctx); + EC_KEY_set_public_key(ec_key, ec_point); + } while (false); + + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return ec_key; +} + +static EC_KEY* ECCFromPEMPriv(SEC_BYTE* pem, SEC_SIZE pem_len) { + BIO* bio = nullptr; + EC_KEY* ec_key = nullptr; + + do { + bio = BIO_new_mem_buf(pem, static_cast(pem_len)); + ec_key = PEM_read_bio_ECPrivateKey(bio, &ec_key, Sec_DisablePassphrasePrompt, nullptr); + + if (ec_key == nullptr) { + SEC_LOG_ERROR("Invalid ECC key container"); + break; + } + } while (false); + + SEC_BIO_FREE(bio); + + return ec_key; +} + +static EC_KEY* ECCFromClearKC(Sec_ProcessorHandle* processorHandle, Sec_KeyContainer kc, SEC_BYTE* data, + SEC_SIZE data_len) { + EC_KEY* ec_key = nullptr; + SecUtils_KeyStoreHeader store_header; + SEC_BYTE store_data[SEC_KEYCONTAINER_MAX_LEN]; + + do { + if (kc == SEC_KEYCONTAINER_DER_ECC_NISTP256) { + ec_key = ECCFromDERPriv(data, data_len); + if (ec_key == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromDERPriv failed"); + break; + } + } else if (kc == SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC) { + ec_key = ECCFromDERPub(data, data_len); + if (ec_key == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromDERPub failed"); + break; + } + } else if (kc == SEC_KEYCONTAINER_RAW_ECC_NISTP256) { + if (data_len == sizeof(Sec_ECCRawPrivateKey)) { + ec_key = ECCFromPrivBinary(reinterpret_cast(data)); + if (ec_key == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromPrivBinary failed"); + break; + } + } else { + SEC_LOG_ERROR("Invalid priv key structure size: %d", data_len); + break; + } + } else if (kc == SEC_KEYCONTAINER_RAW_ECC_NISTP256_PUBLIC) { + if (data_len != sizeof(Sec_ECCRawPublicKey)) { + SEC_LOG_ERROR("Invalid pub key structure size: %d", data_len); + break; + } + + ec_key = ECCFromPubBinary(reinterpret_cast(data)); + if (ec_key == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromPubBinary failed"); + break; + } + } else if (kc == SEC_KEYCONTAINER_PEM_ECC_NISTP256) { + ec_key = ECCFromPEMPriv(data, data_len); + if (ec_key == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromPEMPriv failed"); + break; + } + } else if (kc == SEC_KEYCONTAINER_PEM_ECC_NISTP256_PUBLIC) { + ec_key = ECCFromPEMPub(data, data_len); + if (ec_key == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromPEMPub failed"); + break; + } + } else if (kc == SEC_KEYCONTAINER_STORE) { + // Store Key containers are not supported + Sec_Result result = SecStore_RetrieveData(processorHandle, SEC_FALSE, &store_header, sizeof(store_header), + store_data, sizeof(store_data), data, data_len); + if (result != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecStore_RetrieveData failed"); + break; + } + + ec_key = ECCFromClearKC(processorHandle, static_cast(store_header.inner_kc_type), + store_data, SecStore_GetDataLen(data)); + if (ec_key == nullptr) { + SEC_LOG_ERROR("_ECCFromClearKC failed"); + break; + } + + SEC_LOG_ERROR("Store key containers are not supported"); + break; + } else { + SEC_LOG_ERROR("Unknown container type"); + break; + } + } while (false); + + return ec_key; +} + +Sec_Result testKeyECDHKeyAgreementWithKDF(SEC_OBJECTID id_derived, SEC_OBJECTID id_priv, TestKey priv, TestKc priv_kc, + TestKey pub, Sec_KeyType keyType, Sec_StorageLoc loc, Sec_DigestAlgorithm digestAlgorithm, bool testEncDec) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle = nullptr; + if ((keyHandle = ctx.provisionKey(id_priv, loc, priv, priv_kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + ProvKey* keyPubRaw = TestCreds::getKey(pub, TESTKC_RAW, SEC_OBJECTID_INVALID); + EC_KEY* ec_key_pub = ECCFromClearKC(ctx.proc(), keyPubRaw->kc, &(keyPubRaw->key[0]), keyPubRaw->key.size()); + if (ec_key_pub == nullptr) { + SEC_ECC_FREE(ec_key_pub); + SEC_LOG_ERROR("_ECCFromClearKC failed"); + delete keyPubRaw; + return SEC_RESULT_FAILURE; + } + + delete keyPubRaw; + + Sec_ECCRawPublicKey pub_other; + if (ECCToPubBinary(ec_key_pub, &pub_other) != SEC_RESULT_SUCCESS) { + SEC_ECC_FREE(ec_key_pub); + SEC_LOG_ERROR("_ECCToPubBinary failed"); + return SEC_RESULT_FAILURE; + } + + SEC_ECC_FREE(ec_key_pub); + std::vector other_info = TestCtx::random(52); + TestCtx::printHex("other_info: ", other_info); + + if (SecKey_ECDHKeyAgreementWithKDF(keyHandle, &pub_other, keyType, id_derived, loc, SEC_KDF_CONCAT, + digestAlgorithm, &other_info[0], other_info.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ECDHKeyAgreementWithKDF failed"); + return SEC_RESULT_FAILURE; + } + + if (testEncDec) { + if (cipherEncDecSingle(&ctx, id_derived, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + } + + SecKey_Delete(ctx.proc(), id_derived); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyDeriveCMACAES128(SEC_OBJECTID idDerived, SEC_OBJECTID idBase, TestKc baseKc, Sec_KeyType keyType, + Sec_StorageLoc loc, bool testEncDec, SEC_BYTE counter, uint32_t L) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (ctx.provisionKey(idBase, loc, TESTKEY_AES128, baseKc) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //base key + TestCtx::printHex("baseKey", TestCreds::asOpenSslAes(TESTKEY_AES128)); + + //label + std::vector otherData = TestCtx::random(10); + //separator + otherData.push_back(0); + //ctx + std::vector ctx2 = TestCtx::random(32); + otherData.insert(otherData.end(), ctx2.begin(), ctx2.end()); + + otherData.push_back(0); + otherData.push_back(0); + otherData.push_back(0); + otherData.push_back(0); + Sec_Uint32ToBEBytes(L, &otherData[otherData.size() - 4]); + + TestCtx::printHex("otherData", otherData); + + if (SecKey_Derive_CMAC_AES128(ctx.proc(), idDerived, keyType, loc, idBase, &otherData[0], otherData.size(), + &counter, 1) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_CMAC_AES128 failed"); + return SEC_RESULT_FAILURE; + } + + if (testEncDec) { + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (cipherEncDecSingle(&ctx, idDerived, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + } + } + + SecKey_Delete(ctx.proc(), idDerived); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyDeriveBaseKey(SEC_OBJECTID idDerived, Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector nonce = TestCtx::random(SEC_NONCE_LEN); + TestCtx::printHex("nonce", nonce); + + if (SecKey_Derive_BaseKey(ctx.proc(), idDerived, SEC_KEYTYPE_HMAC_128, loc, &nonce[0]) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_BaseKey failed"); + return SEC_RESULT_FAILURE; + } + + SecKey_Delete(ctx.proc(), idDerived); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyDeriveHKDFBaseKey(Sec_KeyType typeDerived, Sec_StorageLoc loc, Sec_MacAlgorithm macAlgorithm) { + Sec_Result result = SEC_RESULT_FAILURE; + SEC_OBJECTID baseKeyId = SEC_OBJECTID_USER_BASE; + SEC_OBJECTID idDerived = baseKeyId + 1; + SEC_OBJECTID idDerivedSecond = idDerived + 1; + + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector nonce = TestCtx::random(SEC_NONCE_LEN); + TestCtx::printHex("nonce", nonce); + + std::vector salt = TestCtx::random(20); + TestCtx::printHex("salt", salt); + + std::vector info = TestCtx::random(40); + TestCtx::printHex("info", info); + do { + if (SecKey_Derive_BaseKey(ctx.proc(), baseKeyId, SEC_KEYTYPE_HMAC_128, loc, &nonce[0]) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_BaseKey failed"); + break; + } + + if (SecKey_Derive_HKDF_BaseKey(ctx.proc(), idDerived, typeDerived, loc, macAlgorithm, &salt[0], salt.size(), + &info[0], info.size(), baseKeyId) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_HKDF_BaseKey failed"); + break; + } + + //repeat derivation + if (SecKey_Derive_BaseKey(ctx.proc(), baseKeyId, SEC_KEYTYPE_HMAC_128, loc, &nonce[0]) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_BaseKey failed"); + break; + } + + if (SecKey_Derive_HKDF_BaseKey(ctx.proc(), idDerivedSecond, typeDerived, loc, macAlgorithm, &salt[0], + salt.size(), &info[0], info.size(), baseKeyId) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_HKDF_BaseKey failed"); + break; + } + + //test enc/dec or mac + if (SecKey_IsAES(typeDerived) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idDerived, idDerivedSecond) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + break; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idDerived, idDerivedSecond) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + break; + } + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + SecKey_Delete(ctx.proc(), baseKeyId); + SecKey_Delete(ctx.proc(), idDerived); + SecKey_Delete(ctx.proc(), idDerivedSecond); + + return result; +} + +Sec_Result testKeyDeriveConcatKDFBaseKey(Sec_KeyType typeDerived, Sec_StorageLoc loc, + Sec_DigestAlgorithm digestAlgorithm) { + SEC_OBJECTID baseKeyId = SEC_OBJECTID_USER_BASE; + SEC_OBJECTID idDerived = baseKeyId + 1; + SEC_OBJECTID idDerivedSecond = idDerived + 1; + Sec_Result result = SEC_RESULT_FAILURE; + + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector nonce = TestCtx::random(SEC_NONCE_LEN); + TestCtx::printHex("nonce", nonce); + + std::vector info = TestCtx::random(40); + TestCtx::printHex("info", info); + do { + if (SecKey_Derive_BaseKey(ctx.proc(), baseKeyId, SEC_KEYTYPE_AES_128, loc, &nonce[0]) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_BaseKey failed"); + break; + } + + if (SecKey_Derive_ConcatKDF_BaseKey(ctx.proc(), idDerived, typeDerived, loc, digestAlgorithm, &info[0], + info.size(), baseKeyId) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_ConcatKDF_BaseKey failed"); + SecKey_Delete(ctx.proc(), baseKeyId); + break; + } + + //repeat derivation + if (SecKey_Derive_BaseKey(ctx.proc(), baseKeyId, SEC_KEYTYPE_AES_128, loc, &nonce[0]) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_BaseKey failed"); + break; + } + + if (SecKey_Derive_ConcatKDF_BaseKey(ctx.proc(), idDerivedSecond, typeDerived, loc, digestAlgorithm, &info[0], + info.size(), baseKeyId) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_ConcatKDF_BaseKey failed"); + SecKey_Delete(ctx.proc(), baseKeyId); + break; + } + + //test enc/dec or mac + if (SecKey_IsAES(typeDerived) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idDerived, idDerivedSecond) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + break; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idDerived, idDerivedSecond) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + break; + } + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + SecKey_Delete(ctx.proc(), baseKeyId); + SecKey_Delete(ctx.proc(), idDerived); + SecKey_Delete(ctx.proc(), idDerivedSecond); + + return result; +} + +Sec_Result testExportProvisionedKey(TestKey key, TestKc kc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + //provision encryption key + Sec_KeyHandle* keyHandle = ctx.provisionKey(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, key, kc); + if (keyHandle == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //export j-type key + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + return SEC_RESULT_FAILURE; + } + exported_key.resize(exported_len); + + //provision exported + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, + &exported_key[0], exported_key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* exportedKeyHandle; + if (SecKey_GetInstance(ctx.proc(), SEC_OBJECTID_USER_BASE, &exportedKeyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + //grab properties from exported + Sec_KeyProperties exported_props; + if (SecKey_GetProperties(exportedKeyHandle, &exported_props) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetProperties failed"); + return SEC_RESULT_FAILURE; + } + + SecKey_Release(exportedKeyHandle); + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/key.h b/test/main/cpp/key.h new file mode 100644 index 0000000..0ed1ed8 --- /dev/null +++ b/test/main/cpp/key.h @@ -0,0 +1,71 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef KEY_H +#define KEY_H + +#include "sec_security.h" +#include "test_creds.h" + +Sec_Result testStore(SEC_BOOL encrypt, SEC_BOOL mac); + +Sec_Result testStoreProvision(SEC_OBJECTID id, SEC_BOOL encrypt, SEC_BOOL mac); + +Sec_Result testKeyProvision(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc); + +Sec_Result testKeyProvisionDouble(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, TestKey key2, TestKc kc2, + Sec_StorageLoc loc2); + +Sec_Result testKeyGetKeyInfo(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc); + +Sec_Result testKeyNoSha(SEC_OBJECTID id, TestKey key, TestKc kc); + +Sec_Result testKeyExtractPublicKey(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc); + +Sec_Result testKeyGenerate(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, bool testEncDec); + +Sec_Result testKeyDeriveHKDF(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, Sec_MacAlgorithm macAlgorithm, + bool testEncDec, bool useSalt); + +Sec_Result testKeyDeriveConcatKDF(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, + Sec_DigestAlgorithm digestAlgorithm, bool testEncDec); + +Sec_Result testKeyDeriveVendorAes128(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, + Sec_MacAlgorithm macAlgorithm, bool testEncDec); + +Sec_Result testKeyDeriveKeyLadderAes128(SEC_OBJECTID id, Sec_KeyType keyType, Sec_StorageLoc loc, + Sec_KeyLadderRoot root, bool testEncDec); + +Sec_Result testKeyComputeBaseKeyDigest(SEC_OBJECTID id, Sec_DigestAlgorithm alg); + +Sec_Result testKeyECDHKeyAgreementWithKDF(SEC_OBJECTID id_derived, SEC_OBJECTID id_priv, TestKey priv, TestKc priv_kc, + TestKey pub, Sec_KeyType keyType, Sec_StorageLoc loc, Sec_DigestAlgorithm digestAlgorithm, bool testEncDec); + +Sec_Result testKeyDeriveCMACAES128(SEC_OBJECTID idDerived, SEC_OBJECTID idBase, TestKc baseKc, Sec_KeyType keyType, + Sec_StorageLoc loc, bool testEncDec, SEC_BYTE counter, uint32_t L); + +Sec_Result testKeyDeriveBaseKey(SEC_OBJECTID idDerived, Sec_StorageLoc loc); + +Sec_Result testKeyDeriveHKDFBaseKey(Sec_KeyType typeDerived, Sec_StorageLoc loc, Sec_MacAlgorithm macAlgorithm); + +Sec_Result testKeyDeriveConcatKDFBaseKey(Sec_KeyType typeDerived, Sec_StorageLoc loc, + Sec_DigestAlgorithm digestAlgorithm); + +Sec_Result testExportProvisionedKey(TestKey key, TestKc kc); + +#endif // KEY_H diff --git a/test/main/cpp/keyctrl.cpp b/test/main/cpp/keyctrl.cpp new file mode 100644 index 0000000..561f14a --- /dev/null +++ b/test/main/cpp/keyctrl.cpp @@ -0,0 +1,1813 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "keyctrl.h" // NOLINT +#include "jtype.h" +#include "sec_adapter_utils.h" +#include "sec_security_comcastids.h" +#include "sign.h" +#include "test_ctx.h" + +#define BUFFER_SIZE 4096 + +// default params for jtype key container +struct default_jtype_data_struct { + TestKey contentKey; + TestKey encryptionKey; + TestKc encKc; + TestKey macKey; + TestKc macKc; + SEC_OBJECTID provisionId; +} __attribute__((aligned(32))) g_default_jtype_data = { + .contentKey = TESTKEY_AES128, + .encryptionKey = TESTKEY_AES128, + .encKc = TESTKC_CONDITIONAL, + .macKey = TESTKEY_HMAC160, + .macKc = TESTKC_RAW, + .provisionId = SEC_OBJECTID_USER_BASE}; + +static char opr_str[8][64] = { + "Not-set", + "SVP", + "DTCP", + "HDCP-1.4", + "HDCP-2.2", + "Analog", + "Transcription-copy", + "Unrestricted-copy"}; + +#define RIGHTS_INIT(x) memset(x, 0, SEC_KEYOUTPUTRIGHT_NUM) + +std::string toB64(const SEC_BYTE* data, SEC_SIZE len); + +/* Convenience function to provision the jtype key and session keys using the default + * settings. Since the jtype is a wrapped key, a check is performed to test if the + * platform supports wrapped keys in the clear. if it doesn't, SOC key container + * needs to be used. + */ +static Sec_KeyHandle* provisionJTypeAndSession(TestCtx& ctx, std::string& jtypeKey) { + Sec_KeyHandle* keyHandle = nullptr; + + do { + if (SecKey_IsProvisioned(ctx.proc(), SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY) == SEC_TRUE && + SecKey_IsProvisioned(ctx.proc(), SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY) == SEC_TRUE) { + SEC_PRINT("Session ENC and MAC keys are already provisioned. Not provisioning again.\n"); + } else { + SEC_PRINT("Provisioning session ENC and MAC.\n"); + + //provision encryption key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY, SEC_STORAGELOC_RAM, + g_default_jtype_data.encryptionKey, g_default_jtype_data.encKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + break; + } + + //provision maccing key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY, SEC_STORAGELOC_RAM, + g_default_jtype_data.macKey, g_default_jtype_data.macKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + break; + } + } + + //provision jtype key + if (SecKey_Provision(ctx.proc(), g_default_jtype_data.provisionId, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_JTYPE, + reinterpret_cast(&jtypeKey[0]), jtypeKey.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + break; + } + + if (SecKey_GetInstance(ctx.proc(), g_default_jtype_data.provisionId, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed for jtype key"); + break; + } + } while (false); + + return keyHandle; +} + +/* SecCipher_GetInstance should fail with notBefore date in the future */ +Sec_Result testKeyCtrlKeyNotYetAvail(int version, const char* alg) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + const char* notBeforeTimeStr = "2022-12-09T19:53:06Z"; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + do { + /* key avail in one hour */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", + createDefaultRights(SEC_KEYTYPE_AES_128).c_str(), SEC_FALSE, 1, notBeforeTimeStr, + "2030-12-09T19:53:06Z", g_default_jtype_data.macKey, version, alg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + break; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + if (SecCipher_GetInstance(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, keyHandle, + iv, &cipherHandle) != SEC_RESULT_FAILURE) { + SEC_LOG_ERROR("expected SecCipher_GetInstance to fail for jtype key with notBefore [%s]", notBeforeTimeStr); + + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (cipherHandle != nullptr) + SecCipher_Release(cipherHandle); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +/* Generate a jtype key with usage of key only. SecCipher_GetInstance should fail. */ +Sec_Result testKeyCtrlKeyOnlyUsage(int version, const char* alg) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + do { + /* expired key */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", + createDefaultRights(SEC_KEYTYPE_AES_128).c_str(), SEC_FALSE, SEC_KEYUSAGE_KEY, "2010-12-09T19:53:06Z", + "2025-12-09T01:02:03Z", g_default_jtype_data.macKey, version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + break; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + if (SecCipher_GetInstance(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, keyHandle, + iv, &cipherHandle) == SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR( + "expected Seccipher_GetInstance to fail for key with usage flag for 'key' only"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + if (cipherHandle != nullptr) + SecCipher_Release(cipherHandle); + + return result; +} + +/* Generate a jtype key with usage of data only. */ +Sec_Result testKeyCtrlUnwrapWithKeyUsage(int version, const char* alg, TestKey contentKey) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", + createDefaultRights(TestCreds::getKeyType(contentKey)).c_str(), SEC_FALSE, SEC_KEYUSAGE_KEY, + "2010-12-09T19:53:06Z", "2025-12-09T01:02:03Z", g_default_jtype_data.macKey, version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + /* FIXME: actually encrypt the key bytes first */ + + //create wrapped asn1 key + std::vector wrapped = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector asn1; + asn1.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE asn1_len; + SEC_BYTE input[SEC_AES_BLOCK_SIZE]; + SEC_BYTE output[SEC_AES_BLOCK_SIZE]; + SEC_SIZE output_len; + + do { + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + if (SecKey_GenerateWrappedKeyAsn1(&wrapped[0], wrapped.size(), SEC_KEYTYPE_AES_128, + g_default_jtype_data.provisionId, nullptr, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, + &asn1[0], asn1.size(), &asn1_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GenerateWrappedKeyAsn1 failed"); + break; + } + asn1.resize(asn1_len); + + //provision wrapped + SEC_PRINT("Provisioning wrapped\n"); + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE + 1, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_ASN1, + &asn1[0], asn1.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + break; + } + + SEC_PRINT("Wielding wrapped\n"); + if (SecCipher_SingleInputId(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, + SEC_OBJECTID_USER_BASE + 1, nullptr, input, sizeof(input), output, sizeof(output), + &output_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +Sec_Result testKeyCtrlUnwrapWithDataUsage(int version, const char* alg) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + //create wrapped asn1 key + std::vector wrapped = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector asn1; + asn1.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE asn1_len; + SEC_BYTE input[SEC_AES_BLOCK_SIZE]; + SEC_BYTE output[SEC_AES_BLOCK_SIZE]; + SEC_SIZE output_len; + std::string jtype; + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key(SEC_KEYCONTAINER_MAX_LEN, 0); + SEC_SIZE exported_len = 0; + + do { + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + break; + } + + jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", + createDefaultRights(SEC_KEYTYPE_AES_128).c_str(), SEC_TRUE, SEC_KEYUSAGE_DATA, "2010-12-09T19:53:06Z", + "2025-12-09T01:02:03Z", g_default_jtype_data.macKey, version, alg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + if (SecKey_GenerateWrappedKeyAsn1(&wrapped[0], wrapped.size(), SEC_KEYTYPE_AES_128, SEC_OBJECTID_USER_BASE, + nullptr, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, &asn1[0], asn1.size(), &asn1_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GenerateWrappedKeyAsn1 failed"); + break; + } + asn1.resize(asn1_len); + + //provision wrapped + SEC_PRINT("Provisioning wrapped\n"); + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE + 1, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_ASN1, + &asn1[0], asn1.size()) != SEC_RESULT_SUCCESS) { + //this will fail on some platforms, others will fail when wielding cipher + result = SEC_RESULT_SUCCESS; + break; + } + + SEC_PRINT("Wielding wrapped\n"); + if (SecCipher_SingleInputId(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, + SEC_OBJECTID_USER_BASE + 1, nullptr, input, sizeof(input), output, sizeof(output), + &output_len) == SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Expected provisioning or wielding cipher to fail"); + break; + } + + /* export the jtype and re-provision as exported to test exported logic as well */ + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Export failed"); + break; + } + SecKey_Release(keyHandle); + keyHandle = nullptr; + SecKey_Delete(ctx.proc(), g_default_jtype_data.provisionId); + + /* provision exported */ + if (SecKey_Provision(ctx.proc(), g_default_jtype_data.provisionId, SEC_STORAGELOC_RAM, + SEC_KEYCONTAINER_EXPORTED, &exported_key[0], exported_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed for exported key"); + break; + } + + if (SecCipher_SingleInputId(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, + SEC_OBJECTID_USER_BASE + 1, nullptr, input, sizeof(input), output, sizeof(output), + &output_len) == SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Expected provisioning or wielding cipher to fail"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +/* SecCipher_Getinstance should fail with notOnOrAfter date < now */ +Sec_Result testKeyCtrlKeyExpired(int version, const char* alg) { + TestCtx ctx; + + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + const char* notOnOrAfter = "2015-12-09T19:53:06Z"; + Sec_Result result = SEC_RESULT_FAILURE; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + /* expired key */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", + createDefaultRights(SEC_KEYTYPE_AES_128).c_str(), SEC_FALSE, 1, "2010-12-09T19:53:06Z", notOnOrAfter, + g_default_jtype_data.macKey, version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + do { + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + if (SecCipher_GetInstance(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, keyHandle, + iv, &cipherHandle) == SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Expected Seccipher_GetInstance to fail for jtype key with expired notOnOrAfter [%s]", + notOnOrAfter); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (cipherHandle != nullptr) + SecCipher_Release(cipherHandle); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +/* On 32bit machine, provision should fail if key contains date > 2038/01/19 */ +Sec_Result testKeyCtrlProvision32bit2038(int version, const char* alg) { + TestCtx ctx; + + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + TestKey contentKey = TESTKEY_AES128; + TestKey encryptionKey = TESTKEY_AES128; + TestKc encKc = TestCreds::supports(CAPABILITY_CLEAR_JTYPE_WRAPPING) ? g_default_jtype_data.encKc : TESTKC_SOC; + TestKey macKey = TESTKEY_HMAC160; + TestKc macKc = TESTKC_RAW; + const char* notOnOrAfter = "2038-12-09T19:53:06Z"; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + /* expired key */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, encryptionKey, + "9c621060-3a17-4813-8dcb-2e9187aaa903", createDefaultRights(SEC_KEYTYPE_AES_128).c_str(), SEC_FALSE, 1, + "2010-12-09T19:53:06Z", notOnOrAfter, macKey, version, alg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + //provision encryption key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY, SEC_STORAGELOC_RAM, encryptionKey, encKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + //provision maccing key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY, SEC_STORAGELOC_RAM, macKey, macKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //provision jtype key +#if defined(__x86_64__) || defined(__ppc64__) + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_JTYPE, + reinterpret_cast(&jtype[0]), jtype.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } +#else + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_JTYPE, + reinterpret_cast(&jtype[0]), jtype.size()) == SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Expecting SecKey_Provision to fail on jtype with date '%s'", notOnOrAfter); + return SEC_RESULT_FAILURE; + } +#endif + + return SEC_RESULT_SUCCESS; +} + +/* test that export fails with a jtype key where is_cacheable is false */ +Sec_Result testKeyCtrlExportUnCachable(int version, const char* alg) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + Sec_KeyHandle* keyHandle = nullptr; + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key(SEC_KEYCONTAINER_MAX_LEN, 0); + SEC_SIZE exported_len = 0; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", + createDefaultRights(SEC_KEYTYPE_AES_128).c_str(), SEC_FALSE, 1, "2010-12-09T19:53:06Z", + "2037-12-09T19:53:06Z", g_default_jtype_data.macKey, version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + return SEC_RESULT_FAILURE; + } + + do { + //get properties from j-type + Sec_KeyProperties jtype_props; + if (SecKey_GetProperties(keyHandle, &jtype_props) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetProperties failed"); + break; + } + + //export j-type key + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) == + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Expected SecKey_ExportKey to fail with cachable flag set to false"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +Sec_Result testKeyCtrlExpectedJTypeProperties(int version, const char* alg, TestKey contentKey) { + TestCtx ctx; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + const char* notOnOrAfter = "2025-12-09T19:53:06Z"; + const char* notBefore = "2010-12-09T19:53:06Z"; + const char* keyId = "9c621060-3a17-4813-8dcb-2e9187aaa903"; + Sec_KeyProperties keyProps; + SEC_BOOL cacheable = SEC_FALSE; + Sec_KeyUsage keyUsage = SEC_KEYUSAGE_KEY; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + /* expired key */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, + g_default_jtype_data.encryptionKey, keyId, createDefaultRights(TestCreds::getKeyType(contentKey)).c_str(), + cacheable, keyUsage, notBefore, notOnOrAfter, g_default_jtype_data.macKey, version, alg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + return SEC_RESULT_FAILURE; + } + + SecKey_GetProperties(keyHandle, &keyProps); + SecKey_Release(keyHandle); + + if (strcmp(keyId, keyProps.keyId) != 0) { + SEC_LOG_ERROR("Keyid mismatch expecting '%s', received '%s'", keyId, keyProps.keyId); + return SEC_RESULT_FAILURE; + } + if (strcmp(notOnOrAfter, keyProps.notOnOrAfter) != 0) { + SEC_LOG_ERROR("NotOnOrAfter mismatch expecting '%s', received '%s'", notOnOrAfter, keyProps.notOnOrAfter); + return SEC_RESULT_FAILURE; + } + if (strcmp(notBefore, keyProps.notBefore) != 0) { + SEC_LOG_ERROR("NotBefore mismatch expecting '%s', received '%s'", notBefore, keyProps.notBefore); + return SEC_RESULT_FAILURE; + } + if (TestCreds::getKeyType(contentKey) != keyProps.keyType) { + SEC_LOG_ERROR("KeyType mismatch. got %d, expected %d", keyProps.keyType, TestCreds::getKeyType(contentKey)); + return SEC_RESULT_FAILURE; + } + if (SecKey_GetKeyLenForKeyType(TestCreds::getKeyType(contentKey)) != keyProps.keyLength) { + SEC_LOG_ERROR("KeyLength mismatch expecting %d, received %d", + SecKey_GetKeyLenForKeyType(TestCreds::getKeyType(contentKey)), keyProps.keyLength); + return SEC_RESULT_FAILURE; + } + if (cacheable != keyProps.cacheable) { + SEC_LOG_ERROR("Cacheable mismatch, expecting %d", cacheable); + return SEC_RESULT_FAILURE; + } + if (keyUsage != keyProps.usage) { + SEC_LOG_ERROR("Usage mismatch, expecting %d, received %d", keyUsage, keyProps.usage); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyCtrlBadB64Jtype(int version, const char* alg) { + TestCtx ctx; + TestKey contentKey = TESTKEY_AES128; + TestKey encryptionKey = TESTKEY_AES128; + TestKey macKey = TESTKEY_HMAC160; + TestKc macKc = TESTKC_RAW; + SEC_SIZE input_len = 256; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::string jtype = "B" + createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, encryptionKey, + "9c621060-3a17-4813-8dcb-2e9187aaa903", + createDefaultRights(SEC_KEYTYPE_AES_128).c_str(), SEC_FALSE, 1, + "2010-12-09T19:53:06Z", "2037-12-09T19:53:06Z", macKey, version, alg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsProvisioned(ctx.proc(), SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY) == SEC_TRUE && + SecKey_IsProvisioned(ctx.proc(), SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY) == SEC_TRUE) { + SEC_PRINT("Session ENC and MAC keys are already provisioned. Not provisioning again.\n"); + } else { + SEC_PRINT("Provisioning session ENC and MAC.\n"); + + //provision encryption key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONENCKEY, SEC_STORAGELOC_RAM, + g_default_jtype_data.encryptionKey, g_default_jtype_data.encKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //provision maccing key + if (ctx.provisionKey(SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY, SEC_STORAGELOC_RAM, g_default_jtype_data.macKey, + g_default_jtype_data.macKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return SEC_RESULT_FAILURE; + } + } + + //provision jtype key + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_JTYPE, + reinterpret_cast(&jtype[0]), jtype.size()) != SEC_RESULT_FAILURE) { + SEC_LOG_ERROR("Expected provisionKey to failed with bad base64"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyCtrlExportEcc(TestKc kc) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + SEC_OBJECTID priv_id = SEC_OBJECTID_USER_BASE + 1; + Sec_KeyHandle* keyHandle = nullptr; + TestKey pub = TESTKEY_EC_PUB; + TestKey priv = TESTKEY_EC_PRIV; + std::vector clear = TestCtx::random(32); + std::vector derivation_input = TestCtx::random(16); + SEC_BYTE exported_buffer[1024]; + std::vector signature; + signature.resize(512); + SEC_SIZE exported_size = 0; + SEC_SIZE cipher_output_written = 0; + SEC_SIZE signature_size = 0; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if ((keyHandle = ctx.provisionKey(priv_id, SEC_STORAGELOC_RAM, priv, kc)) == nullptr) { + SEC_LOG_ERROR("Provision priv key failed"); + return SEC_RESULT_FAILURE; + } + + if (SecSignature_SingleInputId(ctx.proc(), SEC_SIGNATUREALGORITHM_ECDSA_NISTP256, SEC_SIGNATUREMODE_SIGN, priv_id, + &clear[0], clear.size(), &signature[0], &signature_size) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInputId failed on signing with priv ecc key"); + return SEC_RESULT_FAILURE; + } + signature.resize(signature_size); + + //verify + if (verifyOpenSSL(SEC_SIGNATUREALGORITHM_ECDSA_NISTP256, pub, clear, signature) != SEC_TRUE) { + SEC_LOG_ERROR("VerifyOpenSSL failed"); + return SEC_RESULT_FAILURE; + } + + /* export priv key */ + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_buffer, sizeof(exported_buffer), + &exported_size) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Export failed for private ecc"); + return SEC_RESULT_FAILURE; + } + SecKey_Delete(ctx.proc(), priv_id); + + if (SecKey_Provision(ctx.proc(), priv_id, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, exported_buffer, + exported_size) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + signature.resize(512); + if (SecSignature_SingleInputId(ctx.proc(), SEC_SIGNATUREALGORITHM_ECDSA_NISTP256, SEC_SIGNATUREMODE_VERIFY, priv_id, + &clear[0], clear.size(), &signature[0], &signature_size) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_SingleInputId failed on verification with priv ecc key"); + return SEC_RESULT_FAILURE; + } + signature.resize(signature_size); + + //verify + if (verifyOpenSSL(SEC_SIGNATUREALGORITHM_ECDSA_NISTP256, pub, clear, signature) != SEC_TRUE) { + SEC_LOG_ERROR("VerifyOpenSSL failed"); + return SEC_RESULT_FAILURE; + } + + result = SEC_RESULT_SUCCESS; + + return result; +} + +Sec_Result testKeyCtrlExportAes(TestKey aesKey, Sec_StorageLoc location) { + Sec_Result result = SEC_RESULT_FAILURE; + Sec_KeyHandle* keyHandle = nullptr; + int i = 0; + + TestCtx ctx; + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + SEC_BYTE exported_key[BUFFER_SIZE]; + SEC_SIZE exported_key_len = 0; + SEC_SIZE exported_key_len2 = 0; + Sec_CipherAlgorithm alg = SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING; + Sec_KeyProperties keyProps; + std::vector encrypted(SEC_AES_BLOCK_SIZE); + std::vector decrypted(SEC_AES_BLOCK_SIZE); + SEC_SIZE enc_len = 0; + Sec_KeyContainer keyContainerType = SEC_KEYCONTAINER_RAW_AES_128; + + memset(&keyProps, 0, sizeof(Sec_KeyProperties)); + + if (keyHandle != nullptr) { + SecKey_Release(keyHandle); + } + keyHandle = nullptr; + + // input to export function + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + + //gen iv + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + + //gen clear input + std::vector clear = TestCtx::random(SEC_AES_BLOCK_SIZE); + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_PRINT("SEC_KEYCONTAINER_RAW_AES_128\n"); + ProvKey* p = TestCreds::getKey(aesKey, TESTKC_RAW, id); + SEC_PRINT("provisioning " SEC_OBJECTID_PATTERN "\n", id); + + if (SecKey_Provision(ctx.proc(), id, location, + aesKey == TESTKEY_AES128 ? SEC_KEYCONTAINER_RAW_AES_128 : SEC_KEYCONTAINER_RAW_AES_256, + &p->key[0], p->key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + delete p; + return SEC_RESULT_FAILURE; + } + + delete p; + + do { + //encrypt + if (SecCipher_SingleInputId(ctx.proc(), alg, SEC_CIPHERMODE_ENCRYPT, id, nullptr, &clear[0], clear.size(), + &encrypted[0], encrypted.size(), &enc_len) != SEC_RESULT_SUCCESS) { + + SEC_LOG_ERROR("Encrypt failed"); + break; + } + + if (SecKey_GetInstance(ctx.proc(), id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + break; + } + // get size + if (SecKey_ExportKey(keyHandle, &derivation_input[0], nullptr, 0, &exported_key_len2) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed for key size"); + break; + } + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_key, sizeof(exported_key), &exported_key_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + break; + } + SecKey_Release(keyHandle); + keyHandle = nullptr; + + if (exported_key_len2 != exported_key_len) { + SEC_LOG_ERROR("Exported key length mismatch, expected %d, received %d", + exported_key_len2, exported_key_len); + break; + } + + // NOTE: on intel, exported keys MUST be provisioned with the same object_id as when + // they were originally provisioned. + SEC_PRINT("provisioning exported " SEC_OBJECTID_PATTERN "\n", id); + if (SecKey_Provision(ctx.proc(), id, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, exported_key, + exported_key_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + // test decrypt with exported key + if (SecCipher_SingleInputId(ctx.proc(), alg, SEC_CIPHERMODE_DECRYPT, id, nullptr, &encrypted[0], + encrypted.size(), &decrypted[0], decrypted.size(), &enc_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Decrypt failed"); + break; + } + TestCtx::printHex("derivation input", derivation_input); + TestCtx::printHex(" encrypted", encrypted); + TestCtx::printHex(" decrypted", decrypted); + TestCtx::printHex(" clear", clear); + if (clear != decrypted) { + SEC_LOG_ERROR("Decrypted vector mismatch"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +Sec_Result testKeyCtrlExportDerived() { + Sec_Result result = SEC_RESULT_FAILURE; + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + SEC_BYTE exported_key[BUFFER_SIZE]; + SEC_SIZE exported_key_len = 0; + Sec_KeyHandle* keyHandle = nullptr; + TestCtx ctx; + SEC_BYTE enc_output[256]; + SEC_SIZE enc_output_len = 0; + SEC_BYTE enc_output2[256]; + SEC_SIZE enc_output_len2 = 0; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + + std::vector input = TestCtx::random(25); + TestCtx::printHex("input", input); + + if (SecKey_Derive_VendorAes128(ctx.proc(), id, SEC_STORAGELOC_RAM, &input[0], input.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_VendorAes128 failed"); + return SEC_RESULT_FAILURE; + } + + do { + if (SecKey_GetInstance(ctx.proc(), id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + break; + } + + if (SecCipher_SingleInputId(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, id, + nullptr, &derivation_input[0], derivation_input.size(), enc_output, sizeof(enc_output), + &enc_output_len) != SEC_RESULT_SUCCESS) { + + SEC_LOG_ERROR("Encrypt failed"); + break; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_key, sizeof(exported_key), &exported_key_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed for derived key type"); + break; + } + SecKey_Release(keyHandle); + keyHandle = nullptr; + SecKey_Delete(ctx.proc(), id); + + /* import exported derived key */ + if (SecKey_Provision(ctx.proc(), id, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, exported_key, + exported_key_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed for exported key"); + return SEC_RESULT_FAILURE; + } + if (SecKey_GetInstance(ctx.proc(), id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + break; + } + if (SecCipher_SingleInputId(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, id, + nullptr, enc_output, enc_output_len, enc_output2, sizeof(enc_output2), &enc_output_len2) != + SEC_RESULT_SUCCESS) { + + SEC_LOG_ERROR("Decrypt failed"); + break; + } + if (derivation_input.size() != enc_output_len2) { + SEC_LOG_ERROR("Enc output size mismatch, expected %d, %d", derivation_input.size(), enc_output_len2); + break; + } + Sec_PrintHex(&derivation_input[0], derivation_input.size()); + SEC_PRINT("\n"); + Sec_PrintHex(enc_output2, enc_output_len2); + SEC_PRINT("\n"); + if (memcmp(&derivation_input[0], enc_output2, enc_output_len2) != 0) { + SEC_LOG_ERROR("Enc output mismatch"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +Sec_Result testKeyCtrlExpectedExportedProperties(int version, const char* alg, TestKey contentKey) { + TestCtx ctx; + + SEC_BYTE jtypeRights[SEC_KEYOUTPUTRIGHT_NUM]; + std::string b64rights; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + const char* notOnOrAfter = "2025-12-09T19:53:06Z"; + const char* notBefore = "2010-12-09T19:53:06Z"; + const char* keyId = "9c621060-3a17-4813-8dcb-2e9187aaa903"; + Sec_KeyProperties keyProps; + SEC_BOOL cacheable = SEC_TRUE; + Sec_KeyUsage keyUsage = SEC_KEYUSAGE_KEY; + SEC_BYTE exported_key[BUFFER_SIZE]; + SEC_SIZE exported_key_len = 0; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + RIGHTS_INIT(jtypeRights); + jtypeRights[0] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + jtypeRights[1] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + jtypeRights[2] = SEC_KEYOUTPUTRIGHT_ANALOG_OUTPUT_ALLOWED; + b64rights = toB64(jtypeRights, SEC_KEYOUTPUTRIGHT_NUM); + + /* expired key */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, + g_default_jtype_data.encryptionKey, keyId, b64rights.c_str(), cacheable, keyUsage, notBefore, notOnOrAfter, + g_default_jtype_data.macKey, version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + return SEC_RESULT_FAILURE; + } + + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_key, sizeof(exported_key), &exported_key_len) != + SEC_RESULT_SUCCESS) { + SecKey_Release(keyHandle); + SEC_LOG_ERROR("SecKey_ExportKey failed"); + return SEC_RESULT_FAILURE; + } + + SecKey_Release(keyHandle); + keyHandle = nullptr; + SecKey_Delete(ctx.proc(), SEC_OBJECTID_USER_BASE); + + // reprovision exported + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, + exported_key, exported_key_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed for exported key"); + return SEC_RESULT_FAILURE; + } + if (SecKey_GetInstance(ctx.proc(), SEC_OBJECTID_USER_BASE, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed for exported key"); + return SEC_RESULT_FAILURE; + } + + SecKey_GetProperties(keyHandle, &keyProps); + SecKey_Release(keyHandle); + keyHandle = nullptr; + + if (strcmp(keyId, keyProps.keyId) != 0) { + SEC_LOG_ERROR("Keyid mismatch expecting '%s', received '%s'", keyId, keyProps.keyId); + return SEC_RESULT_FAILURE; + } + if (strcmp(notOnOrAfter, keyProps.notOnOrAfter) != 0) { + SEC_LOG_ERROR("NotOnOrAfter mismatch expecting '%s', received '%s'", notOnOrAfter, keyProps.notOnOrAfter); + return SEC_RESULT_FAILURE; + } + if (strcmp(notBefore, keyProps.notBefore) != 0) { + SEC_LOG_ERROR("NotBefore mismatch expecting '%s', received '%s'", notBefore, keyProps.notBefore); + return SEC_RESULT_FAILURE; + } + if (TestCreds::getKeyType(contentKey) != keyProps.keyType) { + SEC_LOG_ERROR("KeyType mismatch. got %d, expected %d", keyProps.keyType, TestCreds::getKeyType(contentKey)); + return SEC_RESULT_FAILURE; + } + if (SecKey_GetKeyLenForKeyType(TestCreds::getKeyType(contentKey)) != keyProps.keyLength) { + SEC_LOG_ERROR("KeyLength mismatch expecting %d, received %d", + SecKey_GetKeyLenForKeyType(TestCreds::getKeyType(contentKey)), keyProps.keyLength); + return SEC_RESULT_FAILURE; + } + if (cacheable != keyProps.cacheable) { + SEC_LOG_ERROR("Cacheable mismatch, expecting %d", cacheable); + return SEC_RESULT_FAILURE; + } + if (keyUsage != keyProps.usage) { + SEC_LOG_ERROR("Usage mismatch, expecting %d, received %d", keyUsage, keyProps.usage); + return SEC_RESULT_FAILURE; + } + + if (memcmp(keyProps.rights, jtypeRights, 8) != 0) { + SEC_LOG_ERROR("Keyrights mismatch"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +/* export a key, re-provision it, then export it again + */ +Sec_Result testKeyCtrlExportProvisionExport(int version, const char* alg, TestKey contentKey) { + TestCtx ctx; + + SEC_BYTE jtypeRights[SEC_KEYOUTPUTRIGHT_NUM]; + std::string b64rights; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + const char* notOnOrAfter = "2025-12-09T19:53:06Z"; + const char* notBefore = "2010-12-09T19:53:06Z"; + const char* keyId = "9c621060-3a17-4813-8dcb-2e9187aaa903"; + Sec_KeyProperties keyProps; + SEC_BOOL cacheable = SEC_TRUE; + Sec_KeyUsage keyUsage = SEC_KEYUSAGE_KEY; + SEC_BYTE exported_key[BUFFER_SIZE]; + SEC_SIZE exported_key_len = 0; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + RIGHTS_INIT(jtypeRights); + jtypeRights[0] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + jtypeRights[1] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + jtypeRights[2] = SEC_KEYOUTPUTRIGHT_ANALOG_OUTPUT_ALLOWED; + b64rights = toB64(jtypeRights, SEC_KEYOUTPUTRIGHT_NUM); + + /* expired key */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, + g_default_jtype_data.encryptionKey, keyId, b64rights.c_str(), cacheable, keyUsage, notBefore, notOnOrAfter, + g_default_jtype_data.macKey, version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + return SEC_RESULT_FAILURE; + } + + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_key, sizeof(exported_key), &exported_key_len) != + SEC_RESULT_SUCCESS) { + SecKey_Release(keyHandle); + SEC_LOG_ERROR("SecKey_ExportKey failed"); + return SEC_RESULT_FAILURE; + } + + SecKey_Release(keyHandle); + keyHandle = nullptr; + SecKey_Delete(ctx.proc(), SEC_OBJECTID_USER_BASE); + + // reprovision exported + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, + exported_key, exported_key_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed for exported key"); + return SEC_RESULT_FAILURE; + } + if (SecKey_GetInstance(ctx.proc(), SEC_OBJECTID_USER_BASE, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed for exported key"); + return SEC_RESULT_FAILURE; + } + + // export it again + derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_key, sizeof(exported_key), &exported_key_len) != + SEC_RESULT_SUCCESS) { + SecKey_Release(keyHandle); + SEC_LOG_ERROR("SecKey_ExportKey failed"); + return SEC_RESULT_FAILURE; + } + SecKey_Release(keyHandle); + keyHandle = nullptr; + SecKey_Delete(ctx.proc(), SEC_OBJECTID_USER_BASE); + + // reprovision exported + if (SecKey_Provision(ctx.proc(), SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, + exported_key, exported_key_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed for exported key"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_GetInstance(ctx.proc(), SEC_OBJECTID_USER_BASE, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed for exported key"); + return SEC_RESULT_FAILURE; + } + + SecKey_GetProperties(keyHandle, &keyProps); + SecKey_Release(keyHandle); + keyHandle = nullptr; + + if (strcmp(keyId, keyProps.keyId) != 0) { + SEC_LOG_ERROR("Keyid mismatch expecting '%s', received '%s'", keyId, keyProps.keyId); + return SEC_RESULT_FAILURE; + } + if (strcmp(notOnOrAfter, keyProps.notOnOrAfter) != 0) { + SEC_LOG_ERROR("NotOnOrAfter mismatch expecting '%s', received '%s'", notOnOrAfter, keyProps.notOnOrAfter); + return SEC_RESULT_FAILURE; + } + if (strcmp(notBefore, keyProps.notBefore) != 0) { + SEC_LOG_ERROR("NotBefore mismatch expecting '%s', received '%s'", notBefore, keyProps.notBefore); + return SEC_RESULT_FAILURE; + } + if (TestCreds::getKeyType(contentKey) != keyProps.keyType) { + SEC_LOG_ERROR("KeyType mismatch. got %d, expected %d", keyProps.keyType, TestCreds::getKeyType(contentKey)); + return SEC_RESULT_FAILURE; + } + if (SecKey_GetKeyLenForKeyType(TestCreds::getKeyType(contentKey)) != keyProps.keyLength) { + SEC_LOG_ERROR("KeyLength mismatch expecting %d, received %d", + SecKey_GetKeyLenForKeyType(TestCreds::getKeyType(contentKey)), keyProps.keyLength); + return SEC_RESULT_FAILURE; + } + if (cacheable != keyProps.cacheable) { + SEC_LOG_ERROR("Cacheable mismatch, expecting %d", cacheable); + return SEC_RESULT_FAILURE; + } + if (keyUsage != keyProps.usage) { + SEC_LOG_ERROR("Usage mismatch, expecting %d, received %d", keyUsage, keyProps.usage); + return SEC_RESULT_FAILURE; + } + + if (memcmp(keyProps.rights, jtypeRights, 8) != 0) { + SEC_LOG_ERROR("Keyrights mismatch"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +// get just size needed for key by passing NULL out buffer to KeyExport call +Sec_Result testKeyCtrlKeyExportGetSize(int version, const char* alg) { + TestCtx ctx; + + SEC_BYTE jtypeRights[SEC_KEYOUTPUTRIGHT_NUM]; + std::string b64rights; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + const char* notOnOrAfter = "2025-12-09T19:53:06Z"; + const char* notBefore = "2010-12-09T19:53:06Z"; + const char* keyId = "9c621060-3a17-4813-8dcb-2e9187aaa903"; + Sec_KeyProperties keyProps; + SEC_BOOL cacheable = SEC_TRUE; + Sec_KeyUsage keyUsage = SEC_KEYUSAGE_KEY; + SEC_BYTE exported_key[BUFFER_SIZE]; + SEC_SIZE exported_key_len = 0; + SEC_SIZE exported_key_len2 = 0; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + RIGHTS_INIT(jtypeRights); + jtypeRights[0] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + jtypeRights[1] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + jtypeRights[2] = SEC_KEYOUTPUTRIGHT_ANALOG_OUTPUT_ALLOWED; + b64rights = toB64(jtypeRights, SEC_KEYOUTPUTRIGHT_NUM); + + /* expired key */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, keyId, b64rights.c_str(), cacheable, + keyUsage, notBefore, notOnOrAfter, g_default_jtype_data.macKey, version, + alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + return SEC_RESULT_FAILURE; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + return SEC_RESULT_FAILURE; + } + + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + + // get size + if (SecKey_ExportKey(keyHandle, &derivation_input[0], nullptr, 0, &exported_key_len2) != SEC_RESULT_SUCCESS) { + SecKey_Release(keyHandle); + SEC_LOG_ERROR("SecKey_ExportKey failed while getting key length"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_key, sizeof(exported_key), &exported_key_len) != + SEC_RESULT_SUCCESS) { + SecKey_Release(keyHandle); + SEC_LOG_ERROR("SecKey_ExportKey failed"); + return SEC_RESULT_FAILURE; + } + SecKey_Release(keyHandle); + keyHandle = nullptr; + + if (exported_key_len != exported_key_len2) { + SEC_LOG_ERROR("Exported key length mismatch, expected %d, received %d", exported_key_len2, exported_key_len); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyCtrlKeyExportHmac(TestKey macKey, Sec_StorageLoc location) { + TestCtx ctx; + Sec_Result result = SEC_RESULT_FAILURE; + + Sec_KeyHandle* keyHandle = nullptr; + TestKc macKc = TESTKC_RAW; + Sec_KeyProperties keyProps; + SEC_BYTE exported_key[BUFFER_SIZE]; + SEC_SIZE exported_key_len = 0; + SEC_SIZE exported_key_len2 = 0; + Sec_MacHandle* macHandle = nullptr; + SEC_BYTE mac_output[256]; + SEC_SIZE mac_output_len = 0; + SEC_BYTE mac_output2[256]; + SEC_SIZE mac_output_len2 = 0; + SEC_OBJECTID id = SEC_OBJECTID_COMCAST_XCALSESSIONMACKEY; + + memset(mac_output, 0, sizeof(mac_output)); + memset(mac_output2, 0, sizeof(mac_output2)); + + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + + do { + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + break; + } + + //provision maccing key + if (ctx.provisionKey(id, location, macKey, macKc) == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + break; + } + + if (SecKey_GetInstance(ctx.proc(), id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed for session mac key"); + break; + } + + if (SecMac_GetInstance(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA1, keyHandle, &macHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_GetInstance failed for hmac key"); + break; + } + if (SecMac_Update(macHandle, &derivation_input[0], derivation_input.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_GetInstance failed for hmac key"); + break; + } + + SecMac_Release(macHandle, mac_output, &mac_output_len); + macHandle = nullptr; + + // get size + if (SecKey_ExportKey(keyHandle, &derivation_input[0], nullptr, 0, &exported_key_len2) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed while getting key length"); + break; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_key, sizeof(exported_key), &exported_key_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failedi for mac key"); + break; + } + SecKey_Release(keyHandle); + keyHandle = nullptr; + + SecKey_Delete(ctx.proc(), id); + + if (exported_key_len != exported_key_len2) { + SEC_LOG_ERROR("Exported key length mismatch, expected %d, received %d", + exported_key_len2, exported_key_len); + break; + } + + if (SecKey_Provision(ctx.proc(), id, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, exported_key, + exported_key_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed for exported hmac key"); + return SEC_RESULT_FAILURE; + } + if (SecKey_GetInstance(ctx.proc(), id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed for session mac key"); + break; + } + if (SecMac_GetInstance(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA1, keyHandle, &macHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_GetInstance failed for hmac key"); + break; + } + if (SecMac_Update(macHandle, &derivation_input[0], derivation_input.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_Update failed for hmac key"); + break; + } + + SecMac_Release(macHandle, mac_output2, &mac_output_len2); + macHandle = nullptr; + + if (mac_output_len != mac_output_len2) { + SEC_LOG_ERROR("Mac output size mismatch, %d, %d", mac_output_len, mac_output_len2); + break; + } + Sec_PrintHex(mac_output, mac_output_len); + SEC_PRINT("\n"); + Sec_PrintHex(mac_output2, mac_output_len2); + SEC_PRINT("\n"); + if (memcmp(mac_output, mac_output2, mac_output_len2) != 0) { + SEC_LOG_ERROR("Mac output mismatch"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (macHandle != nullptr) + SecMac_Release(macHandle, mac_output, &mac_output_len); + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +/* Only Opaque buffers can be used when SVP is required */ +Sec_Result testKeyCtrlCipherFailsSvpNonOpaque(int version, const char* alg, Sec_CipherAlgorithm cipher_algorithm) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + SEC_BYTE clear_text[SEC_AES_BLOCK_SIZE] = {0x01}; + SEC_BYTE cipher_text[SEC_AES_BLOCK_SIZE]; + SEC_SIZE bytesWritten = 0; + const char* notBeforeTimeStr = "2010-12-09T19:53:06Z"; + const char* notOnOrAfterTimeStr = "2022-12-09T19:53:06Z"; + SEC_BYTE jtypeRights[SEC_KEYOUTPUTRIGHT_NUM]; + std::string b64rights; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + RIGHTS_INIT(jtypeRights); + jtypeRights[0] = SEC_KEYOUTPUTRIGHT_SVP_REQUIRED; + jtypeRights[1] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + jtypeRights[2] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + b64rights = toB64(jtypeRights, SEC_KEYOUTPUTRIGHT_NUM); + + do { + /* key avail in one hour */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", b64rights.c_str(), SEC_TRUE, + 1, notBeforeTimeStr, notOnOrAfterTimeStr, g_default_jtype_data.macKey, version, alg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + break; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + if (SecCipher_GetInstance(ctx.proc(), cipher_algorithm, SEC_CIPHERMODE_ENCRYPT, keyHandle, iv, &cipherHandle) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + break; + } + + if (SecCipher_Process(cipherHandle, clear_text, sizeof(clear_text), SEC_TRUE, cipher_text, sizeof(cipher_text), + &bytesWritten) == SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("expected SecCipher_Process to fail when processing non-opaque buffer with SVP required"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (cipherHandle != nullptr) + SecCipher_Release(cipherHandle); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +/* cipher process succeeds with svp required and opaque buffer */ +Sec_Result testKeyCtrlCipherSvpOpaque(int version, const char* alg, TestKey contentKey, + Sec_CipherAlgorithm cipher_algorithm) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + Sec_OpaqueBufferHandle* clearOpaqueBufferHandle = nullptr; + Sec_OpaqueBufferHandle* cipherOpaqueBufferHandle = nullptr; + SEC_SIZE bytesWritten = 0; + const char* notBeforeTimeStr = "2010-12-09T19:53:06Z"; + const char* notOnOrAfterTimeStr = "2022-12-09T19:53:06Z"; + SEC_BYTE jtypeRights[SEC_KEYOUTPUTRIGHT_NUM]; + std::string b64rights; + SEC_BYTE clear_data[SEC_AES_BLOCK_SIZE] = {0x01}; + + RIGHTS_INIT(jtypeRights); + jtypeRights[0] = SEC_KEYOUTPUTRIGHT_SVP_REQUIRED; + jtypeRights[1] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + jtypeRights[2] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + b64rights = toB64(jtypeRights, SEC_KEYOUTPUTRIGHT_NUM); + + do { + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", b64rights.c_str(), SEC_TRUE, + 1, notBeforeTimeStr, notOnOrAfterTimeStr, g_default_jtype_data.macKey, version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + break; + } + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + /* init opaque buffers */ + if (SecOpaqueBuffer_Malloc(SEC_AES_BLOCK_SIZE, &clearOpaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Malloc failed"); + break; + } + if (SecOpaqueBuffer_Malloc(SEC_AES_BLOCK_SIZE, &cipherOpaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Malloc failed"); + break; + } + if (SecOpaqueBuffer_Write(clearOpaqueBufferHandle, 0, clear_data, SEC_AES_BLOCK_SIZE) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Write failed"); + break; + } + + if (SecCipher_GetInstance(ctx.proc(), cipher_algorithm, SEC_CIPHERMODE_ENCRYPT, keyHandle, iv, &cipherHandle) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + break; + } + + if (SecCipher_ProcessOpaque(cipherHandle, clearOpaqueBufferHandle, cipherOpaqueBufferHandle, SEC_AES_BLOCK_SIZE, + SEC_TRUE, &bytesWritten) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_ProcessOpaque failed"); + break; + } + if (bytesWritten != SEC_AES_BLOCK_SIZE) { + SEC_LOG_ERROR("Expected output size to be 16, received %d", (int) bytesWritten); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (cipherHandle != nullptr) + SecCipher_Release(cipherHandle); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + if (clearOpaqueBufferHandle != nullptr) + SecOpaqueBuffer_Free(clearOpaqueBufferHandle); + + if (cipherOpaqueBufferHandle != nullptr) + SecOpaqueBuffer_Free(cipherOpaqueBufferHandle); + + return result; +} + +Sec_Result testKeyCtrlCipherSvpDataShiftOpaque(int version, const char* alg) { + // Data Shift not supported +#if 0 + Sec_Result result = SEC_RESULT_FAILURE; + SEC_BYTE jtypeRights[SEC_KEYOUTPUTRIGHT_NUM]; + std::string b64rights; + const char *notBeforeTimeStr = "2010-12-09T19:53:06Z"; + const char *notOnOrAfterTimeStr = "2022-12-09T19:53:06Z"; + TestCtx ctx; + Sec_OpaqueBufferHandle *inputHandle1 = nullptr; + Sec_OpaqueBufferHandle *inputHandle2 = nullptr; + Sec_OpaqueBufferHandle *outputHandle = nullptr; + SEC_SIZE written = 0; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle *handle = nullptr; + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + + RIGHTS_INIT(jtypeRights); + jtypeRights[0]= SEC_KEYOUTPUTRIGHT_SVP_REQUIRED; + jtypeRights[1]= SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + jtypeRights[2]= SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + b64rights = toB64(jtypeRights, SEC_KEYOUTPUTRIGHT_NUM); + +do { + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", + "HS256", + g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, + "9c621060-3a17-4813-8dcb-2e9187aaa903", + b64rights.c_str(), SEC_TRUE, 1, + notBeforeTimeStr, + notOnOrAfterTimeStr, + g_default_jtype_data.macKey, + version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + break; + } + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (nullptr == (handle = _provisionJTypeAndSession(ctx, jtype))) + { + break; + } + + if (!= SEC_RESULT_SUCCESS) SecCipher_GetInstance(ctx.proc(), + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, handle, + &iv[0], &cipherHandle)) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + break; + } + + if (SecOpaqueBuffer_Malloc(8, &inputHandle1) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Malloc failed"); + break; + } + + if (SecOpaqueBuffer_Malloc(256-8, &inputHandle2) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Malloc failed"); + break; + } + + if (SecOpaqueBuffer_Malloc(256, &outputHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Malloc failed"); + break; + } + + if (!= SEC_RESULT_SUCCESS) SecCipher_ProcessOpaque(cipherHandle, + inputHandle1, outputHandle, 8, SEC_FALSE, + &written)) { + SEC_LOG_ERROR("SecCipher_ProcessOpaque failed"); + break; + } + + if (SecCipher_ProcessCtrWithOpaqueDataShift(cipherHandle, inputHandle2, outputHandle, 256-8, &written, 8) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_ProcessCtrWithOpaqueDataShift failed"); + break; + } + + result = SEC_RESULT_SUCCESS; + + } while(false); + + + if (cipherHandle) + SecCipher_Release(cipherHandle); + if (handle) + SecKey_Release(handle); + if (outputHandle) + SecOpaqueBuffer_Free(outputHandle); + if (inputHandle1) + SecOpaqueBuffer_Free(inputHandle1); + if (inputHandle2) + SecOpaqueBuffer_Free(inputHandle2); + + return result; +#endif + SEC_LOG_ERROR("SecCipher_ProcessCtrWithOpaqueDataShift not supported"); + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeyCtrlSvpCheckOpaque(int version, const char* alg, TestKey contentKey) { + TestCtx ctx; + Sec_Result result = SEC_RESULT_FAILURE; + SEC_BYTE jtypeRights[SEC_KEYOUTPUTRIGHT_NUM]; + std::string b64rights; + const char* notBeforeTimeStr = "2010-12-09T19:53:06Z"; + const char* notOnOrAfterTimeStr = "2022-12-09T19:53:06Z"; + SEC_SIZE written = 0; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + Sec_KeyHandle* keyHandle2 = nullptr; + std::vector expected = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector input(SEC_AES_BLOCK_SIZE, 0); + SEC_SIZE bytesWritten = 0; + Sec_OpaqueBufferHandle* opaqueBufferHandle = nullptr; + + RIGHTS_INIT(jtypeRights); + jtypeRights[0] = SEC_KEYOUTPUTRIGHT_SVP_REQUIRED; + jtypeRights[1] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + jtypeRights[2] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + b64rights = toB64(jtypeRights, SEC_KEYOUTPUTRIGHT_NUM); + + do { + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", b64rights.c_str(), SEC_TRUE, + 1, notBeforeTimeStr, notOnOrAfterTimeStr, g_default_jtype_data.macKey, version, alg); + + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + break; + } + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + /* provision key setup expected test data */ + keyHandle2 = ctx.provisionKey(SEC_OBJECTID_USER_BASE + 1, SEC_STORAGELOC_RAM, contentKey, TESTKC_RAW, + SEC_FALSE); + if (keyHandle2 == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + break; + } + + if (SecCipher_SingleInput(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, + keyHandle2, nullptr, &expected[0], expected.size(), &input[0], input.size(), &bytesWritten) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + break; + } + + /* cipher handle using jtype key */ + if (SecCipher_GetInstance(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, keyHandle, + nullptr, &cipherHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + TestCtx::printHex(" input", input); + TestCtx::printHex("expected", expected); + + if (SecOpaqueBuffer_Malloc(input.size(), &opaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Malloc failed"); + return SEC_RESULT_FAILURE; + } + + if (SecOpaqueBuffer_Write(opaqueBufferHandle, 0, &input[0], input.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Write failed"); + return SEC_RESULT_FAILURE; + } + + if (SecCipher_KeyCheckOpaque(cipherHandle, opaqueBufferHandle, SEC_AES_BLOCK_SIZE, &expected[0]) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_KeyCheckOpaque failed"); + return SEC_RESULT_FAILURE; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (cipherHandle != nullptr) + SecCipher_Release(cipherHandle); + if (opaqueBufferHandle != nullptr) + SecOpaqueBuffer_Free(opaqueBufferHandle); + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +/* Only Opaque buffers can be used when SVP is required */ +Sec_Result testKeyCtrlProcessCtrDataShiftFailsSvpNonOpaque(int version, const char* alg) { + Sec_Result result = SEC_RESULT_FAILURE; + TestCtx ctx; + Sec_CipherHandle* cipherHandle = nullptr; + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE iv[SEC_AES_BLOCK_SIZE] = {0x01}; + SEC_BYTE clear_text[SEC_AES_BLOCK_SIZE] = {0x01}; + SEC_BYTE cipher_text[SEC_AES_BLOCK_SIZE]; + SEC_SIZE bytesWritten = 0; + const char* notBeforeTimeStr = "2010-12-09T19:53:06Z"; + const char* notOnOrAfterTimeStr = "2022-12-09T19:53:06Z"; + SEC_BYTE jtypeRights[SEC_KEYOUTPUTRIGHT_NUM]; + std::string b64rights; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + RIGHTS_INIT(jtypeRights); + jtypeRights[0] = SEC_KEYOUTPUTRIGHT_SVP_REQUIRED; + jtypeRights[1] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_1_4_ALLOWED; + jtypeRights[2] = SEC_KEYOUTPUTRIGHT_DIGITAL_OPL_HDCP_2_2_ALLOWED; + b64rights = toB64(jtypeRights, SEC_KEYOUTPUTRIGHT_NUM); + + do { + /* key avail in one hour */ + std::string jtype = createJTypeContainer("1WXQ46EYW65SENER", "HS256", g_default_jtype_data.contentKey, + g_default_jtype_data.encryptionKey, "9c621060-3a17-4813-8dcb-2e9187aaa903", b64rights.c_str(), SEC_TRUE, + 1, notBeforeTimeStr, notOnOrAfterTimeStr, g_default_jtype_data.macKey, version, alg); + if (jtype.empty()) { + SEC_LOG_ERROR("CreateJTypeContainer failed"); + break; + } + + if ((keyHandle = provisionJTypeAndSession(ctx, jtype)) == nullptr) { + break; + } + + if (SecCipher_GetInstance(ctx.proc(), SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, keyHandle, iv, + &cipherHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + break; + } + + if (SecCipher_ProcessCtrWithDataShift(cipherHandle, clear_text, sizeof(clear_text), cipher_text, + sizeof(cipher_text), &bytesWritten, 8) == SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Expected SecCipher_ProcessCtrWithDataShift to fail when processing non-opaque buffer with" + " SVP required"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (cipherHandle != nullptr) + SecCipher_Release(cipherHandle); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} + +Sec_Result testKeyCtrlKeyExportSmallBuffer() { + Sec_Result result = SEC_RESULT_FAILURE; + + Sec_KeyHandle* keyHandle = nullptr; + SEC_BYTE exported_key[8]; + SEC_SIZE exported_key_len = 0; + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE + 50; + Sec_ProcessorHandle* processorHandle = nullptr; + Sec_StorageLoc location = SEC_STORAGELOC_RAM; + TestCtx ctx; + + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector aesKey = TestCtx::random(SEC_AES_BLOCK_SIZE); + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id, location, SEC_KEYCONTAINER_RAW_AES_128, &aesKey[0], aesKey.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + do { + if (SecKey_GetInstance(ctx.proc(), id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + break; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], exported_key, sizeof(exported_key), &exported_key_len) == + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Expected SecKey_ExportKey to fail with under-sized output buffer"); + break; + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + if (keyHandle != nullptr) + SecKey_Release(keyHandle); + + return result; +} diff --git a/test/main/cpp/keyctrl.h b/test/main/cpp/keyctrl.h new file mode 100644 index 0000000..9322211 --- /dev/null +++ b/test/main/cpp/keyctrl.h @@ -0,0 +1,106 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef KEYCTRL_H +#define KEYCTRL_H + +#include "sec_security.h" +#include "test_creds.h" +#include + +Sec_Result testKeyCtrlDefaultProperties(int version, const char *alg); + +Sec_Result testKeyCtrlFalseDefaultProperties(int version, const char *alg); + +/* test expected platform default rights */ +Sec_Result testKeyCtrlRightsFromPlatformDefault(int version, const char *alg); + +/* gets output rights from either default (hard-coded) values or devicesettings + * depending on compile directive -DSEC_KEYCTRL_ENABLE_DEVICE_SETTINGS + */ +Sec_Result testKeyCtrlGetOutputRights(int version, const char *alg); + +/* Sec_GetCipherInstance fails with request right that is not allowed on device */ +Sec_Result testKeyCtrlUnSupportedOutputRight(int version, const char *alg); + +/* En/Decrypt successful with key requesting a right that is allowed on the device */ +Sec_Result testKeyCtrlDecryptSupportedOutputRight(int version, const char *alg); + +/* SecKey_Export fails if cacheable flag == 0 */ +Sec_Result testKeyCtrlExportUnCachable(int version, const char *alg); + +/* general rights combinations */ +Sec_Result testKeyCtrlAllowedRights(int version, const char *alg); + +/* SecCipher_GetInstance fails for key with usage for 'key' only */ +Sec_Result testKeyCtrlKeyOnlyUsage(int version, const char *alg); + +/* SecCipher_Getinstance should fail with notOnOrAfter date < now */ +Sec_Result testKeyCtrlKeyExpired(int version, const char *alg); + +/* SecCipher_GetInstance should fail with notBefore date in the future */ +Sec_Result testKeyCtrlKeyNotYetAvail(int version, const char *alg); + +/* test provision fails for date > 2038/01/19 date on 32bit machines. */ +Sec_Result testKeyCtrlProvision32bit2038(int version, const char *alg); + +/* key properties vaidation */ +Sec_Result testKeyCtrlValidatePropertiesBadNotBefore(int version, const char *alg); + +Sec_Result testKeyCtrlValidatePropertiesBadNotOnOrAfter(int version, const char *alg); + +Sec_Result testKeyCtrlValidatePropertiesDefaults(int version, const char *alg); + +Sec_Result testKeyCtrlUtilsTime(int version, const char *alg); + +Sec_Result testKeyCtrlUnwrapWithKeyUsage(int version, const char *alg, TestKey key); + +Sec_Result testKeyCtrlUnwrapWithDataUsage(int version, const char *alg); + +Sec_Result testKeyCtrlBadB64Jtype(int version, const char *alg); + +Sec_Result testKeyCtrlExportDerived(); + +Sec_Result testKeyCtrlExpectedJTypeProperties(int version, const char *alg, TestKey key); + +Sec_Result testKeyCtrlExpectedExportedProperties(int version, const char *alg, TestKey key); + +Sec_Result testKeyCtrlExportProvisionExport(int version, const char *alg, TestKey contentKey); + +Sec_Result testKeyCtrlKeyExportGetSize(int version, const char *alg); + +Sec_Result testKeyCtrlExportAes(TestKey aesKey, Sec_StorageLoc location); + +Sec_Result testKeyCtrlKeyExportHmac(TestKey macKey, Sec_StorageLoc location); + +Sec_Result testKeyCtrlCipherFailsSvpNonOpaque(int version, const char *alg, Sec_CipherAlgorithm cipher_algorithm); + +Sec_Result testKeyCtrlCipherSvpOpaque(int version, const char *alg, TestKey contentKey, + Sec_CipherAlgorithm cipher_algorithm); + +Sec_Result testKeyCtrlCipherSvpDataShiftOpaque(int version, const char *alg); + +Sec_Result testKeyCtrlSvpCheckOpaque(int version, const char *alg, TestKey contentKey); + +Sec_Result testKeyCtrlProcessCtrDataShiftFailsSvpNonOpaque(int version, const char *alg); + +Sec_Result testKeyCtrlExportEcc(TestKc kc); + +Sec_Result testKeyCtrlKeyExportSmallBuffer(); + +#endif // KEYCTRL_H diff --git a/test/main/cpp/mac.cpp b/test/main/cpp/mac.cpp new file mode 100644 index 0000000..e1058fd --- /dev/null +++ b/test/main/cpp/mac.cpp @@ -0,0 +1,306 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mac.h" +#include "test_ctx.h" +#include +#include + +std::vector macOpenSSL(Sec_MacAlgorithm alg, const std::vector& openssl_key, + const std::vector& input) { + std::vector mac; + SEC_SIZE mac_len; + CMAC_CTX* cmac_ctx; + + switch (alg) { + case SEC_MACALGORITHM_HMAC_SHA1: + mac.resize(20); + HMAC(EVP_sha1(), &openssl_key[0], static_cast(openssl_key.size()), &input[0], input.size(), &mac[0], + &mac_len); + return mac; + + case SEC_MACALGORITHM_HMAC_SHA256: + mac.resize(32); + HMAC(EVP_sha256(), &openssl_key[0], static_cast(openssl_key.size()), &input[0], input.size(), &mac[0], + &mac_len); + return mac; + + case SEC_MACALGORITHM_CMAC_AES_128: { + mac.resize(SEC_AES_BLOCK_SIZE); + cmac_ctx = CMAC_CTX_new(); + if (CMAC_Init(cmac_ctx, &openssl_key[0], openssl_key.size(), + openssl_key.size() == SEC_AES_BLOCK_SIZE ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), nullptr) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("Comcast_CMAC_Init failed"); + return {}; + } + CMAC_Update(cmac_ctx, &input[0], input.size()); + size_t outl; + CMAC_Final(cmac_ctx, &mac[0], &outl); + mac_len = outl; + CMAC_CTX_free(cmac_ctx); + return mac; + } + default: + break; + } + + SEC_LOG_ERROR("Unimplemented"); + return {}; +} + +std::vector macOpenSSL(Sec_MacAlgorithm alg, TestKey key, const std::vector& input) { + std::vector mac; + SEC_SIZE mac_len; + CMAC_CTX* cmac_ctx; + + std::vector openssl_key = TestCreds::asOpenSslAes(key); + if (openssl_key.empty()) { + SEC_LOG_ERROR("TestCreds::asOpenSslAes failed"); + return {}; + } + + switch (alg) { + case SEC_MACALGORITHM_HMAC_SHA1: + mac.resize(20); + HMAC(EVP_sha1(), &openssl_key[0], static_cast(openssl_key.size()), &input[0], input.size(), &mac[0], + &mac_len); + return mac; + + case SEC_MACALGORITHM_HMAC_SHA256: + mac.resize(32); + HMAC(EVP_sha256(), &openssl_key[0], static_cast(openssl_key.size()), &input[0], input.size(), &mac[0], + &mac_len); + return mac; + + case SEC_MACALGORITHM_CMAC_AES_128: { + mac.resize(SEC_AES_BLOCK_SIZE); + cmac_ctx = CMAC_CTX_new(); + if (CMAC_Init(cmac_ctx, &openssl_key[0], openssl_key.size(), + openssl_key.size() == SEC_AES_BLOCK_SIZE ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), nullptr) != + OPENSSL_SUCCESS) { + SEC_LOG_ERROR("Comcast_CMAC_Init failed"); + return {}; + } + CMAC_Update(cmac_ctx, &input[0], input.size()); + size_t outl; + CMAC_Final(cmac_ctx, &mac[0], &outl); + mac_len = outl; + CMAC_CTX_free(cmac_ctx); + return mac; + } + default: + break; + } + + SEC_LOG_ERROR("Unimplemented"); + return {}; +} + +std::vector macSecApi(TestCtx* ctx, Sec_MacAlgorithm alg, Sec_KeyHandle* keyHandle, + const std::vector& input, const std::vector& inputSizes) { + + std::vector output; + output.resize(SEC_MAC_MAX_LEN); + + SEC_SIZE inputProcessed = 0; + SEC_SIZE written = 0; + + Sec_MacHandle* macHandle = ctx->acquireMac(alg, keyHandle); + if (macHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireMac failed"); + return {}; + } + + for (unsigned int inputSize : inputSizes) { + if (inputSize > 0) { + if (SecMac_Update(macHandle, const_cast(&input[inputProcessed]), inputSize) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_Update failed"); + return {}; + } + } + + inputProcessed += inputSize; + } + + if (ctx->releaseMac(macHandle, &output[0], &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + output.resize(written); + + return output; +} + +std::vector macSecApi(TestCtx* ctx, Sec_MacAlgorithm alg, Sec_KeyHandle* keyHandle, + Sec_KeyHandle* paylodKeyHandle) { + + std::vector output; + output.resize(SEC_MAC_MAX_LEN); + + SEC_SIZE written = 0; + + Sec_MacHandle* macHandle = ctx->acquireMac(alg, keyHandle); + if (macHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireMac failed"); + return {}; + } + + if (SecMac_UpdateWithKey(macHandle, paylodKeyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_Update failed"); + return {}; + } + + if (ctx->releaseMac(macHandle, &output[0], &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_Process failed"); + return {}; + } + + output.resize(written); + + return output; +} + +Sec_Result testMacOverKey(Sec_MacAlgorithm alg, SEC_OBJECTID id_mac, TestKey keyMac, + TestKc kc, SEC_OBJECTID id_payload, TestKey keyPayload, + Sec_StorageLoc loc) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandleMac; + if ((keyHandleMac = ctx.provisionKey(id_mac, loc, keyMac, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandlePayload; + if ((TestCreds::supports(CAPABILITY_HMAC_OVER_HWKEY) && alg != SEC_MACALGORITHM_CMAC_AES_128) || + (TestCreds::supports(CAPABILITY_CMAC_OVER_HWKEY) && alg == SEC_MACALGORITHM_CMAC_AES_128)) { + if ((keyHandlePayload = ctx.provisionKey(id_payload, loc, keyPayload, TESTKC_RAW)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + } else { + if ((keyHandlePayload = ctx.provisionKey(id_payload, loc, keyPayload, TESTKC_RAW, SEC_TRUE)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + } + + //gen clear input + std::vector clear = TestCreds::asOpenSslAes(keyPayload); + TestCtx::printHex("key", clear); + + //mac + std::vector macSA = macSecApi(&ctx, alg, keyHandleMac, keyHandlePayload); + TestCtx::printHex("macSecApi", macSA); + + std::vector macOS = macOpenSSL(alg, keyMac, clear); + TestCtx::printHex("macOpenssl", macOS); + + //check if results match + if (macSA != macOS || macSA.empty()) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testMacSingle(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_MacAlgorithm alg, + SEC_SIZE inputSize) { + std::vector inputSizes; + inputSizes.resize(1); + inputSizes[0] = inputSize; + + return testMacMult(id, key, kc, loc, alg, inputSizes); +} + +Sec_Result testMacMult(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_MacAlgorithm alg, + const std::vector& inputSizes) { + + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //gen clear input + std::vector clear = TestCtx::random(TestCtx::coalesceInputSizes(inputSizes)); + TestCtx::printHex("clear", clear); + + //mac + std::vector macSA = macSecApi(&ctx, alg, keyHandle, clear, inputSizes); + TestCtx::printHex("macSecApi", macSA); + + std::vector macOS = macOpenSSL(alg, key, clear); + TestCtx::printHex("macOpenssl", macOS); + + //check if results match + if (macSA != macOS) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result macCheck(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm alg, SEC_OBJECTID id, SEC_BYTE* key, + SEC_SIZE key_len) { + std::vector mac_secapi; + mac_secapi.resize(SEC_MAC_MAX_LEN); + SEC_SIZE mac_len; + + std::vector clear = TestCtx::random(256); + TestCtx::printHex("clear", clear); + + if (SecMac_SingleInputId(processorHandle, alg, id, &clear[0], clear.size(), &mac_secapi[0], &mac_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_SingleInputId failed"); + return SEC_RESULT_FAILURE; + } + + mac_secapi.resize(mac_len); + TestCtx::printHex("macSecApi", mac_secapi); + + std::vector openssl_key = std::vector(key, key + key_len); + + std::vector macOS = macOpenSSL(alg, openssl_key, clear); + TestCtx::printHex("macOpenssl", macOS); + + //check if results match + if (mac_secapi != macOS) { + SEC_LOG_ERROR("Results do not match"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/mac.h b/test/main/cpp/mac.h new file mode 100644 index 0000000..aee9c90 --- /dev/null +++ b/test/main/cpp/mac.h @@ -0,0 +1,40 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef MAC_H +#define MAC_H + +#include "sec_security.h" +#include "test_creds.h" +#include + +Sec_Result testMacOverKey(Sec_MacAlgorithm alg, SEC_OBJECTID id_mac, TestKey keyMac, TestKc kc, SEC_OBJECTID id_payload, + TestKey keyPayload, Sec_StorageLoc loc); + +Sec_Result testMacSingle(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_MacAlgorithm alg, + SEC_SIZE inputSize); + +Sec_Result testMacMult(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, Sec_MacAlgorithm alg, + const std::vector& inputSizes); + +std::vector macOpenSSL(Sec_MacAlgorithm alg, TestKey key, const std::vector& input); + +Sec_Result macCheck(Sec_ProcessorHandle* processorHandle, Sec_MacAlgorithm alg, SEC_OBJECTID id, SEC_BYTE* key, + SEC_SIZE key_len); + +#endif // MAC_H diff --git a/test/main/cpp/processor.cpp b/test/main/cpp/processor.cpp new file mode 100644 index 0000000..cf2531a --- /dev/null +++ b/test/main/cpp/processor.cpp @@ -0,0 +1,114 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "processor.h" +#include "test_ctx.h" + +Sec_Result testProcessorPrintInfo() { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (SecProcessor_PrintInfo(ctx.proc()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecProcessor_PrintInfo failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testProcessorGetInfo() { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_ProcessorInfo info; + + if (SecProcessor_GetInfo(ctx.proc(), &info) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecProcessor_GetInfo failed"); + return SEC_RESULT_FAILURE; + } + + SEC_PRINT("version: %s\n", info.version); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testProcessorGetDeviceId() { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + std::vector deviceId(SEC_DEVICEID_LEN); + std::vector zeros(SEC_DEVICEID_LEN); + + if (SecProcessor_GetDeviceId(ctx.proc(), &deviceId[0]) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecProcessor_GetDeviceId failed"); + return SEC_RESULT_FAILURE; + } + + TestCtx::printHex("deviceid", deviceId); + + if (deviceId == zeros) { + SEC_LOG_ERROR("DeviceId is all zeros"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testProcessorGetKeyLadderMinMaxDepth(Sec_KeyLadderRoot root) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_SIZE depthMin = SecProcessor_GetKeyLadderMinDepth(ctx.proc(), root); + SEC_SIZE depthMax = SecProcessor_GetKeyLadderMaxDepth(ctx.proc(), root); + + SEC_PRINT("min:%d\nmax:%d\n", depthMin, depthMax); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testProcessorNativeMallocFree() { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + void* mem = Sec_NativeMalloc(ctx.proc(), 256); + memset(mem, 0, 256); + + if (mem == nullptr) { + SEC_LOG_ERROR("Sec_NativeMalloc failed"); + return SEC_RESULT_FAILURE; + } + + Sec_NativeFree(ctx.proc(), mem); + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/processor.h b/test/main/cpp/processor.h new file mode 100644 index 0000000..dbfaa88 --- /dev/null +++ b/test/main/cpp/processor.h @@ -0,0 +1,34 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef PROCESSOR_H +#define PROCESSOR_H + +#include "sec_security.h" + +Sec_Result testProcessorPrintInfo(); + +Sec_Result testProcessorGetDeviceId(); + +Sec_Result testProcessorGetKeyLadderMinMaxDepth(Sec_KeyLadderRoot root); + +Sec_Result testProcessorNativeMallocFree(); + +Sec_Result testProcessorGetInfo(); + +#endif // PROCESSOR_H diff --git a/test/main/cpp/random.cpp b/test/main/cpp/random.cpp new file mode 100644 index 0000000..ee26755 --- /dev/null +++ b/test/main/cpp/random.cpp @@ -0,0 +1,47 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "random.h" +#include "test_ctx.h" + +Sec_Result testRandom(Sec_RandomAlgorithm alg, SEC_SIZE size) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_RandomHandle* randomHandle; + if ((randomHandle = ctx.acquireRandom(alg)) == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireRandom failed"); + return SEC_RESULT_FAILURE; + } + + std::vector out; + out.resize(size); + + if (SecRandom_Process(randomHandle, &out[0], out.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecRandom_Process failed"); + return SEC_RESULT_FAILURE; + } + + TestCtx::printHex("out", out); + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/random.h b/test/main/cpp/random.h new file mode 100644 index 0000000..b13f5c5 --- /dev/null +++ b/test/main/cpp/random.h @@ -0,0 +1,26 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef RANDOM_H +#define RANDOM_H + +#include "sec_security.h" + +Sec_Result testRandom(Sec_RandomAlgorithm alg, SEC_SIZE size); + +#endif // RANDOM_H diff --git a/test/main/cpp/sec_api_utest_main.cpp b/test/main/cpp/sec_api_utest_main.cpp new file mode 100644 index 0000000..bc9f67b --- /dev/null +++ b/test/main/cpp/sec_api_utest_main.cpp @@ -0,0 +1,1365 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_api_utest_main.h" // NOLINT +#include "bundle.h" +#include "cert.h" +#include "cipher.h" +#include "concurrent.h" +#include "digest.h" +#include "exchange.h" +#include "jtype.h" +#include "key.h" +#include "keyctrl.h" +#include "mac.h" +#include "processor.h" +#include "random.h" +#include "sec_security.h" +#include "sign.h" +#include "svp.h" +#include "test_creds.h" +#include "test_ctx.h" +#include "wrapped.h" +#include +#include + +#ifdef SEC_PLATFORM_OPENSSL +#include "sec_adapter_openssl.h" +#endif + +void runProcessorTests(SuiteCtx* suite) { + RUN_TEST(suite, testProcessorPrintInfo()) + RUN_TEST(suite, testProcessorGetInfo()) + RUN_TEST(suite, testProcessorGetDeviceId()) + RUN_TEST(suite, testProcessorGetKeyLadderMinMaxDepth(SEC_KEYLADDERROOT_UNIQUE)) + RUN_TEST(suite, testProcessorGetKeyLadderMinMaxDepth(SEC_KEYLADDERROOT_SHARED)) + RUN_TEST(suite, testProcessorNativeMallocFree()) +} + +void runBundleTests(SuiteCtx* suite) { + RUN_TEST(suite, testBundleProvision(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, 256)) + RUN_TEST(suite, testBundleProvision(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_FILE, 256)) + RUN_TEST(suite, testBundleProvisionNoAppDir(SEC_OBJECTID_USER_BASE, 256)) + RUN_TEST(suite, testBundleProvisionNoSha(SEC_OBJECTID_USER_BASE)) +} + +#define CERT_TESTS_LOC(suite, cert, loc) \ + do { \ + RUN_TEST(suite, testCertProvision(SEC_OBJECTID_USER_BASE, cert, loc)); \ + RUN_TEST(suite, testCertExport(SEC_OBJECTID_USER_BASE, cert, loc)); \ + RUN_TEST(suite, testCertExportNoSha(SEC_OBJECTID_USER_BASE, cert)); \ + } while (0) + +#define CERT_TESTS(suite, cert, pub_key) \ + do { \ + CERT_TESTS_LOC(suite, cert, SEC_STORAGELOC_RAM); \ + CERT_TESTS_LOC(suite, cert, SEC_STORAGELOC_FILE); \ + RUN_TEST(suite, testCertVerify(SEC_OBJECTID_USER_BASE, cert, SEC_OBJECTID_USER_BASE + 1, pub_key, \ + SEC_STORAGELOC_RAM)); \ + RUN_TEST(suite, testCertVerify(SEC_OBJECTID_USER_BASE, cert, SEC_OBJECTID_USER_BASE + 1, pub_key, \ + SEC_STORAGELOC_RAM_SOFT_WRAPPED)); \ + } while (0) + +void runCertTests(SuiteCtx* suite) { // NOLINT + if (TestCreds::supports(CAPABILITY_RSA_1024)) { + CERT_TESTS(suite, TESTCERT_RSA1024, TESTKEY_RSA1024_SGN_PUB); + } + CERT_TESTS(suite, TESTCERT_RSA2048, TESTKEY_RSA2048_SGN_PUB); + CERT_TESTS(suite, TESTCERT_EC, TESTKEY_EC_PUB); + RUN_TEST(suite, testCertSignWithPkcs7(SEC_OBJECTID_USER_BASE, TESTCERT_RSA2048, SEC_OBJECTID_USER_BASE + 1, \ + TESTKEY_RSA2048_SGN_PRIV, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) +} + +#define KEY_EXPORT_TESTS(suite, contentKey, encryptionKey, encKc, macKey, version, alg) \ + do { \ + RUN_TEST(suite, testExportKey(contentKey, encryptionKey, encKc, macKey, TESTKC_RAW, SEC_CIPHERALGORITHM_AES_CTR, \ + 20, version, alg)); \ + RUN_TEST(suite, testExportKey(contentKey, encryptionKey, encKc, macKey, TESTKC_RAW, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 32, version, alg)); \ + RUN_TEST(suite, testExportKey(contentKey, encryptionKey, encKc, macKey, TESTKC_RAW, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, 20, version, alg)); \ + RUN_TEST(suite, testExportKey(contentKey, encryptionKey, encKc, macKey, TESTKC_RAW, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 32, version, alg)); \ + RUN_TEST(suite, testExportKey(contentKey, encryptionKey, encKc, macKey, TESTKC_RAW, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, 20, version, alg)); \ + } while (0) + +#define JTYPE_DECRYPT_TESTS(suite, contentKey, encryptionKey, encKc, macKey, version, alg) \ + do { \ + RUN_TEST(suite, testDecryptJType(contentKey, encryptionKey, encKc, macKey, TESTKC_RAW, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 256, version, alg)); \ + RUN_TEST(suite, testDecryptJType(contentKey, encryptionKey, encKc, macKey, TESTKC_RAW, \ + SEC_CIPHERALGORITHM_AES_CTR, 256, version, alg)); \ + RUN_TEST(suite, testDecryptJType(contentKey, encryptionKey, encKc, macKey, TESTKC_RAW, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256, version, alg)); \ + } while (0) + +#define JTYPE_TESTS(suite, contentKey, encryptionKey, macKey, version) \ + do { \ + if ((version) == 1) { \ + if (TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) { \ + RUN_TEST(suite, testProvisionJType(contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, TESTKC_RAW, 1, \ + "aesEcbNone")); \ + KEY_EXPORT_TESTS(suite, contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, 1, "aesEcbNone"); \ + JTYPE_DECRYPT_TESTS(suite, contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, 1, "aesEcbNone"); \ + } \ + if (TestCreds::supports(CAPABILITY_CLEAR_JTYPE_WRAPPING)) { \ + RUN_TEST(suite, testProvisionJType(contentKey, encryptionKey, TESTKC_RAW, macKey, TESTKC_RAW, 1, \ + "aesEcbNone")); \ + KEY_EXPORT_TESTS(suite, contentKey, encryptionKey, TESTKC_RAW, macKey, 1, "aesEcbNone"); \ + JTYPE_DECRYPT_TESTS(suite, contentKey, encryptionKey, TESTKC_RAW, macKey, 1, "aesEcbNone"); \ + } \ + } else if ((version) == 2) { \ + if (TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) { \ + RUN_TEST(suite, testProvisionJType(contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, TESTKC_RAW, 2, \ + "aesEcbNone")); \ + RUN_TEST(suite, testProvisionJType(contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, TESTKC_RAW, 2, \ + "aesEcbPkcs5")); \ + KEY_EXPORT_TESTS(suite, contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, 2, "aesEcbNone"); \ + KEY_EXPORT_TESTS(suite, contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, 2, "aesEcbPkcs5"); \ + JTYPE_DECRYPT_TESTS(suite, contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, 2, "aesEcbNone"); \ + JTYPE_DECRYPT_TESTS(suite, contentKey, encryptionKey, TESTKC_CONDITIONAL, macKey, 2, "aesEcbPkcs5"); \ + } \ + if (TestCreds::supports(CAPABILITY_CLEAR_JTYPE_WRAPPING)) { \ + RUN_TEST(suite, testProvisionJType(contentKey, encryptionKey, TESTKC_RAW, macKey, TESTKC_RAW, 2, \ + "aesEcbNone")); \ + RUN_TEST(suite, testProvisionJType(contentKey, encryptionKey, TESTKC_RAW, macKey, TESTKC_RAW, 2, \ + "aesEcbPkcs5")); \ + KEY_EXPORT_TESTS(suite, contentKey, encryptionKey, TESTKC_RAW, macKey, 2, "aesEcbNone"); \ + KEY_EXPORT_TESTS(suite, contentKey, encryptionKey, TESTKC_RAW, macKey, 2, "aesEcbPkcs5"); \ + JTYPE_DECRYPT_TESTS(suite, contentKey, encryptionKey, TESTKC_RAW, macKey, 2, "aesEcbNone"); \ + JTYPE_DECRYPT_TESTS(suite, contentKey, encryptionKey, TESTKC_RAW, macKey, 2, "aesEcbPkcs5"); \ + } \ + } \ + } while (0) + +void runProvisionedKeyExportTest(SuiteCtx* suite) { + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_AES128, TESTKC_RAW)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_AES256, TESTKC_RAW)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_HMAC128, TESTKC_RAW)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_HMAC160, TESTKC_RAW)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_HMAC256, TESTKC_RAW)) + + if (TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) { + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_AES128, TESTKC_CONDITIONAL)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_AES256, TESTKC_CONDITIONAL)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_HMAC128, TESTKC_CONDITIONAL)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_HMAC160, TESTKC_CONDITIONAL)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_HMAC256, TESTKC_CONDITIONAL)) + + if (TestCreds::supports(CAPABILITY_EXPORT_RSA) && TestCreds::supports(CAPABILITY_RSA_1024)) { + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_RSA1024_SGN_PRIV, TESTKC_CONDITIONAL)) + } + if (TestCreds::supports(CAPABILITY_EXPORT_RSA)) { + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_RSA2048_SGN_PRIV, TESTKC_CONDITIONAL)) + } + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_EC_PRIV, TESTKC_CONDITIONAL)) + } + + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_AES128, TESTKC_GENERATED)) + RUN_TEST(suite, testExportProvisionedKey(TESTKEY_AES256, TESTKC_GENERATED)) +} + +void runKeyTests(SuiteCtx* suite) { // NOLINT + RUN_TEST(suite, testStore(SEC_TRUE, SEC_TRUE)) + RUN_TEST(suite, testStore(SEC_TRUE, SEC_FALSE)) + RUN_TEST(suite, testStore(SEC_FALSE, SEC_TRUE)) + RUN_TEST(suite, testStore(SEC_FALSE, SEC_FALSE)) + RUN_TEST(suite, testStoreProvision(SEC_OBJECTID_USER_BASE, SEC_TRUE, SEC_TRUE)) + RUN_TEST(suite, testStoreProvision(SEC_OBJECTID_USER_BASE, SEC_TRUE, SEC_FALSE)) + RUN_TEST(suite, testStoreProvision(SEC_OBJECTID_USER_BASE, SEC_FALSE, SEC_TRUE)) + RUN_TEST(suite, testStoreProvision(SEC_OBJECTID_USER_BASE, SEC_FALSE, SEC_FALSE)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_FILE)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, + SEC_STORAGELOC_FILE_SOFT_WRAPPED)) + + RUN_TEST(suite, testKeyProvisionDouble(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED, TESTKEY_AES128, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, SEC_STORAGELOC_RAM)) + + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + + JTYPE_TESTS(suite, TESTKEY_AES128, TESTKEY_AES128, TESTKEY_HMAC160, 1); + JTYPE_TESTS(suite, TESTKEY_AES128, TESTKEY_AES128, TESTKEY_HMAC160, 2); + JTYPE_TESTS(suite, TESTKEY_AES256, TESTKEY_AES128, TESTKEY_HMAC160, 2); + + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, SEC_STORAGELOC_RAM)) + + RUN_TEST(suite, + testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, + testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, + testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, + testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + + RUN_TEST(suite, testKeyNoSha(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW)) + RUN_TEST(suite, testKeyGenerate(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE)) + RUN_TEST(suite, testKeyGenerate(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_FALSE)) + RUN_TEST(suite, testKeyGenerate(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_HMAC_160, SEC_STORAGELOC_RAM, SEC_FALSE)) + RUN_TEST(suite, testKeyGenerate(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_HMAC_256, SEC_STORAGELOC_RAM, SEC_FALSE)) + RUN_TEST(suite, testKeyGenerate(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_ECC_NISTP256, SEC_STORAGELOC_RAM, SEC_FALSE)) + + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_GENERATED, SEC_STORAGELOC_RAM)) + + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_MACALGORITHM_HMAC_SHA1, SEC_TRUE, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_MACALGORITHM_HMAC_SHA1, SEC_TRUE, SEC_FALSE)) + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_MACALGORITHM_HMAC_SHA256, SEC_TRUE, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_MACALGORITHM_HMAC_SHA256, SEC_TRUE, SEC_FALSE)) + if (TestCreds::supports(CAPABILITY_HKDF_CMAC)) { + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_MACALGORITHM_CMAC_AES_128, SEC_TRUE, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_MACALGORITHM_CMAC_AES_128, SEC_TRUE, SEC_FALSE)) + } + RUN_TEST(suite, testKeyDeriveConcatKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_DIGESTALGORITHM_SHA1, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveConcatKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_DIGESTALGORITHM_SHA256, SEC_TRUE)) + + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_MACALGORITHM_HMAC_SHA1, SEC_TRUE, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_MACALGORITHM_HMAC_SHA1, SEC_TRUE, SEC_FALSE)) + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_MACALGORITHM_HMAC_SHA256, SEC_TRUE, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_MACALGORITHM_HMAC_SHA256, SEC_TRUE, SEC_FALSE)) + if (TestCreds::supports(CAPABILITY_HKDF_CMAC)) { + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_MACALGORITHM_CMAC_AES_128, SEC_TRUE, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveHKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_MACALGORITHM_CMAC_AES_128, SEC_TRUE, SEC_FALSE)) + } + RUN_TEST(suite, testKeyDeriveConcatKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_DIGESTALGORITHM_SHA1, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveConcatKDF(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_DIGESTALGORITHM_SHA256, SEC_TRUE)) + + RUN_TEST(suite, testKeyDeriveVendorAes128(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_MACALGORITHM_HMAC_SHA1, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveVendorAes128(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_MACALGORITHM_HMAC_SHA256, SEC_TRUE)) + RUN_TEST(suite, testKeyDeriveKeyLadderAes128(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_KEYLADDERROOT_UNIQUE, SEC_TRUE)) + + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE, 1, 256)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE, 2, 256)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE, 3, 512)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE, 4, 512)) + + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_GENERATED, + SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE, 1, 256)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_GENERATED, + SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE, 2, 256)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_GENERATED, + SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE, 3, 512)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_GENERATED, + SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_TRUE, 4, 512)) + + if (TestCreds::supports(CAPABILITY_AES256)) { + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM, SEC_TRUE, 1, 256)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM, SEC_TRUE, 2, 512)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM, SEC_TRUE, 3, 512)) + } + + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_FALSE, 1, 256)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_FALSE, 2, 256)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_FALSE, 3, 512)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_FALSE, 4, 512)) + + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_HMAC_256, SEC_STORAGELOC_RAM, SEC_FALSE, 1, 512)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_HMAC_256, SEC_STORAGELOC_RAM, SEC_FALSE, 2, 512)) + RUN_TEST(suite, testKeyDeriveCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKC_CONDITIONAL, + SEC_KEYTYPE_HMAC_256, SEC_STORAGELOC_RAM, SEC_FALSE, 3, 512)) + + RUN_TEST(suite, testKeyDeriveBaseKey(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM)) + + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA1)) + if (TestCreds::supports(CAPABILITY_AES256)) { + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA1)) + } + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA1)) + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_HMAC_160, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA1)) + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_HMAC_256, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA1)) + + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA256)) + if (TestCreds::supports(CAPABILITY_AES256)) { + RUN_TEST(suite, + testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA256)) + } + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA256)) + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_HMAC_160, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA256)) + RUN_TEST(suite, testKeyDeriveHKDFBaseKey(SEC_KEYTYPE_HMAC_256, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA256)) + + RUN_TEST(suite, testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA1)) + if (TestCreds::supports(CAPABILITY_AES256)) { + RUN_TEST(suite, + testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA1)) + } + RUN_TEST(suite, testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA1)) + RUN_TEST(suite, testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_HMAC_160, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA1)) + RUN_TEST(suite, testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_HMAC_256, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA1)) + + RUN_TEST(suite, testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA256)) + if (TestCreds::supports(CAPABILITY_AES256)) { + RUN_TEST(suite, + testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA256)) + } + RUN_TEST(suite, + testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_HMAC_128, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA256)) + RUN_TEST(suite, + testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_HMAC_160, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA256)) + RUN_TEST(suite, + testKeyDeriveConcatKDFBaseKey(SEC_KEYTYPE_HMAC_256, SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA256)) + + if (TestCreds::supports(CAPABILITY_AES256)) { + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyGenerate(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM, SEC_TRUE)) + + RUN_TEST(suite, + testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyGenerate(SEC_OBJECTID_USER_BASE, SEC_KEYTYPE_AES_256, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_TRUE)) + } + + if (TestCreds::supports(CAPABILITY_RSA_1024)) { + RUN_TEST(suite, + testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, + testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyExtractPublicKey(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PUB, TESTKC_RAW, + SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PUB, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PUB, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyExtractPublicKey(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PUB, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, + testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PRIV, TESTKC_CONDITIONAL, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PRIV, TESTKC_CONDITIONAL, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, + testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_RSA1024_SGN_PRIV, TESTKC_CONDITIONAL, SEC_STORAGELOC_RAM)) + } + + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, + testKeyExtractPublicKey(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PUB, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PUB, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyExtractPublicKey(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PUB, TESTKC_RAW, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PRIV, TESTKC_CONDITIONAL, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PRIV, TESTKC_CONDITIONAL, + SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, + testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_RSA2048_SGN_PRIV, TESTKC_CONDITIONAL, SEC_STORAGELOC_RAM)) + + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, + testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyExtractPublicKey(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PUB, TESTKC_RAW, SEC_STORAGELOC_RAM)) + + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PRIV, TESTKC_CONDITIONAL, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PRIV, TESTKC_CONDITIONAL, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyExtractPublicKey(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PRIV, TESTKC_CONDITIONAL, SEC_STORAGELOC_RAM)) + + RUN_TEST(suite, testKeyProvision(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PRIV, TESTKC_GENERATED, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyGetKeyInfo(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PRIV, TESTKC_GENERATED, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, + testKeyExtractPublicKey(SEC_OBJECTID_USER_BASE, TESTKEY_EC_PRIV, TESTKC_GENERATED, SEC_STORAGELOC_RAM)) + + RUN_TEST(suite, testKeyComputeBaseKeyDigest(SEC_OBJECTID_USER_BASE, SEC_DIGESTALGORITHM_SHA1)) + RUN_TEST(suite, testKeyComputeBaseKeyDigest(SEC_OBJECTID_USER_BASE, SEC_DIGESTALGORITHM_SHA256)) + + RUN_TEST(suite, testKeyECDHKeyAgreementWithKDF(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKEY_EC_PRIV, + TESTKC_CONDITIONAL, TESTKEY_EC_PUB, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_DIGESTALGORITHM_SHA1, SEC_TRUE)) + RUN_TEST(suite, testKeyECDHKeyAgreementWithKDF(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKEY_EC_PRIV, + TESTKC_CONDITIONAL, TESTKEY_EC_PUB, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, + SEC_DIGESTALGORITHM_SHA256, SEC_TRUE)) + + RUN_TEST(suite, testKeyECDHKeyAgreementWithKDF(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKEY_EC_PRIV, + TESTKC_GENERATED, TESTKEY_EC_PUB, SEC_KEYTYPE_AES_128, + SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA1, SEC_TRUE)) + RUN_TEST(suite, testKeyECDHKeyAgreementWithKDF(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, TESTKEY_EC_PRIV, + TESTKC_GENERATED, TESTKEY_EC_PUB, SEC_KEYTYPE_AES_128, + SEC_STORAGELOC_RAM, SEC_DIGESTALGORITHM_SHA256, SEC_TRUE)) + + runProvisionedKeyExportTest(suite); +} + +void runKeyCtrlTests(SuiteCtx* suite) { // NOLINT + RUN_TEST(suite, testKeyCtrlExportUnCachable(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlKeyOnlyUsage(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlKeyExpired(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlKeyNotYetAvail(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlProvision32bit2038(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlExpectedJTypeProperties(1, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlExpectedJTypeProperties(2, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlExpectedJTypeProperties(2, "aesEcbNone", TESTKEY_AES256)) + RUN_TEST(suite, testKeyCtrlExpectedExportedProperties(1, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlExpectedExportedProperties(2, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlExpectedExportedProperties(2, "aesEcbNone", TESTKEY_AES256)) + RUN_TEST(suite, testKeyCtrlUnwrapWithKeyUsage(1, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlUnwrapWithKeyUsage(2, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlUnwrapWithKeyUsage(2, "aesEcbNone", TESTKEY_AES256)) + RUN_TEST(suite, testKeyCtrlUnwrapWithDataUsage(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlBadB64Jtype(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlExportDerived()) + RUN_TEST(suite, testKeyCtrlExportProvisionExport(1, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlExportProvisionExport(2, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlExportProvisionExport(2, "aesEcbNone", TESTKEY_AES256)) + RUN_TEST(suite, testKeyCtrlKeyExportGetSize(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlKeyExportGetSize(2, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlExportAes(TESTKEY_AES128, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyCtrlExportAes(TESTKEY_AES256, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyCtrlExportAes(TESTKEY_AES128, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyCtrlExportAes(TESTKEY_AES256, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyCtrlKeyExportHmac(TESTKEY_HMAC128, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyCtrlKeyExportHmac(TESTKEY_HMAC160, SEC_STORAGELOC_RAM_SOFT_WRAPPED)) + RUN_TEST(suite, testKeyCtrlKeyExportHmac(TESTKEY_HMAC128, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testKeyCtrlKeyExportHmac(TESTKEY_HMAC160, SEC_STORAGELOC_RAM)) + if (TestCreds::supports(CAPABILITY_SVP)) { + RUN_TEST(suite, testKeyCtrlCipherFailsSvpNonOpaque(1, "aesEcbNone", SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING)) + RUN_TEST(suite, + testKeyCtrlCipherSvpOpaque(1, "aesEcbNone", TESTKEY_AES128, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING)) + RUN_TEST(suite, + testKeyCtrlCipherSvpOpaque(2, "aesEcbNone", TESTKEY_AES128, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING)) + RUN_TEST(suite, + testKeyCtrlCipherSvpOpaque(2, "aesEcbNone", TESTKEY_AES256, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING)) + RUN_TEST(suite, testKeyCtrlCipherSvpDataShiftOpaque(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlSvpCheckOpaque(1, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlSvpCheckOpaque(2, "aesEcbNone", TESTKEY_AES128)) + RUN_TEST(suite, testKeyCtrlSvpCheckOpaque(2, "aesEcbNone", TESTKEY_AES256)) + RUN_TEST(suite, testKeyCtrlProcessCtrDataShiftFailsSvpNonOpaque(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlCipherFailsSvpNonOpaque(1, "aesEcbNone", SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING)) + RUN_TEST(suite, + testKeyCtrlCipherSvpOpaque(1, "aesEcbNone", TESTKEY_AES128, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING)) + RUN_TEST(suite, + testKeyCtrlCipherSvpOpaque(2, "aesEcbNone", TESTKEY_AES128, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING)) + RUN_TEST(suite, + testKeyCtrlCipherSvpOpaque(2, "aesEcbNone", TESTKEY_AES256, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING)) + RUN_TEST(suite, testKeyCtrlCipherSvpDataShiftOpaque(1, "aesEcbNone")) + RUN_TEST(suite, testKeyCtrlProcessCtrDataShiftFailsSvpNonOpaque(1, "aesEcbNone")) + } + RUN_TEST(suite, testKeyCtrlExportEcc(TESTKC_CONDITIONAL)) + RUN_TEST(suite, testKeyCtrlKeyExportSmallBuffer()) +} + +#define DIGEST_TESTS(suite, alg) \ + do { \ + RUN_TEST(suite, testDigestSingle(alg, 0)); \ + RUN_TEST(suite, testDigestSingle(alg, 256)); \ + RUN_TEST(suite, testDigestSingle(alg, 259)); \ +\ + SEC_SIZE inputSizes[] = {16, 16, 8, 0, 3, 16}; \ + RUN_TEST(suite, testDigestMult(alg, std::vector(inputSizes, inputSizes + sizeof(inputSizes) / sizeof(SEC_SIZE)))); \ +\ + RUN_TEST(suite, testDigestOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES128, SEC_STORAGELOC_RAM)); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RUN_TEST(suite, testDigestOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES256, SEC_STORAGELOC_RAM)); \ + } \ + RUN_TEST(suite, testDigestOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, SEC_STORAGELOC_RAM)); \ + RUN_TEST(suite, testDigestOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, SEC_STORAGELOC_RAM)); \ + RUN_TEST(suite, testDigestOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, SEC_STORAGELOC_RAM)); \ + } while (0) + +#define MAC_TESTS(suite, key, kc, loc, alg) \ + do { \ + RUN_TEST(suite, testMacSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, alg, 256)); \ + RUN_TEST(suite, testMacSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, alg, 259)); \ +\ + SEC_SIZE inputSizes[] = {16, 16, 8, 0, 3, 16}; \ + RUN_TEST(suite, testMacMult(SEC_OBJECTID_USER_BASE, key, kc, loc, alg, \ + std::vector(inputSizes, inputSizes + sizeof(inputSizes) / sizeof(SEC_SIZE)))); \ +\ + if ((alg) != SEC_MACALGORITHM_CMAC_AES_128) { \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES128, loc)); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES256, loc)); \ + } \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC128, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC160, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC256, loc)); \ +\ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES128, loc)); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, \ +\ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES256, loc)); \ + } \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC128, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC160, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC160, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC256, loc)); \ +\ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES128, loc)); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES256, loc)); \ + } \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC128, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC160, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_HMAC256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC256, loc)); \ + } else { \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES128, loc)); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES256, loc)); \ + } \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC128, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC160, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC256, loc)); \ +\ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES128, loc)); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_AES256, loc)); \ + } \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC128, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC160, loc)); \ + RUN_TEST(suite, testMacOverKey(alg, SEC_OBJECTID_USER_BASE, TESTKEY_AES256, TESTKC_RAW, \ + SEC_OBJECTID_USER_BASE + 1, TESTKEY_HMAC256, loc)); \ + } \ + } \ + } while (0); + +#define AESCTR_SPECIFIC_TESTS(suite, key, kc, loc, mode, inplace) \ + do { \ + if ((kc) != TESTKC_GENERATED) { \ + RUN_TEST(suite, testProcessCtrWithDataShift(SEC_OBJECTID_USER_BASE, key, kc, loc, mode, inplace)); \ + RUN_TEST(suite, testCtrRollover(SEC_OBJECTID_USER_BASE, key, kc, loc, mode, 256, inplace)); \ + } \ + } while (0) + +#define AESCTR_INPLACE_TESTS(suite, key, kc, loc, mode) \ + do { \ + AESCTR_SPECIFIC_TESTS(suite, key, kc, loc, mode, SEC_TRUE); \ + AESCTR_SPECIFIC_TESTS(suite, key, kc, loc, mode, SEC_FALSE); \ + } while (0) + +#define AESCTR_MODE_TESTS(suite, key, kc, loc) \ + do { \ + AESCTR_INPLACE_TESTS(suite, key, kc, loc, SEC_CIPHERMODE_ENCRYPT); \ + AESCTR_INPLACE_TESTS(suite, key, kc, loc, SEC_CIPHERMODE_DECRYPT); \ + } while (0) + +#define AESCTR_LOC_TESTS(suite, key, kc) \ + do { \ + AESCTR_MODE_TESTS(suite, key, kc, SEC_STORAGELOC_RAM); \ + if ((kc) == TESTKC_RAW) { \ + AESCTR_MODE_TESTS(suite, key, kc, SEC_STORAGELOC_RAM_SOFT_WRAPPED); \ + } \ + } while (0) + +#define AESCTR_KC_TESTS(suite, key) \ + do { \ + AESCTR_LOC_TESTS(suite, key, TESTKC_RAW); \ + if (TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) { \ + AESCTR_LOC_TESTS(suite, key, TESTKC_CONDITIONAL); \ + } \ + AESCTR_LOC_TESTS(suite, key, TESTKC_GENERATED); \ + } while (0) + +#define AESCTR_TESTS(suite) \ + do { \ + AESCTR_KC_TESTS(suite, TESTKEY_AES128); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + AESCTR_KC_TESTS(suite, TESTKEY_AES256); \ + } \ + } while (0) + +#define AES_TESTS(suite, key, kc, loc) \ + do { \ + SEC_SIZE inputSizesBlock[] = {0, 16, 32, 64, 128}; \ + SEC_SIZE inputSizes[] = {0, 16, 32, 64, 128, 5}; \ + SEC_SIZE inputSizesStream[] = {0, 6, 16, 17, 32, 128, 3}; \ + std::vector blocked(inputSizesBlock, inputSizesBlock + sizeof(inputSizesBlock) / sizeof(SEC_SIZE)); \ + std::vector unaligned(inputSizes, inputSizes + sizeof(inputSizes) / sizeof(SEC_SIZE)); \ +\ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE * 2)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE * 2)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_ENCRYPT, blocked)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_DECRYPT, blocked)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_ENCRYPT, blocked, SEC_TRUE)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_DECRYPT, blocked, SEC_TRUE)); \ + RUN_TEST(suite, testCipherUpdateIV(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE * 2, SEC_FALSE)); \ + RUN_TEST(suite, testCipherUpdateIV(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, \ + SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE * 2, SEC_FALSE)); \ +\ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE * 2 + 8)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE * 2 + 8)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, unaligned)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, unaligned)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, unaligned, SEC_TRUE)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, unaligned, SEC_TRUE)); \ +\ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE * 2)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE * 2)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, blocked)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, blocked)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_ENCRYPT, blocked, SEC_TRUE)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, blocked, SEC_TRUE)); \ +\ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE * 2 + 8)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE * 2 + 8)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, unaligned)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, unaligned)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_ENCRYPT, unaligned, SEC_TRUE)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_ECB_PKCS7_PADDING, SEC_CIPHERMODE_DECRYPT, unaligned, SEC_TRUE)); \ +\ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE + 1)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE + 1, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE * 2)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE + 1)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE + 1, SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE * 2)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, blocked)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, unaligned)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, blocked)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, unaligned)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, blocked, SEC_TRUE)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, unaligned, SEC_TRUE)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, blocked, SEC_TRUE)); \ + RUN_TEST(suite, testCipherMult(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, unaligned, SEC_TRUE)); \ + RUN_TEST(suite, testCipherUpdateIV(SEC_OBJECTID_USER_BASE, key, kc, \ + loc, SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE * 2, SEC_FALSE)); \ + RUN_TEST(suite, testCipherUpdateIV(SEC_OBJECTID_USER_BASE, key, kc, \ + loc, SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE * 2, SEC_FALSE)); \ + } while (0) + +#define RSA_ENCRYPT_TESTS(suite, pub, priv, kc) \ + do { \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE, \ + SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_CIPHERALGORITHM_RSA_OAEP_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_CIPHERALGORITHM_RSA_OAEP_PADDING, SEC_CIPHERMODE_ENCRYPT, SEC_AES_BLOCK_SIZE, \ + SEC_TRUE)); \ + } while (0) + +#define RSA_DECRYPT_TESTS(suite, pub, priv, kc) \ + do { \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE, \ + SEC_TRUE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_CIPHERALGORITHM_RSA_OAEP_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE)); \ + RUN_TEST(suite, testCipherSingle(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_CIPHERALGORITHM_RSA_OAEP_PADDING, SEC_CIPHERMODE_DECRYPT, SEC_AES_BLOCK_SIZE, \ + SEC_TRUE)); \ + } while (0) + +void runRandomTests(SuiteCtx* suite) { + RUN_TEST(suite, testRandom(SEC_RANDOMALGORITHM_TRUE, 17)) + RUN_TEST(suite, testRandom(SEC_RANDOMALGORITHM_PRNG, 17)) +} + +void runSVPTests(SuiteCtx* suite) { + if (TestCreds::supports(CAPABILITY_SVP)) { + RUN_TEST(suite, testOpaqueMalloc()) + RUN_TEST(suite, testCopyOpaque()) + RUN_TEST(suite, testSecureBootEnabled()) + RUN_TEST(suite, testSetTime()) + RUN_TEST(suite, testKeycheckOpaque(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM)) + RUN_TEST(suite, testProcessOpaque(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM, + SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING)) + RUN_TEST(suite, testProcessOpaque(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM, + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING)) + RUN_TEST(suite, + testProcessDataShiftOpaque(SEC_OBJECTID_USER_BASE, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM)) + } +} + +#define RSAAESRSAAESAES_SPECIFIC_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, ck_sym_alg, wkfv) \ + do { \ + TestKey key = (sym_type) == SEC_KEYTYPE_AES_128 ? TESTKEY_AES128 : TESTKEY_AES256; \ + RUN_TEST(suite, testWrappedCipherSingleRsaAesRsaAesAes(key, TESTKC_SOC, rsa_type, rsa_alg, sym_type, \ + sym_alg, ck_sym_alg, wkfv)); \ + } while (0) + +#define RSAAESRSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, ck_sym_alg) \ + do { \ + RSAAESRSAAESAES_SPECIFIC_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, ck_sym_alg, WKFV_V2); \ + if (TestCreds::supports(CAPABILITY_WRAPPED_KEY_FORMAT_V3)) { \ + RSAAESRSAAESAES_SPECIFIC_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, ck_sym_alg, WKFV_V3); \ + } \ + } while (0) + +#define RSAAESRSAAESAES_CKSYMALG_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg) \ + do { \ + if (TestCreds::supports(CAPABILITY_RSA_AESCBC_AES)) { \ + RSAAESRSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING); \ + RSAAESRSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING); \ + } \ + RSAAESRSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING); \ + if (TestCreds::supports(CAPABILITY_RSA_AESCTR_AES)) { \ + RSAAESRSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, SEC_CIPHERALGORITHM_AES_CTR); \ + } \ + } while (0) + +#define RSAAESRSAAESAES_SYMALG_TESTS(suite, rsa_type, rsa_alg, sym_type) \ + do { \ + RSAAESRSAAESAES_CKSYMALG_TESTS(suite, rsa_type, rsa_alg, sym_type, SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING); \ + if (TestCreds::supports(CAPABILITY_RSA_AESCTR_RSA)) { \ + RSAAESRSAAESAES_CKSYMALG_TESTS(suite, rsa_type, rsa_alg, sym_type, SEC_CIPHERALGORITHM_AES_CTR); \ + } \ + } while (0) + +#define RSAAESRSAAESAES_SYMTYPE_TESTS(suite, rsa_type, rsa_alg) \ + do { \ + RSAAESRSAAESAES_SYMALG_TESTS(suite, rsa_type, rsa_alg, SEC_KEYTYPE_AES_128); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RSAAESRSAAESAES_SYMALG_TESTS(suite, rsa_type, rsa_alg, SEC_KEYTYPE_AES_256); \ + } \ + } while (0) + +#define RSAAESRSAAESAES_ASYMALG_TESTS(suite, rsa_type) \ + do { \ + RSAAESRSAAESAES_SYMTYPE_TESTS(suite, rsa_type, SEC_CIPHERALGORITHM_RSA_OAEP_PADDING); \ + RSAAESRSAAESAES_SYMTYPE_TESTS(suite, rsa_type, SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING); \ + } while (0) + +#define RSAAESRSAAESAES_ASYMTYPE_TESTS(suite) \ + do { \ + if (TestCreds::supports(CAPABILITY_RSA_1024)) { \ + RSAAESRSAAESAES_ASYMALG_TESTS(suite, SEC_KEYTYPE_RSA_1024); \ + } \ + RSAAESRSAAESAES_ASYMALG_TESTS(suite, SEC_KEYTYPE_RSA_2048); \ + } while (0) + +#define RSAAES_SPECIFIC_TESTS(suite, con_key, rsa_type, rsa_alg, wkfv) \ + do { \ + RUN_TEST(suite, testWrappedCipherSingleRsaAes(con_key, TESTKC_SOC, rsa_type, rsa_alg, wkfv)); \ + } while (0) + +#define RSAAES_WKFV_TESTS(suite, con_key, rsa_type, rsa_alg) \ + do { \ + RSAAES_SPECIFIC_TESTS(suite, con_key, rsa_type, rsa_alg, WKFV_V2); \ + if (TestCreds::supports(CAPABILITY_WRAPPED_KEY_FORMAT_V3)) { \ + RSAAES_SPECIFIC_TESTS(suite, con_key, rsa_type, rsa_alg, WKFV_V3); \ + } \ + } while (0) + +#define RSAAES_ASYMALG_TESTS(suite, con_key, rsa_type) \ + do { \ + RSAAES_WKFV_TESTS(suite, con_key, rsa_type, SEC_CIPHERALGORITHM_RSA_OAEP_PADDING); \ + RSAAES_WKFV_TESTS(suite, con_key, rsa_type, SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING); \ + } while (0) + +#define RSAAES_ASYTYPE_TESTS(suite, con_key) \ + do { \ + if (TestCreds::supports(CAPABILITY_RSA_1024)) { \ + RSAAES_ASYMALG_TESTS(suite, con_key, SEC_KEYTYPE_RSA_1024); \ + } \ + RSAAES_ASYMALG_TESTS(suite, con_key, SEC_KEYTYPE_RSA_2048); \ + } while (0) + +#define RSAAES_TESTS(suite) \ + do { \ + if (TestCreds::supports(CAPABILITY_RSA_AES_M2M)) { \ + RSAAES_ASYTYPE_TESTS(suite, TESTKEY_AES128); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RSAAES_ASYTYPE_TESTS(suite, TESTKEY_AES256); \ + } \ + } \ + } while (0) + +#define RSAAESAES_SPECIFIC_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, wkfv) \ + do { \ + TestKey key = (sym_type) == SEC_KEYTYPE_AES_128 ? TESTKEY_AES128 : TESTKEY_AES256; \ + RUN_TEST(suite, testWrappedCipherSingleRsaAesAes(key, TESTKC_SOC, rsa_type, rsa_alg, sym_type, sym_alg, wkfv)); \ + RUN_TEST(suite, testExportWrappedRsaAesAes(key, TESTKC_SOC, rsa_type, rsa_alg, sym_type, sym_alg, wkfv)); \ + } while (0) + +#define RSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg) \ + do { \ + RSAAESAES_SPECIFIC_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, WKFV_V2); \ + if (TestCreds::supports(CAPABILITY_WRAPPED_KEY_FORMAT_V3)) { \ + RSAAESAES_SPECIFIC_TESTS(suite, rsa_type, rsa_alg, sym_type, sym_alg, WKFV_V3); \ + } \ + } while (0) + +#define RSAAESAES_SYMALG_TESTS(suite, rsa_type, rsa_alg, sym_type) \ + do { \ + RSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING); \ + if (TestCreds::supports(CAPABILITY_RSA_AESCBC_AES)) { \ + RSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING); \ + RSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, SEC_CIPHERALGORITHM_AES_CBC_PKCS7_PADDING); \ + } \ + if (TestCreds::supports(CAPABILITY_RSA_AESCTR_AES)) { \ + RSAAESAES_WKFV_TESTS(suite, rsa_type, rsa_alg, sym_type, SEC_CIPHERALGORITHM_AES_CTR); \ + } \ + } while (0) + +#define RSAAESAES_SYMTYPE_TESTS(suite, rsa_type, rsa_alg) \ + do { \ + RSAAESAES_SYMALG_TESTS(suite, rsa_type, rsa_alg, SEC_KEYTYPE_AES_128); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RSAAESAES_SYMALG_TESTS(suite, rsa_type, rsa_alg, SEC_KEYTYPE_AES_256); \ + } \ + } while (0) + +#define RSAAESAES_ASYMALG_TESTS(suite, rsa_type) \ + do { \ + RSAAESAES_SYMTYPE_TESTS(suite, rsa_type, SEC_CIPHERALGORITHM_RSA_OAEP_PADDING); \ + RSAAESAES_SYMTYPE_TESTS(suite, rsa_type, SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING); \ + } while (0) + +#define RSAAESAES_TESTS(suite) \ + do { \ + if (TestCreds::supports(CAPABILITY_RSA_1024)) { \ + RSAAESAES_ASYMALG_TESTS(suite, SEC_KEYTYPE_RSA_1024); \ + } \ + RSAAESAES_ASYMALG_TESTS(suite, SEC_KEYTYPE_RSA_2048); \ + } while (0) + +#define ECAESAES_SPECIFIC_TESTS(suite, con_key, asym_alg, sym_alg, wkfv) \ + do { \ + RUN_TEST(suite, testWrappedCipherSingleEcAesAes(con_key, TESTKC_SOC, SEC_KEYTYPE_AES_128, asym_alg, sym_alg, \ + wkfv)); \ + RUN_TEST(suite, testExportWrappedEccAesAes(con_key, TESTKC_SOC, asym_alg, SEC_KEYTYPE_AES_128, sym_alg, \ + wkfv)); \ + RUN_TEST(suite, testExportWrappedGeneratedEccAesAes(con_key, asym_alg, SEC_KEYTYPE_AES_128, sym_alg, wkfv)); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + RUN_TEST(suite, testWrappedCipherSingleEcAesAes(con_key, TESTKC_SOC, SEC_KEYTYPE_AES_256, asym_alg, \ + sym_alg, wkfv)); \ + RUN_TEST(suite, testExportWrappedEccAesAes(con_key, TESTKC_SOC, asym_alg, SEC_KEYTYPE_AES_256, sym_alg, \ + wkfv)); \ + RUN_TEST(suite, testExportWrappedGeneratedEccAesAes(con_key, asym_alg, SEC_KEYTYPE_AES_256, sym_alg, \ + wkfv)); \ + } \ + } while (0) + +#define ECAES_SPECIFIC_TESTS(suite, con_key, asym_alg, wkfv) \ + do { \ + RUN_TEST(suite, testWrappedCipherSingleEcAes(con_key, TESTKC_SOC, asym_alg, wkfv)); \ + RUN_TEST(suite, testExportWrappedEccAes(con_key, TESTKC_SOC, asym_alg, wkfv)); \ + RUN_TEST(suite, testExportWrappedGeneratedEccAes(con_key, asym_alg, wkfv)); \ + } while (0) + +#define ECAES_WKFV_TESTS(suite, con_key, asym_alg) \ + do { \ + ECAES_SPECIFIC_TESTS(suite, con_key, asym_alg, WKFV_V2); \ + ECAESAES_SPECIFIC_TESTS(suite, con_key, asym_alg, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, WKFV_V2); \ + ECAESAES_SPECIFIC_TESTS(suite, con_key, asym_alg, SEC_CIPHERALGORITHM_AES_CTR, WKFV_V2); \ + if (TestCreds::supports(CAPABILITY_WRAPPED_KEY_FORMAT_V3)) { \ + ECAES_SPECIFIC_TESTS(suite, con_key, asym_alg, WKFV_V3); \ + ECAESAES_SPECIFIC_TESTS(suite, con_key, asym_alg, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, WKFV_V3); \ + ECAESAES_SPECIFIC_TESTS(suite, con_key, asym_alg, SEC_CIPHERALGORITHM_AES_CTR, WKFV_V3); \ + } \ + } while (0) + +#define ECAES_ASYMALG_TESTS(suite, con_key) \ + do { \ + ECAES_WKFV_TESTS(suite, con_key, SEC_CIPHERALGORITHM_ECC_ELGAMAL); \ + } while (0) + +#define ECAES_TESTS(suite) \ + do { \ + ECAES_ASYMALG_TESTS(suite, TESTKEY_AES128); \ + if (TestCreds::supports(CAPABILITY_AES256)) { \ + ECAES_ASYMALG_TESTS(suite, TESTKEY_AES256); \ + } \ + } while (0) + +#define OPAQUE_WITH_MAP_TESTS(suite, key, kc, loc) \ + do { \ +\ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 1, 0)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 1, 16)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 1, 20)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 1, 256)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 2, 0)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 2, 16)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 2, 20)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 2, 256)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 5, 0)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 5, 16)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 5, 20)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 5, 256)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 10, 0)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 10, 16)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 10, 20)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR, 10, 256)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 1, 0)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 1, 16)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 1, 256)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 2, 0)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 2, 16)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 2, 256)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 5, 0)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 5, 16)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 5, 256)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 10, 0)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 10, 16)); \ + RUN_TEST(suite, testProcessOpaqueWithMap(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING, 10, 256)); \ +\ + RUN_TEST(suite, testProcessOpaqueWithMapVariable(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CTR)); \ + RUN_TEST(suite, testProcessOpaqueWithMapVariable(SEC_OBJECTID_USER_BASE, key, kc, loc, \ + SEC_CIPHERALGORITHM_AES_CBC_NO_PADDING)); \ + } while (0) + +void runWrappedTests(SuiteCtx* suite) { // NOLINT + RSAAESRSAAESAES_ASYMTYPE_TESTS(suite); + RSAAESAES_TESTS(suite); + RSAAES_TESTS(suite); + ECAES_TESTS(suite); + RUN_TEST(suite, + testWrappedKDFCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, SEC_OBJECTID_USER_BASE + 2, + SEC_KEYTYPE_AES_128, 1, 256)) + RUN_TEST(suite, + testWrappedKDFCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, SEC_OBJECTID_USER_BASE + 2, + SEC_KEYTYPE_HMAC_128, 1, 256)) + RUN_TEST(suite, + testExportedKDFCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, SEC_OBJECTID_USER_BASE + 2, + SEC_KEYTYPE_AES_128, 1, 256)) + RUN_TEST(suite, + testExportedKDFCMACAES128(SEC_OBJECTID_USER_BASE, SEC_OBJECTID_USER_BASE + 1, SEC_OBJECTID_USER_BASE + 2, + SEC_KEYTYPE_HMAC_128, 1, 256)) +} + +void runConcurrentTests(SuiteCtx* suite) { + RUN_TEST(suite, testConcurrentVendor128(40)) + + if (TestCreds::supports(CAPABILITY_RSA_1024)) { + + RUN_TEST(suite, testConcurrentRsa(TESTKEY_RSA1024_ENC_PUB, TESTKEY_RSA1024_ENC_PRIV, TESTKC_CONDITIONAL, 10)) + } + RUN_TEST(suite, testConcurrentRsa(TESTKEY_RSA2048_ENC_PUB, TESTKEY_RSA2048_ENC_PRIV, TESTKC_CONDITIONAL, 10)) +} + +void runExchangeTests(SuiteCtx* suite) { + RUN_TEST(suite, testKeyExchangeDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_AES_128, SEC_TRUE)) + RUN_TEST(suite, testKeyExchangeDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_AES_128, SEC_FALSE)) + if (TestCreds::supports(CAPABILITY_AES256)) { + RUN_TEST(suite, testKeyExchangeDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_AES_256, SEC_TRUE)) + RUN_TEST(suite, testKeyExchangeDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_AES_256, SEC_FALSE)) + } + RUN_TEST(suite, testKeyExchangeDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_HMAC_128, SEC_TRUE)) + RUN_TEST(suite, testKeyExchangeDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_HMAC_128, SEC_FALSE)) + RUN_TEST(suite, testKeyExchangeDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_HMAC_160, SEC_TRUE)) + RUN_TEST(suite, testKeyExchangeDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_HMAC_160, SEC_FALSE)) + + RUN_TEST(suite, testKeyExchangeECDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_AES_128, SEC_TRUE)) + RUN_TEST(suite, testKeyExchangeECDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_AES_128, SEC_FALSE)) + if (TestCreds::supports(CAPABILITY_AES256)) { + RUN_TEST(suite, testKeyExchangeECDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_AES_256, SEC_TRUE)) + RUN_TEST(suite, testKeyExchangeECDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_AES_256, + SEC_FALSE)) + } + RUN_TEST(suite, testKeyExchangeECDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_HMAC_128, SEC_TRUE)) + RUN_TEST(suite, testKeyExchangeECDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_HMAC_128, SEC_FALSE)) + RUN_TEST(suite, testKeyExchangeECDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_HMAC_160, SEC_TRUE)) + RUN_TEST(suite, testKeyExchangeECDH(SEC_OBJECTID_USER_BASE, SEC_STORAGELOC_RAM, SEC_KEYTYPE_HMAC_160, SEC_FALSE)) +} + +#define RSA_SIGNATURE_TESTS(suite, pub, priv, kc, keySize) \ + do { \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST, SEC_SIGNATUREMODE_SIGN, 20)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST, SEC_SIGNATUREMODE_VERIFY, 20)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS, SEC_SIGNATUREMODE_SIGN, 2049)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS, SEC_SIGNATUREMODE_VERIFY, 2049)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST, SEC_SIGNATUREMODE_SIGN, 32)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST, SEC_SIGNATUREMODE_VERIFY, 32)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS, SEC_SIGNATUREMODE_SIGN, 2049)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS, SEC_SIGNATUREMODE_VERIFY, 2049)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST, SEC_SIGNATUREMODE_SIGN, 20)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST, SEC_SIGNATUREMODE_VERIFY, 20)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS, SEC_SIGNATUREMODE_SIGN, 2049)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS, SEC_SIGNATUREMODE_VERIFY, 2049)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST, SEC_SIGNATUREMODE_SIGN, 32)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST, SEC_SIGNATUREMODE_VERIFY, 32)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS, SEC_SIGNATUREMODE_SIGN, 2049)); \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS, SEC_SIGNATUREMODE_VERIFY, 2049)); \ + } while (0) + +#define EC_SIGNATURE_TESTS(suite, pub, priv, kc, keySize) \ + do { \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST, SEC_SIGNATUREMODE_SIGN, 32)); \ + if ((kc) != TESTKC_GENERATED) { \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST, SEC_SIGNATUREMODE_VERIFY, 32)); \ + } \ +\ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, kc, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_ECDSA_NISTP256, SEC_SIGNATUREMODE_SIGN, 2049)); \ + if ((kc) != TESTKC_GENERATED) { \ + RUN_TEST(suite, testSignature(SEC_OBJECTID_USER_BASE, pub, priv, TESTKC_RAW, SEC_STORAGELOC_RAM, \ + SEC_SIGNATUREALGORITHM_ECDSA_NISTP256, SEC_SIGNATUREMODE_VERIFY, 2049)); \ + } \ + } while (0) + +int testIt(int argc, char* argv[]) { // NOLINT + int nParams = argc - 1; + std::vector runParams; + SEC_PRINT("Number of runParams: %d\n", nParams); + for (int i = 1; i < (nParams + 1); ++i) { + auto x = strtol(argv[i], nullptr, 0); + runParams.push_back(x); + } + + SEC_PRINT("==============================================\n"); + + //print SecApi info + { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return 1; + } + + if (SecProcessor_PrintInfo(ctx.proc()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecProcessor_PrintInfo failed"); + return 1; + } + } + + TestCreds::init(); + SuiteCtx suite; + suite.setRunParams(runParams); + + SEC_PRINT("\n"); + SEC_PRINT("CAPABILITY_AES256: %d\n", TestCreds::supports(CAPABILITY_AES256)); + SEC_PRINT("CAPABILITY_HMAC_IN_HW: %d\n", TestCreds::supports(CAPABILITY_HMAC_IN_HW)); + SEC_PRINT("CAPABILITY_CMAC_IN_HW: %d\n", TestCreds::supports(CAPABILITY_CMAC_IN_HW)); + SEC_PRINT("CAPABILITY_DIGEST_OVER_HWKEY: %d\n", TestCreds::supports(CAPABILITY_DIGEST_OVER_HWKEY)); + SEC_PRINT("CAPABILITY_HMAC_OVER_HWKEY: %d\n", TestCreds::supports(CAPABILITY_HMAC_OVER_HWKEY)); + SEC_PRINT("CAPABILITY_CMAC_OVER_HWKEY: %d\n", TestCreds::supports(CAPABILITY_CMAC_OVER_HWKEY)); + SEC_PRINT("CAPABILITY_HKDF_CMAC: %d\n", TestCreds::supports(CAPABILITY_HKDF_CMAC)); + SEC_PRINT("CAPABILITY_EXTRACT_RSA_PUB: %d\n", TestCreds::supports(CAPABILITY_EXTRACT_RSA_PUB)); + SEC_PRINT("CAPABILITY_WRAPPED_KEY_FORMAT_V3: %d\n", TestCreds::supports(CAPABILITY_WRAPPED_KEY_FORMAT_V3)); + SEC_PRINT("CAPABILITY_RSA_AES_M2M: %d\n", TestCreds::supports(CAPABILITY_RSA_AES_M2M)); + SEC_PRINT("CAPABILITY_CLEAR_JTYPE_WRAPPING: %d\n", TestCreds::supports(CAPABILITY_CLEAR_JTYPE_WRAPPING)); + SEC_PRINT("CAPABILITY_SVP: %d\n", TestCreds::supports(CAPABILITY_SVP)); + SEC_PRINT("CAPABILITY_LOAD_SYM_SOC_KC: %d\n", TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)); + SEC_PRINT("CAPABILITY_EXPORT_RSA: %d\n", TestCreds::supports(CAPABILITY_EXPORT_RSA)); + SEC_PRINT("CAPABILITY_RSA_1024: %d\n", TestCreds::supports(CAPABILITY_RSA_1024)); + SEC_PRINT("CAPABILITY_RSA_AESCBC_AES: %d\n", TestCreds::supports(CAPABILITY_RSA_AESCBC_AES)); + SEC_PRINT("CAPABILITY_RSA_AESCTR_AES: %d\n", TestCreds::supports(CAPABILITY_RSA_AESCTR_AES)); + SEC_PRINT("CAPABILITY_RSA_AESCTR_RSA: %d\n", TestCreds::supports(CAPABILITY_RSA_AESCTR_RSA)); + SEC_PRINT("\n"); + + runProcessorTests(&suite); + + runRandomTests(&suite); + + runBundleTests(&suite); + + runCertTests(&suite); + + runKeyTests(&suite); + + DIGEST_TESTS(&suite, SEC_DIGESTALGORITHM_SHA1); + DIGEST_TESTS(&suite, SEC_DIGESTALGORITHM_SHA256); + + if (TestCreds::supports(CAPABILITY_HMAC_IN_HW)) { + MAC_TESTS(&suite, TESTKEY_HMAC128, TESTKC_RAW, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA1) + MAC_TESTS(&suite, TESTKEY_HMAC160, TESTKC_RAW, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA1) + MAC_TESTS(&suite, TESTKEY_HMAC256, TESTKC_RAW, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA1) + MAC_TESTS(&suite, TESTKEY_HMAC128, TESTKC_RAW, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA256) + MAC_TESTS(&suite, TESTKEY_HMAC160, TESTKC_RAW, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA256) + MAC_TESTS(&suite, TESTKEY_HMAC256, TESTKC_RAW, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_HMAC_SHA256) + } else { + MAC_TESTS(&suite, TESTKEY_HMAC128, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED, SEC_MACALGORITHM_HMAC_SHA1) + MAC_TESTS(&suite, TESTKEY_HMAC160, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED, SEC_MACALGORITHM_HMAC_SHA1) + MAC_TESTS(&suite, TESTKEY_HMAC256, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED, SEC_MACALGORITHM_HMAC_SHA1) + MAC_TESTS(&suite, TESTKEY_HMAC128, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED, SEC_MACALGORITHM_HMAC_SHA256) + MAC_TESTS(&suite, TESTKEY_HMAC160, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED, SEC_MACALGORITHM_HMAC_SHA256) + MAC_TESTS(&suite, TESTKEY_HMAC256, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED, SEC_MACALGORITHM_HMAC_SHA256) + } + + if (TestCreds::supports(CAPABILITY_CMAC_IN_HW)) { + MAC_TESTS(&suite, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_CMAC_AES_128) + if (TestCreds::supports(CAPABILITY_AES256)) { + MAC_TESTS(&suite, TESTKEY_AES256, TESTKC_RAW, SEC_STORAGELOC_RAM, SEC_MACALGORITHM_CMAC_AES_128) + } + } else { + MAC_TESTS(&suite, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED, SEC_MACALGORITHM_CMAC_AES_128) + if (TestCreds::supports(CAPABILITY_AES256)) { + MAC_TESTS(&suite, TESTKEY_AES256, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED, + SEC_MACALGORITHM_CMAC_AES_128) + } + } + + //aes + AES_TESTS(&suite, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM); + AES_TESTS(&suite, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED); + + if (TestCreds::supports(CAPABILITY_AES256)) { + AES_TESTS(&suite, TESTKEY_AES256, TESTKC_RAW, SEC_STORAGELOC_RAM); + AES_TESTS(&suite, TESTKEY_AES256, TESTKC_RAW, SEC_STORAGELOC_RAM_SOFT_WRAPPED); + } + + AESCTR_TESTS(&suite); + + //rsa + if (TestCreds::supports(CAPABILITY_RSA_1024)) { + RSA_ENCRYPT_TESTS(&suite, TESTKEY_RSA1024_ENC_PUB, TESTKEY_RSA1024_ENC_PRIV, TESTKC_RAW); + RSA_DECRYPT_TESTS(&suite, TESTKEY_RSA1024_ENC_PUB, TESTKEY_RSA1024_ENC_PRIV, TESTKC_CONDITIONAL); + } + + RSA_ENCRYPT_TESTS(&suite, TESTKEY_RSA2048_ENC_PUB, TESTKEY_RSA2048_ENC_PRIV, TESTKC_RAW); + RSA_DECRYPT_TESTS(&suite, TESTKEY_RSA2048_ENC_PUB, TESTKEY_RSA2048_ENC_PRIV, TESTKC_CONDITIONAL); + + //sign + if (TestCreds::supports(CAPABILITY_RSA_1024)) { + RSA_SIGNATURE_TESTS(&suite, TESTKEY_RSA1024_SGN_PUB, TESTKEY_RSA1024_SGN_PRIV, TESTKC_CONDITIONAL, 128); + } + RSA_SIGNATURE_TESTS(&suite, TESTKEY_RSA2048_SGN_PUB, TESTKEY_RSA2048_SGN_PRIV, TESTKC_CONDITIONAL, 256); + + EC_SIGNATURE_TESTS(&suite, TESTKEY_EC_PUB, TESTKEY_EC_PRIV, TESTKC_CONDITIONAL, 128); + EC_SIGNATURE_TESTS(&suite, TESTKEY_EC_PUB, TESTKEY_EC_PRIV, TESTKC_GENERATED, 128); + EC_SIGNATURE_TESTS(&suite, TESTKEY_EC_PUB, TESTKEY_EC_PRIV, TESTKC_EXPORTED, 128); + + OPAQUE_WITH_MAP_TESTS(&suite, TESTKEY_AES128, TESTKC_RAW, SEC_STORAGELOC_RAM); + + runWrappedTests(&suite); + + runKeyCtrlTests(&suite); + + runSVPTests(&suite); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + runConcurrentTests(&suite); +#endif + runExchangeTests(&suite); + + //todo: fragmented processing + //todo: add pem containers, raw formats for keys, certs + + SEC_PRINT("==============================================\n"); + SEC_PRINT("Test summary: %d/%d succeeded, %d skipped\n", suite.getSucceeded().size(), suite.getAttempted().size(), + suite.getSkipped().size()); + + std::vector failed = suite.getFailed(); + if (failed.empty()) { + SEC_PRINT("\nFailed Tests: [%d]\n", failed.size()); + for (unsigned int i = 0; i < failed.size(); ++i) { + SEC_PRINT("%d ", failed[i]); + if (i % SEC_AES_BLOCK_SIZE == 15) { + SEC_PRINT("\n"); + } + } + SEC_PRINT("\n-------------------\n"); + + for (int i : failed) { + SEC_PRINT("%d: %s\n", i, suite.getTestEntry(i).first); + } + } + + TestCreds::shutdown(); + + return static_cast(failed.size()); +} + +int main(int argc, char* argv[]) { + return testIt(argc, argv); +} diff --git a/test/main/cpp/sec_api_utest_main.h b/test/main/cpp/sec_api_utest_main.h new file mode 100644 index 0000000..f9e0fe3 --- /dev/null +++ b/test/main/cpp/sec_api_utest_main.h @@ -0,0 +1,31 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SEC_API_UTEST_MAIN_H +#define SEC_API_UTEST_MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +int testIt(int argc, char* argv[]); + +#ifdef __cplusplus +} +#endif +#endif // SEC_API_UTEST_MAIN_H diff --git a/test/main/cpp/sign.cpp b/test/main/cpp/sign.cpp new file mode 100644 index 0000000..1a79023 --- /dev/null +++ b/test/main/cpp/sign.cpp @@ -0,0 +1,483 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sign.h" // NOLINT +#include "digest.h" +#include "sec_adapter_utils.h" +#include "test_ctx.h" + +static Sec_Result BigNumToBuffer(const BIGNUM* bignum, SEC_BYTE* buffer, SEC_SIZE buffer_len) { + SEC_SIZE num_bytes; + + memset(buffer, 0, buffer_len); + num_bytes = BN_num_bytes(bignum); + + if (num_bytes > buffer_len) { + SEC_LOG_ERROR("Buffer not large enough. needed: %d, actual: %d", num_bytes, buffer_len); + return SEC_RESULT_FAILURE; + } + + BN_bn2bin(bignum, buffer + buffer_len - num_bytes); + + return SEC_RESULT_SUCCESS; +} + +std::vector signOpenSSL(Sec_SignatureAlgorithm alg, TestKey key, const std::vector& input) { + std::vector digest; + const EVP_MD* evp_md; + + bool pss = (alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS); + + if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST) { + digest = input; + evp_md = EVP_sha1(); + } else if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST) { + digest = input; + evp_md = EVP_sha256(); + } else if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS) { + digest = digestOpenSSL(SEC_DIGESTALGORITHM_SHA1, input); + evp_md = EVP_sha1(); + } else if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS || + alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256) { + digest = digestOpenSSL(SEC_DIGESTALGORITHM_SHA256, input); + evp_md = EVP_sha256(); + } else { + SEC_LOG_ERROR("Unknown signature algorithm"); + return {}; + } + + TestCtx::printHex("digest to sign", digest); + + if (SecKey_IsEcc(TestCreds::getKeyType(key)) == SEC_TRUE) { + ECDSA_SIG* esig; + + EC_KEY* ec_key = TestCreds::asOpenSslEcKey(key); + if (ec_key == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslEcKey failed"); + return {}; + } + + esig = ECDSA_do_sign(&digest[0], static_cast(digest.size()), ec_key); + SEC_ECC_FREE(ec_key); + + if (esig == nullptr) { + SEC_LOG_ERROR("ECDSA_do_sign failed"); + return {}; + } + + std::vector sig; + sig.resize(256); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + BigNumToBuffer(esig->r, &sig[0], SEC_ECC_NISTP256_KEY_LEN); + BigNumToBuffer(esig->s, &sig[SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN); +#else + const BIGNUM* esigr = nullptr; + const BIGNUM* esigs = nullptr; + ECDSA_SIG_get0(esig, &esigr, &esigs); + BigNumToBuffer(const_cast(esigr), &sig[0], SEC_ECC_NISTP256_KEY_LEN); + BigNumToBuffer(const_cast(esigs), &sig[SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN); +#endif + ECDSA_SIG_free(esig); + + sig.resize(SecSignature_GetEccSignatureSize(alg)); + return sig; + } + + EVP_PKEY* evp_pkey = TestCreds::asOpenSslEvpPkey(key); + if (evp_pkey == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslEvpPkey failed"); + return {}; + } + + EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(evp_pkey, nullptr); + if (ctx == nullptr) { + EVP_PKEY_free(evp_pkey); + SEC_LOG_ERROR("EVP_PKEY_CTX_new failed"); + return {}; + } + + if (EVP_PKEY_sign_init(ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding(ctx, pss ? RSA_PKCS1_PSS_PADDING : RSA_PKCS1_PADDING) <= 0 || + EVP_PKEY_CTX_set_signature_md(ctx, evp_md) <= 0) { + EVP_PKEY_free(evp_pkey); + EVP_PKEY_CTX_free(ctx); + SEC_LOG_ERROR("Could not setup EVP_PKEY_CTX"); + return {}; + } + + if (pss && EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, evp_md == EVP_sha1() ? 20 : 32) <= 0) { + EVP_PKEY_free(evp_pkey); + EVP_PKEY_CTX_free(ctx); + SEC_LOG_ERROR("Could not setup EVP_PKEY_CTX"); + return {}; + } + + std::vector sig; + sig.resize(256); + size_t siglen = 256; + + if (EVP_PKEY_sign(ctx, nullptr, &siglen, &digest[0], digest.size()) <= 0 || + EVP_PKEY_sign(ctx, &sig[0], &siglen, &digest[0], digest.size()) <= 0) { + EVP_PKEY_free(evp_pkey); + EVP_PKEY_CTX_free(ctx); + SEC_LOG_ERROR("EVP_PKEY_sign failed"); + return {}; + } + + EVP_PKEY_free(evp_pkey); + EVP_PKEY_CTX_free(ctx); + + sig.resize(siglen); + + return sig; +} + +static EC_KEY* ECCFromPubBinary(Sec_ECCRawPublicKey* binary) { + BN_CTX* ctx = BN_CTX_new(); + + if (binary->type != SEC_KEYTYPE_ECC_NISTP256_PUBLIC && binary->type != SEC_KEYTYPE_ECC_NISTP256) + return nullptr; + + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); //create ec_key structure with NIST p256 curve; + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + EC_POINT* ec_point = EC_POINT_new(group); + BN_CTX_start(ctx); + BIGNUM* xp; + BIGNUM* yp; + + do { + if (((xp = BN_CTX_get(ctx)) == nullptr) || ((yp = BN_CTX_get(ctx)) == nullptr)) + break; + + EC_POINT_set_affine_coordinates_GFp(group, ec_point, + BN_bin2bn(binary->x, static_cast(Sec_BEBytesToUint32(binary->key_len)), xp), + BN_bin2bn(binary->y, static_cast(Sec_BEBytesToUint32(binary->key_len)), yp), ctx); + EC_KEY_set_public_key(ec_key, ec_point); + + } while (false); + + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return ec_key; +} + +static SEC_BOOL verifyOpenSSLEccPub(Sec_SignatureAlgorithm alg, Sec_ECCRawPublicKey* eccPub, + const std::vector& input, const std::vector& sig) { + + std::vector digest; + + if (alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST) { + digest = input; + } else if (alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256) { + digest = digestOpenSSL(SEC_DIGESTALGORITHM_SHA256, input); + } else { + SEC_LOG_ERROR("Unknown signature algorithm"); + return SEC_FALSE; + } + + TestCtx::printHex("digest to verify", digest); + + if (sig.size() != SecSignature_GetEccSignatureSize(alg)) { + SEC_LOG_ERROR("Incorrect ECC signature size"); + return SEC_FALSE; + } + + EC_KEY* ec_key = ECCFromPubBinary(eccPub); + if (ec_key == nullptr) { + SEC_LOG_ERROR("TestCreds::_ECCFromPubBinary failed"); + return SEC_FALSE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + ECDSA_SIG esig; + esig.r = BN_new(); + esig.s = BN_new(); + BN_bin2bn(&sig[0], SEC_ECC_NISTP256_KEY_LEN, esig.r); + BN_bin2bn(&sig[SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN, esig.s); + int openssl_res = ECDSA_do_verify(&digest[0], static_cast(digest.size()), &esig, ec_key); + BN_free(esig.r); + BN_free(esig.s); +#else + ECDSA_SIG* esig = ECDSA_SIG_new(); + BIGNUM* r = BN_new(); + BIGNUM* s = BN_new(); + BN_bin2bn(&sig[0], SEC_ECC_NISTP256_KEY_LEN, r); + BN_bin2bn(&sig[SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN, s); + ECDSA_SIG_set0(esig, r, s); + int openssl_res = ECDSA_do_verify(&digest[0], static_cast(digest.size()), esig, ec_key); + ECDSA_SIG_free(esig); +#endif + SEC_ECC_FREE(ec_key); + + if (openssl_res != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("ECDSA_do_verify failed"); + return SEC_FALSE; + } + + return SEC_TRUE; +} + +SEC_BOOL verifyOpenSSL(Sec_SignatureAlgorithm alg, TestKey key, const std::vector& input, + const std::vector& sig) { + + std::vector digest; + const EVP_MD* evp_md; + + bool pss = (alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS); + + if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST || alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST) { + digest = input; + evp_md = EVP_sha1(); + } else if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST) { + digest = input; + evp_md = EVP_sha256(); + } else if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS || alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS) { + digest = digestOpenSSL(SEC_DIGESTALGORITHM_SHA1, input); + evp_md = EVP_sha1(); + } else if (alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS || alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS || + alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256) { + digest = digestOpenSSL(SEC_DIGESTALGORITHM_SHA256, input); + evp_md = EVP_sha256(); + } else { + SEC_LOG_ERROR("Unknown signature algorithm"); + return SEC_FALSE; + } + + TestCtx::printHex("digest to verify", digest); + + if (SecKey_IsEcc(TestCreds::getKeyType(key)) == SEC_TRUE) { + if (sig.size() != SecSignature_GetEccSignatureSize(alg)) { + SEC_LOG_ERROR("Incorrect ECC signature size"); + return SEC_FALSE; + } + + EC_KEY* ec_key = TestCreds::asOpenSslEcKey(key); + if (ec_key == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslEcKey failed"); + return SEC_FALSE; + } + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + ECDSA_SIG esig; + esig.r = BN_new(); + esig.s = BN_new(); + BN_bin2bn(&sig[0], SEC_ECC_NISTP256_KEY_LEN, esig.r); + BN_bin2bn(&sig[SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN, esig.s); + int openssl_res = ECDSA_do_verify(&digest[0], static_cast(digest.size()), &esig, ec_key); + BN_free(esig.r); + BN_free(esig.s); +#else + ECDSA_SIG* esig = ECDSA_SIG_new(); + BIGNUM* r = BN_new(); + BIGNUM* s = BN_new(); + BN_bin2bn(&sig[0], SEC_ECC_NISTP256_KEY_LEN, r); + BN_bin2bn(&sig[SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN, s); + ECDSA_SIG_set0(esig, r, s); + int openssl_res = ECDSA_do_verify(&digest[0], static_cast(digest.size()), esig, ec_key); + ECDSA_SIG_free(esig); +#endif + SEC_ECC_FREE(ec_key); + + if (openssl_res != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("ECDSA_do_verify failed"); + return SEC_FALSE; + } + + return SEC_TRUE; + } + + EVP_PKEY* evp_pkey = TestCreds::asOpenSslEvpPkey(key); + if (evp_pkey == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslEvpPkey failed"); + return SEC_FALSE; + } + + EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(evp_pkey, nullptr); + if (ctx == nullptr) { + EVP_PKEY_free(evp_pkey); + SEC_LOG_ERROR("EVP_PKEY_CTX_new failed"); + return SEC_FALSE; + } + + if (EVP_PKEY_verify_init(ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding(ctx, pss ? RSA_PKCS1_PSS_PADDING : RSA_PKCS1_PADDING) <= 0 || + EVP_PKEY_CTX_set_signature_md(ctx, evp_md) <= 0) { + EVP_PKEY_free(evp_pkey); + EVP_PKEY_CTX_free(ctx); + SEC_LOG_ERROR("Could not setup EVP_PKEY_CTX"); + return SEC_FALSE; + } + + if (pss && EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, evp_md == EVP_sha1() ? 20 : 32) <= 0) { + EVP_PKEY_free(evp_pkey); + EVP_PKEY_CTX_free(ctx); + SEC_LOG_ERROR("Could not setup EVP_PKEY_CTX"); + return SEC_FALSE; + } + + if (EVP_PKEY_verify(ctx, &sig[0], sig.size(), &digest[0], digest.size()) <= 0) { + EVP_PKEY_free(evp_pkey); + EVP_PKEY_CTX_free(ctx); + SEC_LOG_ERROR("EVP_PKEY_verify failed"); + return SEC_FALSE; + } + + EVP_PKEY_free(evp_pkey); + EVP_PKEY_CTX_free(ctx); + + return SEC_TRUE; +} + +std::vector signSecApi(TestCtx* ctx, Sec_SignatureAlgorithm alg, Sec_KeyHandle* keyHandle, + const std::vector& input) { + + Sec_SignatureHandle* signatureHandle = ctx->acquireSignature(alg, SEC_SIGNATUREMODE_SIGN, keyHandle); + if (signatureHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireSignature failed"); + return {}; + } + + std::vector sig; + sig.resize(256); + SEC_SIZE sig_len; + + if (SecSignature_Process(signatureHandle, const_cast(&input[0]), input.size(), &sig[0], &sig_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_Process failed"); + return {}; + } + + sig.resize(sig_len); + + return sig; +} + +SEC_BOOL verifySecApi(TestCtx* ctx, Sec_SignatureAlgorithm alg, Sec_KeyHandle* keyHandle, + const std::vector& input, const std::vector& sig) { + + Sec_SignatureHandle* signatureHandle = ctx->acquireSignature(alg, SEC_SIGNATUREMODE_VERIFY, keyHandle); + if (signatureHandle == nullptr) { + SEC_LOG_ERROR("TestCtx::acquireSignature failed"); + return SEC_FALSE; + } + + SEC_SIZE sig_len = sig.size(); + + if (SecSignature_Process(signatureHandle, const_cast(&input[0]), input.size(), + const_cast(&sig[0]), &sig_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_Process failed"); + return SEC_FALSE; + } + + return SEC_TRUE; +} + +Sec_Result testSignature(SEC_OBJECTID id, TestKey pub, TestKey priv, TestKc kc, Sec_StorageLoc loc, + Sec_SignatureAlgorithm alg, Sec_SignatureMode mode, SEC_SIZE inputSize) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (mode == SEC_SIGNATUREMODE_SIGN && + (alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PKCS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PKCS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA1_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_RSA_SHA256_PSS_DIGEST || + alg == SEC_SIGNATUREALGORITHM_ECDSA_NISTP256_DIGEST)) { + SEC_LOG_ERROR("Signature digest is not supported in SecApi 3"); + return SEC_RESULT_SUCCESS; + } + //mode + bool testSign = (mode == SEC_SIGNATUREMODE_SIGN); + + Sec_KeyHandle* keyHandle; + if (testSign) { + if ((keyHandle = ctx.provisionKey(id, loc, priv, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + } else { + if ((keyHandle = ctx.provisionKey(id, loc, pub, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + } + + //gen clear input + std::vector clear = TestCtx::random(inputSize); + TestCtx::printHex("clear", clear); + + //sign + std::vector sig; + if (testSign) { + sig = signSecApi(&ctx, alg, keyHandle, clear); + } else { + //use openssl to sign + sig = signOpenSSL(alg, priv, clear); + } + + TestCtx::printHex("sig", sig); + + //verify + SEC_BOOL ver_res; + if (testSign) { + //use openssl to verify + if (kc == TESTKC_GENERATED) { + //extract pub from the generated key + Sec_ECCRawPublicKey eccPub; + if (SecKey_ExtractECCPublicKey(keyHandle, &eccPub) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractECCPublicKey failed"); + return SEC_RESULT_FAILURE; + } + + ver_res = verifyOpenSSLEccPub(alg, &eccPub, clear, sig); + } else { + ver_res = verifyOpenSSL(alg, pub, clear, sig); + } + } else { + //use sec api to verify + ver_res = verifySecApi(&ctx, alg, keyHandle, clear, sig); + } + + //check if results match + if (ver_res == SEC_FALSE) { + SEC_LOG_ERROR("Verification failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/sign.h b/test/main/cpp/sign.h new file mode 100644 index 0000000..ab5562a --- /dev/null +++ b/test/main/cpp/sign.h @@ -0,0 +1,34 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SIGN_H +#define SIGN_H + +#include "sec_security.h" +#include "test_creds.h" +#include + +std::vector signOpenSSL(Sec_SignatureAlgorithm alg, TestKey key, const std::vector& input); + +SEC_BOOL verifyOpenSSL(Sec_SignatureAlgorithm alg, TestKey key, const std::vector& input, + const std::vector& sig); + +Sec_Result testSignature(SEC_OBJECTID id, TestKey pub, TestKey priv, TestKc kc, Sec_StorageLoc loc, + Sec_SignatureAlgorithm alg, Sec_SignatureMode mode, SEC_SIZE inputSize); + +#endif // SIGN_H diff --git a/test/main/cpp/svp.cpp b/test/main/cpp/svp.cpp new file mode 100644 index 0000000..40aae1a --- /dev/null +++ b/test/main/cpp/svp.cpp @@ -0,0 +1,335 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "svp.h" +#include "cipher.h" +#include "test_ctx.h" + +#define MAX_BUFFER_SIZE (64 * 1024) + +Sec_Result testOpaqueMalloc() { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_OpaqueBufferHandle* opaqueBufferHandle = nullptr; + SEC_BYTE input[MAX_BUFFER_SIZE]; + + if (SecOpaqueBuffer_Malloc(sizeof(input), &opaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + return SEC_RESULT_FAILURE; + } + + if (SecOpaqueBuffer_Write(opaqueBufferHandle, 0, input, sizeof(input)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_OpaqueBufferWrite failed"); + return SEC_RESULT_FAILURE; + } + + if (SecOpaqueBuffer_Free(opaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_OpaqueBufferFree failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testSecureBootEnabled() { +// SecCodeIntegrity_SecureBootEnabled is an unimplemented feature +#if 0 + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (SecCodeIntegrity_SecureBootEnabled() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCodeIntegrity_SecureBootEnabled failed"); + return SEC_RESULT_FAILURE; + } +#endif + return SEC_RESULT_SUCCESS; +} + +Sec_Result testSetTime() { +// SecSVP_SetTime is an unimplemented feature +#if 0 + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (SecSVP_SetTime(time(nullptr)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSVP_SetTime failed"); + return SEC_RESULT_FAILURE; + } +#endif + return SEC_RESULT_SUCCESS; +} + +Sec_Result testKeycheckOpaque(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + Sec_CipherHandle* cipherHandle = nullptr; + if (SecCipher_GetInstance(ctx.proc(), SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, SEC_CIPHERMODE_DECRYPT, keyHandle, + nullptr, + &cipherHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + std::vector expected = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector input = opensslAesEcb(key, SEC_CIPHERMODE_ENCRYPT, SEC_FALSE, nullptr, expected); + + TestCtx::printHex("input", input); + TestCtx::printHex("expected", expected); + + Sec_OpaqueBufferHandle* opaqueBufferHandle = nullptr; + if (SecOpaqueBuffer_Malloc(256, &opaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SecCipher_Release(cipherHandle); + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + return SEC_RESULT_FAILURE; + } + + if (SecOpaqueBuffer_Write(opaqueBufferHandle, 0, &input[0], input.size()) != SEC_RESULT_SUCCESS) { + SecOpaqueBuffer_Free(opaqueBufferHandle); + SecCipher_Release(cipherHandle); + SEC_LOG_ERROR("Sec_OpaqueBufferWrite failed"); + return SEC_RESULT_FAILURE; + } + + if (SecCipher_KeyCheckOpaque(cipherHandle, opaqueBufferHandle, SEC_AES_BLOCK_SIZE, &expected[0]) != + SEC_RESULT_SUCCESS) { + SecOpaqueBuffer_Free(opaqueBufferHandle); + SecCipher_Release(cipherHandle); + SEC_LOG_ERROR("SecCipher_KeyCheckOpaque failed"); + return SEC_RESULT_FAILURE; + } + + /* 2.2 checks for 'checkLength' arg */ + if (SecCipher_KeyCheckOpaque(cipherHandle, opaqueBufferHandle, 8, &expected[0]) != SEC_RESULT_SUCCESS) { + SecOpaqueBuffer_Free(opaqueBufferHandle); + SecCipher_Release(cipherHandle); + SEC_LOG_ERROR("SecCipher_KeyCheckOpaque failed"); + return SEC_RESULT_FAILURE; + } + if (SecCipher_KeyCheckOpaque(cipherHandle, opaqueBufferHandle, 7, &expected[0]) == SEC_RESULT_SUCCESS) { + SecOpaqueBuffer_Free(opaqueBufferHandle); + SecCipher_Release(cipherHandle); + SEC_LOG_ERROR("Expected SecCipher_KeyCheckOpaque to fail with checkLength < 8"); + return SEC_RESULT_FAILURE; + } + if (SecCipher_KeyCheckOpaque(cipherHandle, opaqueBufferHandle, 17, &expected[0]) == SEC_RESULT_SUCCESS) { + SecOpaqueBuffer_Free(opaqueBufferHandle); + SecCipher_Release(cipherHandle); + SEC_LOG_ERROR("Expected SecCipher_KeyCheckOpaque to fail with checkLength > 16"); + return SEC_RESULT_FAILURE; + } + + SecOpaqueBuffer_Free(opaqueBufferHandle); + SecCipher_Release(cipherHandle); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testProcessOpaque(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm cipher_algorithm) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle* keyHandle; + if ((keyHandle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + Sec_CipherHandle* cipherHandle = nullptr; + if (SecCipher_GetInstance(ctx.proc(), cipher_algorithm, SEC_CIPHERMODE_DECRYPT, keyHandle, &iv[0], &cipherHandle) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + Sec_OpaqueBufferHandle* inOpaqueBufferHandle = nullptr; + if (SecOpaqueBuffer_Malloc(256, &inOpaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + SecCipher_Release(cipherHandle); + return SEC_RESULT_FAILURE; + } + + Sec_OpaqueBufferHandle* outOpaqueBufferHandle = nullptr; + if (SecOpaqueBuffer_Malloc(256, &outOpaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SecOpaqueBuffer_Free(outOpaqueBufferHandle); + SecCipher_Release(cipherHandle); + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + return SEC_RESULT_FAILURE; + } + + SEC_SIZE written = 0; + + if (SecCipher_ProcessOpaque(cipherHandle, inOpaqueBufferHandle, outOpaqueBufferHandle, 256, SEC_TRUE, &written) != + SEC_RESULT_SUCCESS) { + SecOpaqueBuffer_Free(inOpaqueBufferHandle); + SecOpaqueBuffer_Free(outOpaqueBufferHandle); + SecCipher_Release(cipherHandle); + SEC_LOG_ERROR("SecCipher_ProcessOpaque failed"); + return SEC_RESULT_FAILURE; + } + + SecOpaqueBuffer_Free(inOpaqueBufferHandle); + SecOpaqueBuffer_Free(outOpaqueBufferHandle); + SecCipher_Release(cipherHandle); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testCopyOpaque() { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_OpaqueBufferHandle* inOpaqueBufferHandle = nullptr; + if (SecOpaqueBuffer_Malloc(256, &inOpaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + return SEC_RESULT_FAILURE; + } + + Sec_OpaqueBufferHandle* outOpaqueBufferHandle = nullptr; + if (SecOpaqueBuffer_Malloc(256, &outOpaqueBufferHandle) != SEC_RESULT_SUCCESS) { + SecOpaqueBuffer_Free(inOpaqueBufferHandle); + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + return SEC_RESULT_FAILURE; + } + + SEC_BYTE tmp[128]; + if (SecOpaqueBuffer_Write(inOpaqueBufferHandle, 128, tmp, 128) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Write failed"); + SecOpaqueBuffer_Free(inOpaqueBufferHandle); + SecOpaqueBuffer_Free(outOpaqueBufferHandle); + return SEC_RESULT_FAILURE; + } + + if (SecOpaqueBuffer_Copy(outOpaqueBufferHandle, 0, inOpaqueBufferHandle, 128, 128) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecOpaqueBuffer_Copy failed"); + SecOpaqueBuffer_Free(inOpaqueBufferHandle); + SecOpaqueBuffer_Free(outOpaqueBufferHandle); + return SEC_RESULT_FAILURE; + } + + SecOpaqueBuffer_Free(inOpaqueBufferHandle); + SecOpaqueBuffer_Free(outOpaqueBufferHandle); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testProcessDataShiftOpaque(SEC_OBJECTID id, TestKey key, TestKc kc, + Sec_StorageLoc loc) { +// SecCipher_ProcessCtrWithOpaqueDataShift is an unimplemented feature. +#if 0 + TestCtx ctx; + Sec_Result result = SEC_RESULT_FAILURE; + Sec_OpaqueBufferHandle *inputHandle1 = nullptr; + Sec_OpaqueBufferHandle *inputHandle2 = nullptr; + Sec_OpaqueBufferHandle *outputHandle = nullptr; + SEC_SIZE written = 0; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyHandle *handle = nullptr; + if ((handle = ctx.provisionKey(id, loc, key, kc)) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + Sec_CipherHandle *cipherHandle = nullptr; + if (!= SEC_RESULT_SUCCESS) SecCipher_GetInstance(ctx.proc(), + SEC_CIPHERALGORITHM_AES_CTR, SEC_CIPHERMODE_DECRYPT, handle, + &iv[0], &cipherHandle)) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + break; + } + + if (SecOpaqueBuffer_Malloc(8, &inputHandle1) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + break; + } + + if (SecOpaqueBuffer_Malloc(256 - 8, &inputHandle2) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + break; + } + + if (SecOpaqueBuffer_Malloc(256, &outputHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("Sec_OpaqueBufferMalloc failed"); + break; + } + + if (!= SEC_RESULT_SUCCESS) SecCipher_ProcessOpaque(cipherHandle, + inputHandle1, outputHandle, 8, SEC_FALSE, &written)) { + SEC_LOG_ERROR("SecCipher_ProcessOpaque failed"); + break; + } + + if (!= SEC_RESULT_SUCCESS) + SecCipher_ProcessCtrWithOpaqueDataShift(cipherHandle, inputHandle2, outputHandle, 256 - 8, &written, 8)) { + SEC_LOG_ERROR("SecCipher_ProcessCtrWithOpaqueDataShift failed"); + break; + } + + + result = SEC_RESULT_SUCCESS; + + } while(false); + + + if (inputHandle1) + SecOpaqueBuffer_Free(inputHandle1); + if (inputHandle2) + SecOpaqueBuffer_Free(inputHandle2); + if (outputHandle) + SecOpaqueBuffer_Free(outputHandle); + if (cipherHandle) + SecCipher_Release(cipherHandle); + + return result; +#endif + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/svp.h b/test/main/cpp/svp.h new file mode 100644 index 0000000..fcd01f1 --- /dev/null +++ b/test/main/cpp/svp.h @@ -0,0 +1,41 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SVP_H +#define SVP_H + +#include "sec_security.h" +#include "test_creds.h" +#include + +Sec_Result testOpaqueMalloc(); + +Sec_Result testCopyOpaque(); + +Sec_Result testSecureBootEnabled(); + +Sec_Result testSetTime(); + +Sec_Result testKeycheckOpaque(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc); + +Sec_Result testProcessOpaque(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc, + Sec_CipherAlgorithm cipher_algorithm); + +Sec_Result testProcessDataShiftOpaque(SEC_OBJECTID id, TestKey key, TestKc kc, Sec_StorageLoc loc); + +#endif // SVP_H diff --git a/test/main/cpp/test_creds_clear.cpp b/test/main/cpp/test_creds_clear.cpp new file mode 100644 index 0000000..a5077a6 --- /dev/null +++ b/test/main/cpp/test_creds_clear.cpp @@ -0,0 +1,1303 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sec_adapter_utils.h" +#include "test_creds.h" +#include "test_ctx.h" +#include + +unsigned char sym128_a_bin[] = { + 0x05, 0xe8, 0x38, 0x84, 0xc4, 0x0c, 0x0a, 0xd8, 0x20, 0x79, 0x9e, 0xb5, 0x81, 0xf8, 0x74, 0x28}; + +unsigned int sym128_a_bin_len = 16; + +unsigned char sym160_a_bin[] = { + 0xaa, 0xbe, 0xf6, 0x0b, 0x97, 0x3a, 0x55, 0xc0, 0x3d, 0xa0, 0xdd, 0x85, 0xef, 0xb3, 0xbd, 0xc0, + 0x2f, 0x09, 0x32, 0x88}; + +unsigned int sym160_a_bin_len = 20; + +unsigned char sym256_a_bin[] = { + 0x6f, 0x08, 0x2b, 0xb5, 0xa9, 0xb9, 0x27, 0x3b, 0xd5, 0x4b, 0xaf, 0xfb, 0xe9, 0x63, 0xc7, 0xd2, + 0xad, 0xde, 0xf1, 0x68, 0x87, 0x07, 0xdb, 0xc5, 0xbf, 0x7c, 0x2b, 0x33, 0x5f, 0x29, 0x99, 0x44}; + +unsigned int sym256_a_bin_len = 32; + +unsigned char rsa1024_der[] = { + 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xc4, 0x32, 0x70, 0x15, 0xb3, + 0x53, 0xd5, 0xaf, 0x26, 0xc2, 0xcd, 0x6e, 0x87, 0x9f, 0x13, 0x10, 0x9e, 0x3d, 0x8d, 0x6c, 0xb4, + 0x1e, 0xc8, 0xbb, 0xf1, 0xbf, 0x7a, 0xc0, 0xce, 0xbf, 0x5c, 0x00, 0x1f, 0x83, 0xd8, 0xe3, 0xf7, + 0xe8, 0xa3, 0x79, 0x61, 0xd4, 0x3a, 0xae, 0x49, 0x6d, 0x38, 0x1d, 0x12, 0x74, 0xba, 0x9c, 0xb4, + 0x38, 0x61, 0x6b, 0x44, 0x1d, 0xac, 0xf7, 0xa7, 0x7d, 0x8a, 0x80, 0x9f, 0x56, 0x67, 0xb2, 0xe5, + 0x45, 0xbc, 0x0d, 0xde, 0xde, 0x63, 0x06, 0x13, 0x4d, 0x06, 0x2e, 0xe2, 0xf9, 0xfa, 0xe4, 0x3b, + 0xa6, 0xa0, 0x49, 0xbb, 0x11, 0x23, 0xf8, 0x68, 0x85, 0x3c, 0x1b, 0x92, 0xe1, 0x6c, 0x42, 0x37, + 0xe3, 0x1b, 0x7c, 0x7a, 0x25, 0x91, 0x30, 0xd5, 0xa5, 0xf3, 0xbb, 0x91, 0x23, 0xdf, 0x23, 0x94, + 0xb8, 0xf2, 0x61, 0x4f, 0xba, 0x73, 0xd1, 0x4b, 0x2b, 0x89, 0x8f, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x81, 0x00, 0x8c, 0x8d, 0xad, 0xaa, 0x7e, 0x2b, 0xe2, 0xfb, 0x75, 0x83, 0x3c, 0xf4, + 0xa0, 0x08, 0x1f, 0xfa, 0x59, 0xc2, 0xb2, 0xdc, 0x5b, 0x35, 0x6a, 0x8c, 0xea, 0x25, 0x48, 0xe5, + 0x73, 0xb7, 0xb7, 0x4b, 0x07, 0x48, 0xc7, 0x4a, 0x99, 0xc1, 0x79, 0xcb, 0x6d, 0x80, 0x43, 0x01, + 0xb4, 0xec, 0x9f, 0xb4, 0x84, 0x12, 0x47, 0xd6, 0x17, 0x6e, 0x04, 0xac, 0x79, 0xc1, 0xe0, 0xb6, + 0x12, 0xb1, 0x67, 0x54, 0x77, 0xa2, 0xd4, 0x80, 0xf2, 0x87, 0xb9, 0x56, 0xcc, 0xde, 0xc2, 0x52, + 0x09, 0x2d, 0x5b, 0x7b, 0x0e, 0xfa, 0xe2, 0xd8, 0x9e, 0x41, 0xaf, 0xfc, 0x42, 0x0d, 0x24, 0x6c, + 0xe2, 0x8b, 0x3a, 0xae, 0x5c, 0x17, 0x11, 0xbb, 0x33, 0x13, 0xb8, 0x66, 0xd6, 0xc6, 0xb1, 0x2f, + 0xef, 0xf0, 0x68, 0x0e, 0x2c, 0xf9, 0x41, 0xd2, 0x7f, 0xe0, 0x15, 0xe2, 0x33, 0xf5, 0xd8, 0xb6, + 0x01, 0xb0, 0x64, 0x91, 0x02, 0x41, 0x00, 0xf3, 0x37, 0x23, 0xf9, 0xff, 0x24, 0x37, 0x63, 0x10, + 0x19, 0x6f, 0x6c, 0x35, 0xa0, 0x41, 0x3c, 0x2c, 0x00, 0xa8, 0x71, 0xa9, 0x09, 0x0e, 0x1f, 0xc7, + 0x87, 0x6e, 0x67, 0xf3, 0x8a, 0x76, 0x5f, 0xfb, 0x69, 0x44, 0x22, 0x88, 0x36, 0x1d, 0x31, 0xb9, + 0x79, 0xd3, 0x8c, 0x92, 0xb4, 0x0c, 0x0b, 0x72, 0xdd, 0x62, 0x47, 0x86, 0xd7, 0x7d, 0x63, 0xb1, + 0xe3, 0x30, 0xb4, 0x8f, 0x89, 0x63, 0x3b, 0x02, 0x41, 0x00, 0xce, 0x82, 0x96, 0xa8, 0x5c, 0x6a, + 0x8a, 0x50, 0x31, 0xf1, 0x9c, 0xe3, 0xaa, 0x0d, 0x89, 0xe4, 0xe2, 0x68, 0xe2, 0x25, 0xf7, 0xec, + 0x5e, 0xe8, 0xde, 0x68, 0x29, 0x84, 0xf2, 0x58, 0x68, 0xa8, 0xb3, 0x1b, 0x36, 0x68, 0x7c, 0x2d, + 0x21, 0xea, 0x92, 0xb5, 0x3a, 0x80, 0xc2, 0x45, 0xbb, 0xc4, 0xfc, 0x38, 0xb0, 0x33, 0xe2, 0xf1, + 0x93, 0x83, 0x48, 0x5d, 0x91, 0x31, 0xc4, 0x55, 0x65, 0xbd, 0x02, 0x40, 0x0e, 0x66, 0x2d, 0x53, + 0x17, 0xaf, 0xe5, 0x37, 0x90, 0x34, 0x71, 0x4c, 0x4e, 0xc0, 0x76, 0x1c, 0x41, 0xde, 0xa8, 0x1a, + 0x52, 0x8f, 0x9e, 0xae, 0x72, 0xf9, 0xa9, 0xa7, 0xad, 0xdb, 0x7c, 0xb6, 0xa2, 0x03, 0xd1, 0x6c, + 0xd9, 0xf3, 0x9a, 0x36, 0xdf, 0x6c, 0x3f, 0x02, 0x0b, 0x8d, 0x6d, 0x49, 0x20, 0x3b, 0xcb, 0x1d, + 0xc0, 0xf5, 0xf1, 0x0e, 0x7d, 0xf1, 0x9d, 0x68, 0x93, 0x36, 0xe7, 0x11, 0x02, 0x40, 0x4c, 0x12, + 0x93, 0x09, 0x26, 0x32, 0x21, 0x0d, 0x75, 0xb8, 0x79, 0x80, 0xec, 0x4d, 0xdc, 0x74, 0x32, 0x6b, + 0x4c, 0x93, 0x8c, 0x06, 0xc8, 0xd7, 0xa3, 0xc6, 0x5f, 0x35, 0x18, 0x49, 0x35, 0x14, 0xa0, 0x15, + 0xf0, 0x2f, 0x01, 0x3f, 0x66, 0xf5, 0x10, 0x62, 0x2e, 0x50, 0xec, 0x3f, 0xdf, 0xf1, 0xaa, 0xaf, + 0xff, 0x48, 0xbd, 0xdb, 0x1b, 0xea, 0x0a, 0xa8, 0x5d, 0x2a, 0x26, 0x17, 0x07, 0x49, 0x02, 0x41, + 0x00, 0xb6, 0xc4, 0x4b, 0x68, 0x82, 0xe8, 0x40, 0xc0, 0x70, 0x58, 0xdb, 0x68, 0x49, 0x30, 0x7d, + 0x6a, 0xf1, 0xfc, 0x9d, 0x66, 0x33, 0x10, 0x28, 0x1b, 0x54, 0x1d, 0x81, 0xf1, 0x88, 0x9a, 0x6b, + 0xb7, 0x1b, 0x7f, 0x36, 0x79, 0xce, 0x02, 0xec, 0x7c, 0x7e, 0x71, 0x37, 0x05, 0x46, 0x33, 0xee, + 0x3d, 0x71, 0x8f, 0xb6, 0x16, 0x6c, 0xa6, 0x64, 0xa9, 0xe4, 0x04, 0xc8, 0x12, 0xd7, 0x14, 0xcf, + 0xed}; + +unsigned int rsa1024_der_len = 609; + +unsigned char rsa1024_pub_der[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc4, 0x32, 0x70, + 0x15, 0xb3, 0x53, 0xd5, 0xaf, 0x26, 0xc2, 0xcd, 0x6e, 0x87, 0x9f, 0x13, 0x10, 0x9e, 0x3d, 0x8d, + 0x6c, 0xb4, 0x1e, 0xc8, 0xbb, 0xf1, 0xbf, 0x7a, 0xc0, 0xce, 0xbf, 0x5c, 0x00, 0x1f, 0x83, 0xd8, + 0xe3, 0xf7, 0xe8, 0xa3, 0x79, 0x61, 0xd4, 0x3a, 0xae, 0x49, 0x6d, 0x38, 0x1d, 0x12, 0x74, 0xba, + 0x9c, 0xb4, 0x38, 0x61, 0x6b, 0x44, 0x1d, 0xac, 0xf7, 0xa7, 0x7d, 0x8a, 0x80, 0x9f, 0x56, 0x67, + 0xb2, 0xe5, 0x45, 0xbc, 0x0d, 0xde, 0xde, 0x63, 0x06, 0x13, 0x4d, 0x06, 0x2e, 0xe2, 0xf9, 0xfa, + 0xe4, 0x3b, 0xa6, 0xa0, 0x49, 0xbb, 0x11, 0x23, 0xf8, 0x68, 0x85, 0x3c, 0x1b, 0x92, 0xe1, 0x6c, + 0x42, 0x37, 0xe3, 0x1b, 0x7c, 0x7a, 0x25, 0x91, 0x30, 0xd5, 0xa5, 0xf3, 0xbb, 0x91, 0x23, 0xdf, + 0x23, 0x94, 0xb8, 0xf2, 0x61, 0x4f, 0xba, 0x73, 0xd1, 0x4b, 0x2b, 0x89, 0x8f, 0x02, 0x03, 0x01, + 0x00, 0x01}; + +unsigned int rsa1024_pub_der_len = 162; + +unsigned char rsa2048_der[] = { + 0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xf2, 0x6a, 0x52, 0xa0, + 0x96, 0xc5, 0xb7, 0x86, 0x6f, 0xc4, 0x35, 0x39, 0x5e, 0x28, 0xd3, 0xa6, 0xab, 0x80, 0x6a, 0xbb, + 0x07, 0x10, 0x74, 0xea, 0xe0, 0xfc, 0xef, 0x54, 0xb0, 0x5e, 0x66, 0x34, 0x21, 0x89, 0x35, 0x09, + 0xb7, 0x46, 0xf8, 0xb6, 0xf8, 0x86, 0xc0, 0x55, 0xc6, 0xc5, 0x2e, 0x36, 0xcc, 0xb7, 0x24, 0x5e, + 0x56, 0xba, 0x2b, 0x8d, 0xfb, 0x8d, 0x7b, 0xe1, 0x4b, 0x9e, 0xdf, 0x08, 0x5c, 0xb2, 0x28, 0xc0, + 0x79, 0x45, 0xd1, 0xf3, 0x9c, 0x70, 0xd8, 0xaf, 0x50, 0x1c, 0xc3, 0x10, 0x24, 0x84, 0xc1, 0xb1, + 0x36, 0x3f, 0xd4, 0xbf, 0x10, 0x18, 0xf9, 0xd0, 0x72, 0xea, 0xce, 0xbf, 0x34, 0x8e, 0xb5, 0x97, + 0xcb, 0x8a, 0x5e, 0x8e, 0x7d, 0xed, 0x1f, 0xe3, 0xa9, 0xde, 0x5b, 0x3f, 0xc9, 0x33, 0x4c, 0x9b, + 0x3e, 0xd8, 0x29, 0x61, 0x6b, 0x30, 0xba, 0xa1, 0x36, 0xbd, 0x22, 0x33, 0xa1, 0x25, 0x73, 0xab, + 0x5f, 0x6f, 0x35, 0x48, 0xf1, 0xad, 0x96, 0x5f, 0x0d, 0x0c, 0xe5, 0xe9, 0x8d, 0xf9, 0xed, 0x0c, + 0xcf, 0x50, 0x3c, 0x24, 0x34, 0x9b, 0x9e, 0xbc, 0xf9, 0xfa, 0x19, 0x51, 0x37, 0x03, 0x5c, 0xd0, + 0x25, 0x1f, 0xe6, 0xb2, 0xf7, 0xff, 0x96, 0xb0, 0x61, 0x42, 0xbb, 0xc5, 0x64, 0x5f, 0x3d, 0xaf, + 0x6f, 0x14, 0xcc, 0x92, 0x74, 0x6a, 0x06, 0xfa, 0xb2, 0xd9, 0xe1, 0x4d, 0x42, 0x76, 0xab, 0x88, + 0xe3, 0x08, 0xa2, 0xad, 0x00, 0xb6, 0xf7, 0x78, 0x0c, 0xba, 0x08, 0x71, 0xbc, 0x8d, 0x98, 0x43, + 0x12, 0x63, 0x8d, 0x5e, 0x1f, 0x49, 0xb9, 0x5f, 0x0d, 0x55, 0x1a, 0x90, 0x63, 0x4c, 0xd8, 0xe8, + 0x0b, 0x9f, 0x3d, 0x10, 0xb4, 0xf9, 0x1b, 0x44, 0x3f, 0x43, 0xad, 0x35, 0x42, 0x3d, 0x3d, 0x21, + 0x8e, 0xa8, 0x08, 0x28, 0x47, 0x19, 0x14, 0x28, 0x1c, 0x95, 0xb7, 0x5d, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x02, 0x82, 0x01, 0x00, 0x17, 0xd3, 0x1d, 0x45, 0xcd, 0x2b, 0xa7, 0x6a, 0xde, 0x07, 0x31, + 0x97, 0xee, 0xca, 0x22, 0x6b, 0x0a, 0x05, 0xf7, 0xf7, 0x63, 0xad, 0x59, 0x60, 0x50, 0x36, 0x6b, + 0xab, 0x2e, 0x1e, 0x48, 0xfb, 0x2c, 0xa4, 0x98, 0x82, 0xd8, 0xf1, 0x6f, 0xb6, 0x43, 0xdc, 0xb2, + 0x80, 0x7b, 0xa5, 0x9b, 0x72, 0x25, 0x52, 0x86, 0x8f, 0x83, 0x04, 0x8f, 0x0d, 0x48, 0x40, 0xd2, + 0x81, 0x04, 0xf6, 0x9b, 0x42, 0xee, 0x21, 0x50, 0x62, 0x02, 0x49, 0x3b, 0x66, 0x2e, 0xe4, 0xe4, + 0x56, 0xee, 0x8f, 0xb5, 0x18, 0x1c, 0x0e, 0xb4, 0x1e, 0x9f, 0x8f, 0x4c, 0x70, 0x6e, 0xbb, 0x95, + 0xa9, 0xc7, 0xf1, 0x8d, 0xda, 0x3a, 0xe7, 0x1f, 0xaf, 0xc8, 0x80, 0x53, 0xe4, 0xbb, 0x39, 0x97, + 0xdd, 0xbf, 0x2f, 0x2c, 0x56, 0xab, 0x86, 0x90, 0x2b, 0xdd, 0xd4, 0x4e, 0xd4, 0xd5, 0x3d, 0x17, + 0xca, 0x8a, 0x5f, 0xb2, 0x41, 0xa1, 0xc6, 0x52, 0x80, 0xe5, 0xf0, 0x7a, 0xda, 0x35, 0xa5, 0x36, + 0xb9, 0x61, 0x15, 0x60, 0x39, 0x2f, 0x04, 0x1f, 0x6e, 0xee, 0x99, 0xee, 0xa5, 0x21, 0xcc, 0x4f, + 0xa3, 0x4e, 0x06, 0xc5, 0xbc, 0xa5, 0x34, 0xd6, 0x10, 0x57, 0x36, 0x85, 0xf7, 0x0a, 0x34, 0xfb, + 0xa5, 0x6b, 0x71, 0x9c, 0x4a, 0x43, 0x4a, 0xd0, 0xcb, 0xb4, 0x9a, 0xac, 0x4f, 0x9a, 0x29, 0xe8, + 0x68, 0x15, 0x00, 0xe4, 0x6c, 0x34, 0xc3, 0x73, 0x7e, 0xb5, 0x16, 0x2a, 0x17, 0x37, 0xc0, 0xb6, + 0xaf, 0x81, 0xb4, 0x73, 0xf2, 0xd3, 0x9f, 0xaa, 0x40, 0x73, 0x28, 0x0d, 0xfd, 0xb4, 0x67, 0x6e, + 0x82, 0xa8, 0x13, 0x34, 0xc0, 0x54, 0x88, 0xaf, 0x85, 0x6f, 0xd8, 0x33, 0x84, 0x82, 0xb5, 0xd0, + 0x5f, 0x7f, 0x21, 0xca, 0x6d, 0x86, 0x74, 0xb3, 0x89, 0x81, 0x19, 0x45, 0x47, 0x38, 0x41, 0x53, + 0x47, 0x86, 0xc6, 0xcd, 0x9d, 0x02, 0x81, 0x81, 0x00, 0xfd, 0x90, 0x23, 0xf9, 0xba, 0xc5, 0x69, + 0x7d, 0x11, 0xed, 0x69, 0x57, 0x73, 0x1d, 0x06, 0xe8, 0x1b, 0x37, 0x00, 0x69, 0x95, 0xc5, 0x63, + 0x86, 0x3f, 0xda, 0xb4, 0x11, 0xad, 0x69, 0x55, 0xf4, 0x76, 0x3c, 0xa0, 0x95, 0x65, 0x60, 0x29, + 0xb9, 0x69, 0x79, 0xca, 0x74, 0x50, 0xe3, 0x98, 0xc7, 0x90, 0xd7, 0xb8, 0xd4, 0xc5, 0x51, 0x10, + 0xa3, 0x10, 0x72, 0xf3, 0xdc, 0x91, 0xb4, 0xee, 0xdd, 0x9a, 0x57, 0xf1, 0x1b, 0x0e, 0xba, 0x0f, + 0x67, 0x1a, 0x94, 0x86, 0x36, 0x69, 0x20, 0xd5, 0x6b, 0x80, 0x50, 0x7d, 0x20, 0x53, 0xeb, 0xed, + 0x8a, 0xc5, 0xbc, 0xcb, 0x13, 0xb9, 0x0d, 0x49, 0x22, 0x7c, 0xeb, 0xa6, 0x97, 0x5a, 0x5b, 0x92, + 0x3a, 0x3d, 0x93, 0x5b, 0x86, 0x2c, 0x75, 0x0b, 0xfa, 0x68, 0xa6, 0xc1, 0x68, 0x07, 0x37, 0x01, + 0x9b, 0xd1, 0x51, 0xfe, 0xc0, 0x4c, 0x2d, 0x15, 0x9f, 0x02, 0x81, 0x81, 0x00, 0xf4, 0xbe, 0xc1, + 0x32, 0xad, 0xca, 0x28, 0x37, 0x7c, 0x17, 0x99, 0xde, 0x64, 0x9b, 0xc1, 0xf8, 0x23, 0x6a, 0xde, + 0xd8, 0x01, 0x59, 0x09, 0x10, 0x67, 0xb8, 0x27, 0xc5, 0xe6, 0xee, 0xf8, 0x16, 0x7c, 0x46, 0xa0, + 0x0b, 0x00, 0xf9, 0xff, 0x72, 0x4b, 0xde, 0x65, 0x65, 0xb6, 0xaa, 0x44, 0x1a, 0xbc, 0xdf, 0x13, + 0x15, 0x08, 0x80, 0xa5, 0xb4, 0xdd, 0xcd, 0xe0, 0x34, 0x4a, 0x85, 0x31, 0x82, 0x17, 0x57, 0x5a, + 0xea, 0x21, 0x38, 0x26, 0xdf, 0x48, 0x59, 0x1d, 0x58, 0x5b, 0x9f, 0x04, 0x12, 0xee, 0x5b, 0xa2, + 0xa9, 0xb3, 0xfe, 0x83, 0xa7, 0xda, 0x47, 0xc6, 0xfb, 0x89, 0x77, 0x1f, 0x3a, 0xbc, 0x7c, 0xc7, + 0x13, 0xc9, 0xb8, 0xdc, 0xb0, 0x9e, 0xa7, 0x2a, 0xa5, 0x2c, 0x3b, 0x96, 0xe2, 0x2e, 0xc0, 0xcf, + 0xfa, 0x0c, 0xe0, 0x2d, 0xad, 0xaa, 0x7f, 0x85, 0x4b, 0x6f, 0x04, 0xf9, 0x83, 0x02, 0x81, 0x81, + 0x00, 0xca, 0x8f, 0xd2, 0xdd, 0x96, 0xc2, 0x4c, 0x52, 0x58, 0xf7, 0x03, 0x77, 0x94, 0x03, 0x75, + 0x58, 0x09, 0x1d, 0xb8, 0x5b, 0xa1, 0x05, 0x4e, 0x4b, 0x9a, 0x49, 0x5a, 0x1e, 0xe1, 0x1c, 0xcc, + 0x48, 0xfe, 0x07, 0xd2, 0xf5, 0x66, 0x46, 0x1b, 0x2e, 0xfe, 0xbf, 0x07, 0xe8, 0x42, 0x12, 0x80, + 0x23, 0xb5, 0x67, 0x50, 0x45, 0xd1, 0xd7, 0xbf, 0xe5, 0xb4, 0xa7, 0x50, 0x7f, 0x3d, 0x7b, 0x80, + 0x73, 0x51, 0xf0, 0xbd, 0x31, 0x33, 0x63, 0x9a, 0x18, 0x70, 0xd8, 0x84, 0x1b, 0x85, 0x82, 0x70, + 0x5c, 0x6f, 0xe6, 0x5c, 0xff, 0x6d, 0x6b, 0x85, 0x99, 0x9d, 0xfc, 0x03, 0x73, 0x9f, 0x1a, 0xa8, + 0xf9, 0x3f, 0x38, 0x76, 0x1e, 0x65, 0x55, 0xd0, 0x0c, 0x6c, 0xd2, 0x82, 0x84, 0x3e, 0x91, 0xc6, + 0xde, 0xe5, 0xa9, 0x89, 0xca, 0x54, 0x31, 0x32, 0x3c, 0xcb, 0x4c, 0xa8, 0xa9, 0xf0, 0x70, 0xf7, + 0xdb, 0x02, 0x81, 0x80, 0x62, 0x16, 0xd9, 0xa3, 0x90, 0x17, 0x87, 0x8a, 0xc5, 0x47, 0x48, 0x39, + 0xe3, 0xa4, 0xb1, 0x56, 0xdc, 0x0b, 0x07, 0x09, 0x17, 0x71, 0x31, 0xba, 0xcb, 0x76, 0xf9, 0x29, + 0xcd, 0xe6, 0x54, 0xb3, 0xde, 0x57, 0x07, 0xe9, 0xa1, 0x18, 0x91, 0x12, 0xa3, 0xe9, 0x9c, 0x45, + 0xe9, 0xb1, 0xcf, 0xdd, 0xcf, 0x78, 0xb0, 0x53, 0x2b, 0xb7, 0x33, 0xb2, 0x8b, 0x7a, 0xe9, 0xb2, + 0xcb, 0x73, 0x1a, 0x66, 0x83, 0x28, 0x55, 0x9d, 0xa4, 0x76, 0xb6, 0xcd, 0xa2, 0x57, 0x64, 0xf5, + 0x76, 0xb3, 0x02, 0x94, 0xfb, 0xc6, 0xea, 0x28, 0x8d, 0xa5, 0x21, 0xea, 0xf2, 0x06, 0xf6, 0x6e, + 0xf5, 0xa7, 0x32, 0x72, 0xfd, 0xfc, 0x1c, 0x65, 0x87, 0xe1, 0x79, 0x41, 0xa8, 0x34, 0x63, 0x59, + 0x13, 0xa3, 0x46, 0x53, 0x9c, 0x5d, 0x56, 0x7d, 0x67, 0x0f, 0xa9, 0xff, 0x02, 0x68, 0x5d, 0x69, + 0xe0, 0x32, 0xe4, 0x35, 0x02, 0x81, 0x80, 0x55, 0xf8, 0x25, 0x84, 0x94, 0xad, 0x50, 0xab, 0x49, + 0x38, 0x30, 0xaf, 0xde, 0x53, 0xdc, 0x27, 0x08, 0x25, 0x27, 0x5a, 0xd2, 0xe5, 0x21, 0x50, 0xde, + 0x6d, 0x6b, 0xc7, 0x17, 0xae, 0x21, 0xb6, 0xcb, 0xe9, 0x24, 0x7c, 0x76, 0x32, 0xe3, 0xcb, 0xba, + 0xee, 0x61, 0xd2, 0x79, 0xf2, 0x88, 0x12, 0x1c, 0x9f, 0x29, 0xb3, 0x6a, 0x73, 0x16, 0xfc, 0x35, + 0xcf, 0xe7, 0x68, 0xec, 0x47, 0xf7, 0xfb, 0x2d, 0x18, 0xff, 0xa8, 0xbf, 0xe1, 0xe8, 0x64, 0xa0, + 0x98, 0x4a, 0x70, 0x07, 0x5d, 0xb1, 0x8e, 0x6e, 0x15, 0x4e, 0x0d, 0x28, 0x61, 0xb1, 0x37, 0x21, + 0xcb, 0xba, 0x1d, 0x1b, 0xff, 0x06, 0x9f, 0xbe, 0xbc, 0xa9, 0x93, 0x77, 0x07, 0xc1, 0xc0, 0x1a, + 0x4b, 0x13, 0xee, 0xa3, 0xdb, 0x7e, 0x99, 0x94, 0xcc, 0x5b, 0x88, 0xfb, 0xb9, 0x77, 0x3c, 0x81, + 0x80, 0x5d, 0xef, 0x3e, 0xf8, 0x6e, 0xfa}; + +unsigned int rsa2048_der_len = 1191; + +unsigned char rsa2048_pub_der[] = { + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xf2, 0x6a, 0x52, 0xa0, 0x96, 0xc5, 0xb7, 0x86, 0x6f, 0xc4, 0x35, 0x39, 0x5e, 0x28, 0xd3, + 0xa6, 0xab, 0x80, 0x6a, 0xbb, 0x07, 0x10, 0x74, 0xea, 0xe0, 0xfc, 0xef, 0x54, 0xb0, 0x5e, 0x66, + 0x34, 0x21, 0x89, 0x35, 0x09, 0xb7, 0x46, 0xf8, 0xb6, 0xf8, 0x86, 0xc0, 0x55, 0xc6, 0xc5, 0x2e, + 0x36, 0xcc, 0xb7, 0x24, 0x5e, 0x56, 0xba, 0x2b, 0x8d, 0xfb, 0x8d, 0x7b, 0xe1, 0x4b, 0x9e, 0xdf, + 0x08, 0x5c, 0xb2, 0x28, 0xc0, 0x79, 0x45, 0xd1, 0xf3, 0x9c, 0x70, 0xd8, 0xaf, 0x50, 0x1c, 0xc3, + 0x10, 0x24, 0x84, 0xc1, 0xb1, 0x36, 0x3f, 0xd4, 0xbf, 0x10, 0x18, 0xf9, 0xd0, 0x72, 0xea, 0xce, + 0xbf, 0x34, 0x8e, 0xb5, 0x97, 0xcb, 0x8a, 0x5e, 0x8e, 0x7d, 0xed, 0x1f, 0xe3, 0xa9, 0xde, 0x5b, + 0x3f, 0xc9, 0x33, 0x4c, 0x9b, 0x3e, 0xd8, 0x29, 0x61, 0x6b, 0x30, 0xba, 0xa1, 0x36, 0xbd, 0x22, + 0x33, 0xa1, 0x25, 0x73, 0xab, 0x5f, 0x6f, 0x35, 0x48, 0xf1, 0xad, 0x96, 0x5f, 0x0d, 0x0c, 0xe5, + 0xe9, 0x8d, 0xf9, 0xed, 0x0c, 0xcf, 0x50, 0x3c, 0x24, 0x34, 0x9b, 0x9e, 0xbc, 0xf9, 0xfa, 0x19, + 0x51, 0x37, 0x03, 0x5c, 0xd0, 0x25, 0x1f, 0xe6, 0xb2, 0xf7, 0xff, 0x96, 0xb0, 0x61, 0x42, 0xbb, + 0xc5, 0x64, 0x5f, 0x3d, 0xaf, 0x6f, 0x14, 0xcc, 0x92, 0x74, 0x6a, 0x06, 0xfa, 0xb2, 0xd9, 0xe1, + 0x4d, 0x42, 0x76, 0xab, 0x88, 0xe3, 0x08, 0xa2, 0xad, 0x00, 0xb6, 0xf7, 0x78, 0x0c, 0xba, 0x08, + 0x71, 0xbc, 0x8d, 0x98, 0x43, 0x12, 0x63, 0x8d, 0x5e, 0x1f, 0x49, 0xb9, 0x5f, 0x0d, 0x55, 0x1a, + 0x90, 0x63, 0x4c, 0xd8, 0xe8, 0x0b, 0x9f, 0x3d, 0x10, 0xb4, 0xf9, 0x1b, 0x44, 0x3f, 0x43, 0xad, + 0x35, 0x42, 0x3d, 0x3d, 0x21, 0x8e, 0xa8, 0x08, 0x28, 0x47, 0x19, 0x14, 0x28, 0x1c, 0x95, 0xb7, + 0x5d, 0x02, 0x03, 0x01, 0x00, 0x01}; +unsigned int rsa2048_pub_der_len = 294; + +unsigned char rsa1024_cert_der[] = { + 0x30, 0x82, 0x02, 0xb4, 0x30, 0x82, 0x02, 0x1d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, + 0xc4, 0x52, 0xc1, 0x4a, 0x9e, 0x74, 0xe8, 0xa8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x73, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x08, 0x4d, 0x61, 0x72, 0x79, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x08, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x62, 0x69, 0x61, 0x31, 0x10, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x43, 0x6f, 0x6d, 0x63, 0x61, 0x73, 0x74, 0x31, 0x0f, + 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x06, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x31, + 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, + 0x2e, 0x63, 0x6f, 0x6d, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x35, 0x30, 0x36, 0x32, 0x33, 0x30, 0x33, 0x30, 0x35, 0x31, 0x36, 0x5a, 0x17, 0x0d, 0x31, + 0x35, 0x30, 0x37, 0x32, 0x33, 0x30, 0x33, 0x30, 0x35, 0x31, 0x36, 0x5a, 0x30, 0x73, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x4d, 0x61, 0x72, 0x79, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x62, 0x69, + 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x43, 0x6f, 0x6d, 0x63, + 0x61, 0x73, 0x74, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x06, 0x43, 0x6f, + 0x6e, 0x73, 0x65, 0x63, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x63, + 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x2e, 0x63, 0x6f, 0x6d, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc4, 0x32, + 0x70, 0x15, 0xb3, 0x53, 0xd5, 0xaf, 0x26, 0xc2, 0xcd, 0x6e, 0x87, 0x9f, 0x13, 0x10, 0x9e, 0x3d, + 0x8d, 0x6c, 0xb4, 0x1e, 0xc8, 0xbb, 0xf1, 0xbf, 0x7a, 0xc0, 0xce, 0xbf, 0x5c, 0x00, 0x1f, 0x83, + 0xd8, 0xe3, 0xf7, 0xe8, 0xa3, 0x79, 0x61, 0xd4, 0x3a, 0xae, 0x49, 0x6d, 0x38, 0x1d, 0x12, 0x74, + 0xba, 0x9c, 0xb4, 0x38, 0x61, 0x6b, 0x44, 0x1d, 0xac, 0xf7, 0xa7, 0x7d, 0x8a, 0x80, 0x9f, 0x56, + 0x67, 0xb2, 0xe5, 0x45, 0xbc, 0x0d, 0xde, 0xde, 0x63, 0x06, 0x13, 0x4d, 0x06, 0x2e, 0xe2, 0xf9, + 0xfa, 0xe4, 0x3b, 0xa6, 0xa0, 0x49, 0xbb, 0x11, 0x23, 0xf8, 0x68, 0x85, 0x3c, 0x1b, 0x92, 0xe1, + 0x6c, 0x42, 0x37, 0xe3, 0x1b, 0x7c, 0x7a, 0x25, 0x91, 0x30, 0xd5, 0xa5, 0xf3, 0xbb, 0x91, 0x23, + 0xdf, 0x23, 0x94, 0xb8, 0xf2, 0x61, 0x4f, 0xba, 0x73, 0xd1, 0x4b, 0x2b, 0x89, 0x8f, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0x76, 0x63, 0x9b, 0x06, 0xa5, 0x12, 0x26, 0xa5, 0x89, 0xc6, 0x6c, 0x57, 0x5b, 0x4a, + 0x3e, 0x47, 0xb0, 0xa4, 0x0b, 0x1a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x76, 0x63, 0x9b, 0x06, 0xa5, 0x12, 0x26, 0xa5, 0x89, 0xc6, 0x6c, 0x57, 0x5b, + 0x4a, 0x3e, 0x47, 0xb0, 0xa4, 0x0b, 0x1a, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, + 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x33, 0xbe, 0xfe, 0x79, 0xdb, 0x9b, 0xc2, 0x09, + 0xb8, 0x9c, 0x51, 0x6a, 0x2b, 0x5f, 0xe5, 0xc6, 0xc6, 0xd2, 0x72, 0x5d, 0x56, 0x24, 0xa1, 0xa5, + 0xac, 0x28, 0xbc, 0xba, 0x60, 0xb9, 0xd6, 0x30, 0x39, 0x4e, 0x89, 0xc9, 0x41, 0x89, 0x37, 0xf0, + 0xeb, 0xee, 0x09, 0x31, 0xb0, 0x34, 0xed, 0xf6, 0x8f, 0x70, 0xd3, 0x65, 0x81, 0x18, 0x1c, 0xbe, + 0xd0, 0x08, 0x94, 0x1d, 0x80, 0x92, 0x72, 0x8f, 0x16, 0xa4, 0xac, 0xf4, 0x7d, 0x1e, 0xe1, 0x8b, + 0xe7, 0x79, 0x26, 0x4b, 0xc8, 0x17, 0x3e, 0x19, 0xf5, 0x50, 0x07, 0xd0, 0x85, 0xb6, 0xeb, 0x56, + 0xff, 0xdb, 0xe2, 0x28, 0x42, 0x58, 0x52, 0xf3, 0xef, 0x6a, 0xf8, 0x86, 0xae, 0x9e, 0xa2, 0x7c, + 0xa2, 0xb7, 0x87, 0x90, 0x1b, 0x48, 0xdc, 0x7d, 0x2a, 0xf2, 0x0c, 0x55, 0xf3, 0x34, 0x79, 0xb3, + 0x87, 0x67, 0x18, 0x29, 0xc8, 0x3a, 0xc9, 0xe3}; +unsigned int rsa1024_cert_der_len = 696; + +unsigned char rsa2048_cert_der[] = { + 0x30, 0x82, 0x03, 0xb9, 0x30, 0x82, 0x02, 0xa1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, + 0xee, 0x91, 0x7a, 0x08, 0x9a, 0x55, 0x9f, 0x5f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x73, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x08, 0x4d, 0x61, 0x72, 0x79, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x08, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x62, 0x69, 0x61, 0x31, 0x0f, 0x30, 0x0d, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x43, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x31, 0x10, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x43, 0x6f, 0x6d, 0x63, 0x61, 0x73, 0x74, 0x31, + 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, + 0x2e, 0x63, 0x6f, 0x6d, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x35, 0x30, 0x36, 0x32, 0x33, 0x30, 0x33, 0x30, 0x36, 0x30, 0x37, 0x5a, 0x17, 0x0d, 0x31, + 0x35, 0x30, 0x37, 0x32, 0x33, 0x30, 0x33, 0x30, 0x36, 0x30, 0x37, 0x5a, 0x30, 0x73, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x4d, 0x61, 0x72, 0x79, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x62, 0x69, + 0x61, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x43, 0x6f, 0x6e, 0x73, + 0x65, 0x63, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x43, 0x6f, 0x6d, + 0x63, 0x61, 0x73, 0x74, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x63, + 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x2e, 0x63, 0x6f, 0x6d, 0x63, 0x61, 0x73, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xf2, 0x6a, 0x52, 0xa0, 0x96, 0xc5, 0xb7, 0x86, 0x6f, 0xc4, 0x35, 0x39, 0x5e, 0x28, + 0xd3, 0xa6, 0xab, 0x80, 0x6a, 0xbb, 0x07, 0x10, 0x74, 0xea, 0xe0, 0xfc, 0xef, 0x54, 0xb0, 0x5e, + 0x66, 0x34, 0x21, 0x89, 0x35, 0x09, 0xb7, 0x46, 0xf8, 0xb6, 0xf8, 0x86, 0xc0, 0x55, 0xc6, 0xc5, + 0x2e, 0x36, 0xcc, 0xb7, 0x24, 0x5e, 0x56, 0xba, 0x2b, 0x8d, 0xfb, 0x8d, 0x7b, 0xe1, 0x4b, 0x9e, + 0xdf, 0x08, 0x5c, 0xb2, 0x28, 0xc0, 0x79, 0x45, 0xd1, 0xf3, 0x9c, 0x70, 0xd8, 0xaf, 0x50, 0x1c, + 0xc3, 0x10, 0x24, 0x84, 0xc1, 0xb1, 0x36, 0x3f, 0xd4, 0xbf, 0x10, 0x18, 0xf9, 0xd0, 0x72, 0xea, + 0xce, 0xbf, 0x34, 0x8e, 0xb5, 0x97, 0xcb, 0x8a, 0x5e, 0x8e, 0x7d, 0xed, 0x1f, 0xe3, 0xa9, 0xde, + 0x5b, 0x3f, 0xc9, 0x33, 0x4c, 0x9b, 0x3e, 0xd8, 0x29, 0x61, 0x6b, 0x30, 0xba, 0xa1, 0x36, 0xbd, + 0x22, 0x33, 0xa1, 0x25, 0x73, 0xab, 0x5f, 0x6f, 0x35, 0x48, 0xf1, 0xad, 0x96, 0x5f, 0x0d, 0x0c, + 0xe5, 0xe9, 0x8d, 0xf9, 0xed, 0x0c, 0xcf, 0x50, 0x3c, 0x24, 0x34, 0x9b, 0x9e, 0xbc, 0xf9, 0xfa, + 0x19, 0x51, 0x37, 0x03, 0x5c, 0xd0, 0x25, 0x1f, 0xe6, 0xb2, 0xf7, 0xff, 0x96, 0xb0, 0x61, 0x42, + 0xbb, 0xc5, 0x64, 0x5f, 0x3d, 0xaf, 0x6f, 0x14, 0xcc, 0x92, 0x74, 0x6a, 0x06, 0xfa, 0xb2, 0xd9, + 0xe1, 0x4d, 0x42, 0x76, 0xab, 0x88, 0xe3, 0x08, 0xa2, 0xad, 0x00, 0xb6, 0xf7, 0x78, 0x0c, 0xba, + 0x08, 0x71, 0xbc, 0x8d, 0x98, 0x43, 0x12, 0x63, 0x8d, 0x5e, 0x1f, 0x49, 0xb9, 0x5f, 0x0d, 0x55, + 0x1a, 0x90, 0x63, 0x4c, 0xd8, 0xe8, 0x0b, 0x9f, 0x3d, 0x10, 0xb4, 0xf9, 0x1b, 0x44, 0x3f, 0x43, + 0xad, 0x35, 0x42, 0x3d, 0x3d, 0x21, 0x8e, 0xa8, 0x08, 0x28, 0x47, 0x19, 0x14, 0x28, 0x1c, 0x95, + 0xb7, 0x5d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf0, 0xe1, 0x4e, 0x26, 0x9b, 0xa4, 0xc8, 0x7c, 0x24, 0x2d, + 0xa2, 0xdc, 0x5e, 0x3e, 0xb8, 0x64, 0xb0, 0xb7, 0x3e, 0x96, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xf0, 0xe1, 0x4e, 0x26, 0x9b, 0xa4, 0xc8, 0x7c, 0x24, + 0x2d, 0xa2, 0xdc, 0x5e, 0x3e, 0xb8, 0x64, 0xb0, 0xb7, 0x3e, 0x96, 0x30, 0x0c, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x68, 0x60, 0x3a, + 0x9a, 0xcf, 0x75, 0x6c, 0x09, 0xab, 0x9a, 0x4a, 0x0d, 0x9b, 0xe4, 0x7f, 0xdc, 0x7a, 0xa9, 0xfa, + 0x06, 0xb4, 0xc4, 0xca, 0xcf, 0xa0, 0x38, 0x7f, 0xdf, 0xc2, 0x4d, 0x4a, 0x94, 0x82, 0x33, 0x83, + 0x9a, 0x7b, 0x9b, 0x84, 0xf7, 0xfd, 0xb3, 0x93, 0x22, 0xd0, 0xb2, 0x73, 0xa8, 0x54, 0x45, 0xb0, + 0x05, 0xac, 0x1a, 0xff, 0x60, 0x03, 0x54, 0xa7, 0x0d, 0xcb, 0x8d, 0xeb, 0x62, 0x59, 0xcb, 0x8b, + 0xfa, 0x7f, 0x8d, 0xd8, 0xa4, 0x64, 0x3a, 0x3e, 0xdc, 0x5d, 0xb9, 0xc0, 0x27, 0x50, 0xd0, 0x54, + 0x62, 0x1e, 0xe7, 0x7f, 0x66, 0xa8, 0xdf, 0xbc, 0x6a, 0x17, 0xf1, 0xcd, 0x45, 0x76, 0x34, 0xc3, + 0x6c, 0x6f, 0xac, 0x85, 0x50, 0xdc, 0xd4, 0xf0, 0xdd, 0x85, 0xfa, 0x75, 0x23, 0x45, 0x12, 0x90, + 0x0d, 0xf2, 0xc9, 0x43, 0x83, 0x4c, 0x97, 0xfd, 0x76, 0x64, 0xa8, 0x80, 0x15, 0x45, 0x4a, 0xa4, + 0x36, 0xc7, 0xa5, 0x12, 0x09, 0x4d, 0xc1, 0xdb, 0xc0, 0xbe, 0x58, 0x9b, 0x16, 0xe6, 0x6f, 0x63, + 0xed, 0x5c, 0x62, 0xd6, 0x23, 0xb0, 0x26, 0x46, 0xb1, 0x98, 0x5c, 0x94, 0x72, 0x86, 0x2f, 0x26, + 0xa1, 0x91, 0x68, 0x4a, 0x5c, 0x01, 0x8b, 0x44, 0x00, 0xea, 0xa4, 0x61, 0x85, 0x4b, 0xd4, 0xc3, + 0x50, 0x16, 0x97, 0xa4, 0x6f, 0x56, 0x2f, 0x2a, 0xf0, 0x6e, 0x3f, 0x35, 0x6e, 0xe5, 0x27, 0x3c, + 0x76, 0xa9, 0x91, 0x6b, 0x1f, 0x1e, 0x73, 0x82, 0x61, 0xcc, 0x06, 0x2d, 0xae, 0x12, 0x49, 0x66, + 0xa6, 0x86, 0x39, 0x65, 0x00, 0x77, 0x22, 0x92, 0x64, 0x9c, 0x12, 0x30, 0x24, 0x75, 0x8b, 0xd7, + 0x02, 0x7a, 0x5b, 0xbe, 0x15, 0xda, 0x0e, 0xac, 0x9c, 0xfe, 0xb1, 0xc8, 0x6c, 0x25, 0xf8, 0xea, + 0x0a, 0x69, 0x64, 0xb7, 0x5e, 0x60, 0x65, 0xba, 0x02, 0xe4, 0xf5, 0x66, 0x07}; + +unsigned int rsa2048_cert_der_len = 957; + +unsigned char ecc_der[] = { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x4d, 0xef, 0x8c, 0x19, 0x60, 0xf5, 0xd6, 0x78, 0x18, + 0x84, 0x4d, 0xe6, 0xe3, 0x2f, 0x19, 0x4f, 0xcd, 0x10, 0xc5, 0xfd, 0x55, 0x54, 0xc1, 0x7e, 0x95, + 0x4e, 0xbc, 0xe1, 0xba, 0xba, 0x56, 0xc6, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x7f, 0xd8, 0x8a, 0x21, 0x09, 0x41, 0xb2, + 0x02, 0x5b, 0x1d, 0xb0, 0x2e, 0xa5, 0x04, 0x6e, 0xae, 0xae, 0x21, 0xd8, 0x02, 0x8e, 0xaa, 0x3b, + 0x68, 0x03, 0x6e, 0x25, 0xd6, 0x2c, 0x08, 0xff, 0xa6, 0x13, 0x5a, 0x8c, 0x14, 0xe0, 0x93, 0x66, + 0xa2, 0x25, 0x46, 0x75, 0x8f, 0xd6, 0x87, 0x79, 0xb4, 0xc2, 0x62, 0x7e, 0xa8, 0xed, 0x45, 0xb1, + 0xe5, 0x91, 0xb6, 0x2b, 0xd4, 0x2a, 0xbb, 0x2d, 0x94}; + +unsigned int ecc_der_len = 121; + +unsigned char ecc_pub_der[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x7f, 0xd8, 0x8a, 0x21, 0x09, + 0x41, 0xb2, 0x02, 0x5b, 0x1d, 0xb0, 0x2e, 0xa5, 0x04, 0x6e, 0xae, 0xae, 0x21, 0xd8, 0x02, 0x8e, + 0xaa, 0x3b, 0x68, 0x03, 0x6e, 0x25, 0xd6, 0x2c, 0x08, 0xff, 0xa6, 0x13, 0x5a, 0x8c, 0x14, 0xe0, + 0x93, 0x66, 0xa2, 0x25, 0x46, 0x75, 0x8f, 0xd6, 0x87, 0x79, 0xb4, 0xc2, 0x62, 0x7e, 0xa8, 0xed, + 0x45, 0xb1, 0xe5, 0x91, 0xb6, 0x2b, 0xd4, 0x2a, 0xbb, 0x2d, 0x94}; + +unsigned int ecc_pub_der_len = 91; + +unsigned char ecc_cert_der[] = { + 0x30, 0x82, 0x01, 0x7a, 0x30, 0x82, 0x01, 0x20, 0x02, 0x09, 0x00, 0xa6, 0x4e, 0x60, 0x8c, 0xa5, + 0xe7, 0x04, 0x98, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, + 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, + 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, + 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x30, 0x30, 0x39, + 0x31, 0x38, 0x31, 0x35, 0x33, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x31, 0x30, 0x38, 0x31, + 0x38, 0x31, 0x35, 0x33, 0x31, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, + 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, + 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x59, 0x30, + 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x7f, 0xd8, 0x8a, 0x21, 0x09, 0x41, 0xb2, 0x02, + 0x5b, 0x1d, 0xb0, 0x2e, 0xa5, 0x04, 0x6e, 0xae, 0xae, 0x21, 0xd8, 0x02, 0x8e, 0xaa, 0x3b, 0x68, + 0x03, 0x6e, 0x25, 0xd6, 0x2c, 0x08, 0xff, 0xa6, 0x13, 0x5a, 0x8c, 0x14, 0xe0, 0x93, 0x66, 0xa2, + 0x25, 0x46, 0x75, 0x8f, 0xd6, 0x87, 0x79, 0xb4, 0xc2, 0x62, 0x7e, 0xa8, 0xed, 0x45, 0xb1, 0xe5, + 0x91, 0xb6, 0x2b, 0xd4, 0x2a, 0xbb, 0x2d, 0x94, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xad, 0xfc, 0x19, 0xb8, + 0xc3, 0x87, 0x8d, 0x52, 0x3a, 0xf5, 0x83, 0xc6, 0x58, 0xc5, 0x86, 0x3b, 0xd5, 0xce, 0x74, 0x85, + 0x66, 0xd5, 0xbc, 0xfe, 0x5f, 0xd1, 0x75, 0xe3, 0x42, 0xe1, 0x5a, 0x00, 0x02, 0x20, 0x7c, 0x9c, + 0xb8, 0x45, 0x9e, 0xe7, 0x3a, 0x52, 0x9b, 0x2c, 0x92, 0xf3, 0x1b, 0x93, 0x65, 0x47, 0xb3, 0xf1, + 0x1b, 0xf4, 0xf6, 0x50, 0xd2, 0xf4, 0xcb, 0x25, 0x38, 0x21, 0xcb, 0x43, 0xae, 0x7a}; + +unsigned int ecc_cert_der_len = 382; + +unsigned char test_root[] = { + 0xe7, 0x9b, 0x03, 0x18, 0x85, 0x1b, 0x9d, 0xbd, 0xd7, 0x17, 0x18, 0xf9, 0xec, 0x72, 0xf0, 0x3d}; + +unsigned int test_root_len = 16; + +struct TestKeyData { + Sec_KeyType type; + Sec_KeyContainer kc; + SEC_BYTE* buffer; + SEC_SIZE buffer_len; +} __attribute__((aligned(32))); + +static TestKeyData g_keyData[TESTKEY_NUM] = { + {SEC_KEYTYPE_AES_128, SEC_KEYCONTAINER_RAW_AES_128, sym128_a_bin, sym128_a_bin_len}, //TESTKEY_AES128_A + {SEC_KEYTYPE_AES_256, SEC_KEYCONTAINER_RAW_AES_256, sym256_a_bin, sym256_a_bin_len}, //TESTKEY_AES256_A + {SEC_KEYTYPE_HMAC_128, SEC_KEYCONTAINER_RAW_HMAC_128, sym128_a_bin, sym128_a_bin_len}, //TESTKEY_HMAC128_A + {SEC_KEYTYPE_HMAC_160, SEC_KEYCONTAINER_RAW_HMAC_160, sym160_a_bin, sym160_a_bin_len}, //TESTKEY_HMAC160_A + {SEC_KEYTYPE_HMAC_256, SEC_KEYCONTAINER_RAW_HMAC_256, sym256_a_bin, sym256_a_bin_len}, //TESTKEY_HMAC256_A + {SEC_KEYTYPE_RSA_1024, SEC_KEYCONTAINER_DER_RSA_1024, rsa1024_der, rsa1024_der_len}, //TESTKEY_RSA1024_SGN_PRIV + {SEC_KEYTYPE_RSA_1024_PUBLIC, SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC, rsa1024_pub_der, rsa1024_pub_der_len}, //TESTKEY_RSA1024_SGN_PUB + {SEC_KEYTYPE_RSA_1024, SEC_KEYCONTAINER_DER_RSA_1024, rsa1024_der, rsa1024_der_len}, //TESTKEY_RSA1024_ENC_PRIV + {SEC_KEYTYPE_RSA_1024_PUBLIC, SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC, rsa1024_pub_der, rsa1024_pub_der_len}, //TESTKEY_RSA1024_ENC_PUB + {SEC_KEYTYPE_RSA_1024, SEC_KEYCONTAINER_DER_RSA_1024, rsa1024_der, rsa1024_der_len}, //TESTKEY_RSA1024_KEK_PRIV + {SEC_KEYTYPE_RSA_1024_PUBLIC, SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC, rsa1024_pub_der, rsa1024_pub_der_len}, //TESTKEY_RSA1024_KEK_PUB + {SEC_KEYTYPE_RSA_2048, SEC_KEYCONTAINER_DER_RSA_2048, rsa2048_der, rsa2048_der_len}, //TESTKEY_RSA2048_SGN_PRIV + {SEC_KEYTYPE_RSA_2048_PUBLIC, SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC, rsa2048_pub_der, rsa2048_pub_der_len}, //TESTKEY_RSA2048_SGN_PUB + {SEC_KEYTYPE_RSA_2048, SEC_KEYCONTAINER_DER_RSA_2048, rsa2048_der, rsa2048_der_len}, //TESTKEY_RSA2048_ENC_PRIV + {SEC_KEYTYPE_RSA_2048_PUBLIC, SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC, rsa2048_pub_der, rsa2048_pub_der_len}, //TESTKEY_RSA2048_ENC_PUB + {SEC_KEYTYPE_RSA_2048, SEC_KEYCONTAINER_DER_RSA_2048, rsa2048_der, rsa2048_der_len}, //TESTKEY_RSA2048_KEK_PRIV + {SEC_KEYTYPE_RSA_2048_PUBLIC, SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC, rsa2048_pub_der, rsa2048_pub_der_len}, //TESTKEY_RSA2048_KEK_PUB + {SEC_KEYTYPE_ECC_NISTP256, SEC_KEYCONTAINER_DER_ECC_NISTP256, ecc_der, ecc_der_len}, //TESTKEY_ECC + {SEC_KEYTYPE_ECC_NISTP256_PUBLIC, SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC, ecc_pub_der, ecc_pub_der_len}, //TESTKEY_ECC_PUB + {SEC_KEYTYPE_AES_128, SEC_KEYCONTAINER_RAW_AES_128, test_root, test_root_len}, //TESTKEY_ECC_PUB +}; + +struct TestCertData { // NOLINT + Sec_CertificateContainer cc; + SEC_BYTE* buffer; + SEC_SIZE buffer_len; +} __attribute__((aligned(16))); + +static TestCertData g_certData[TESTKEY_NUM] = { + {SEC_CERTIFICATECONTAINER_X509_DER, rsa1024_cert_der, rsa1024_cert_der_len}, //TESTCERT_RSA1024 + {SEC_CERTIFICATECONTAINER_X509_DER, rsa2048_cert_der, rsa2048_cert_der_len}, //TESTCERT_RSA2048 + {SEC_CERTIFICATECONTAINER_X509_DER, ecc_cert_der, ecc_cert_der_len}, //TESTCERT_EC +}; + +static Sec_Result BigNumToBuffer(const BIGNUM* bignum, SEC_BYTE* buffer, SEC_SIZE buffer_len) { + SEC_SIZE num_bytes; + + memset(buffer, 0, buffer_len); + num_bytes = BN_num_bytes(bignum); + + if (num_bytes > buffer_len) { + SEC_LOG_ERROR("Buffer not large enough. needed: %d, actual: %d", num_bytes, buffer_len); + return SEC_RESULT_FAILURE; + } + + BN_bn2bin(bignum, buffer + buffer_len - num_bytes); + + return SEC_RESULT_SUCCESS; +} + +ProvKey* TestCreds::getKey(TestKey key, TestKc kc, SEC_OBJECTID id) { + if (key >= TESTKEY_NUM) { + SEC_LOG_ERROR("Invalid key: %d", key); + return nullptr; + } + + switch (kc) { + case TESTKC_RAW: { + auto keyVector = std::vector(g_keyData[key].buffer, + g_keyData[key].buffer + g_keyData[key].buffer_len); + return new ProvKey(keyVector, g_keyData[key].kc); + } + case TESTKC_SOC: + return TestCreds::getSocKey(key, id); + break; + + case TESTKC_GENERATED: + case TESTKC_STORE: + default: + break; + } + + SEC_LOG_ERROR("Unimplemented"); + return nullptr; +} + +Sec_KeyType TestCreds::getKeyType(TestKey key) { + if (key >= TESTKEY_NUM) { + SEC_LOG_ERROR("Invalid key: %d", key); + return SEC_KEYTYPE_NUM; + } + + return g_keyData[key].type; +} + +ProvCert* TestCreds::getCert(TestCert cert) { + if (cert >= TESTCERT_NUM) { + SEC_LOG_ERROR("Invalid cert: %d", cert); + return nullptr; + } + + auto certVector = std::vector(g_certData[cert].buffer, + g_certData[cert].buffer + g_certData[cert].buffer_len); + return new ProvCert(certVector, g_certData[cert].cc); +} + +std::vector TestCreds::asOpenSslAes(TestKey key) { + return {g_keyData[key].buffer, g_keyData[key].buffer + g_keyData[key].buffer_len}; +} + +static RSA* RSAFromDERPub(const SEC_BYTE* der, SEC_SIZE der_len) { + const auto* p = der; + RSA* rsa = nullptr; + + rsa = d2i_RSAPublicKey(&rsa, &p, der_len); + + if (rsa == nullptr) { + p = der; + rsa = d2i_RSA_PUBKEY(&rsa, &p, der_len); + } + + do { + if (rsa == nullptr) { + SEC_LOG_ERROR("Invalid RSA key container"); + break; + } + } while (false); + + return rsa; +} + +static RSA* RSAFromDERPriv(const SEC_BYTE* der, SEC_SIZE der_len) { + const auto* p = der; + PKCS8_PRIV_KEY_INFO* p8 = nullptr; + EVP_PKEY* evp_key = nullptr; + RSA* rsa = nullptr; + + do { + p8 = d2i_PKCS8_PRIV_KEY_INFO(nullptr, &p, der_len); + if (p8 != nullptr) { + evp_key = EVP_PKCS82PKEY(p8); + if (evp_key == nullptr) { + SEC_LOG_ERROR("EVP_PKCS82PKEY failed"); + break; + } + } else { + evp_key = d2i_AutoPrivateKey(nullptr, &p, der_len); + if (evp_key == nullptr) { + SEC_LOG_ERROR("d2i_AutoPrivateKey failed"); + break; + } + } + + rsa = EVP_PKEY_get1_RSA(evp_key); + if (rsa == nullptr) { + SEC_LOG_ERROR("EVP_PKEY_get1_RSA failed"); + break; + } + } while (false); + + SEC_EVPPKEY_FREE(evp_key); + + if (p8 != nullptr) { + PKCS8_PRIV_KEY_INFO_free(p8); + } + + return rsa; +} + +RSA* TestCreds::asOpenSslRsa(TestKey key) { + RSA* rsa = nullptr; + if (g_keyData[key].kc == SEC_KEYCONTAINER_DER_RSA_1024_PUBLIC || + g_keyData[key].kc == SEC_KEYCONTAINER_DER_RSA_2048_PUBLIC) { + rsa = RSAFromDERPub(g_keyData[key].buffer, g_keyData[key].buffer_len); + if (rsa == nullptr) { + SEC_LOG_ERROR("SecUtils_RSAFromDERPub failed"); + } + } else { + rsa = RSAFromDERPriv(g_keyData[key].buffer, g_keyData[key].buffer_len); + if (rsa == nullptr) { + SEC_LOG_ERROR("SecUtils_RSAFromDERPriv failed"); + } + } + + return rsa; +} + +static EC_KEY* ECCFromDERPub(const SEC_BYTE* der, SEC_SIZE der_len) { + const auto* p = der; + EC_KEY* ec_key = nullptr; + + ec_key = d2i_EC_PUBKEY(&ec_key, &p, der_len); + + do { + if (ec_key == nullptr) { + SEC_LOG_ERROR("Invalid ECC key container"); + break; + } + } while (false); + + return ec_key; +} + +static EC_KEY* ECCFromDERPriv(const SEC_BYTE* der, SEC_SIZE der_len) { + const auto* p = der; + PKCS8_PRIV_KEY_INFO* p8 = nullptr; + EVP_PKEY* evp_key = nullptr; + EC_KEY* ecc = nullptr; + + do { + p8 = d2i_PKCS8_PRIV_KEY_INFO(nullptr, &p, der_len); + if (p8 != nullptr) { + evp_key = EVP_PKCS82PKEY(p8); + if (evp_key == nullptr) { + SEC_LOG_ERROR("EVP_PKCS82PKEY failed"); + break; + } + } else { + evp_key = d2i_AutoPrivateKey(nullptr, &p, der_len); + if (evp_key == nullptr) { + SEC_LOG_ERROR("d2i_AutoPrivateKey failed"); + break; + } + } + + ecc = EVP_PKEY_get1_EC_KEY(evp_key); + if (ecc == nullptr) { + SEC_LOG_ERROR("EVP_PKEY_get1_EC_KEY failed"); + break; + } + } while (false); + + SEC_EVPPKEY_FREE(evp_key); + + if (p8 != nullptr) { + PKCS8_PRIV_KEY_INFO_free(p8); + } + + return ecc; +} + +EC_KEY* TestCreds::asOpenSslEcKey(TestKey key) { + EC_KEY* ec = nullptr; + if (g_keyData[key].kc == SEC_KEYCONTAINER_DER_ECC_NISTP256_PUBLIC) { + ec = ECCFromDERPub(g_keyData[key].buffer, g_keyData[key].buffer_len); + if (ec == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromDERPub failed"); + } + } else { + ec = ECCFromDERPriv(g_keyData[key].buffer, g_keyData[key].buffer_len); + if (ec == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromDERPriv failed"); + } + } + + return ec; +} + +EVP_PKEY* TestCreds::asOpenSslEvpPkey(TestKey key) { + EVP_PKEY* evp_key = nullptr; + + if (SecKey_IsEcc(g_keyData[key].type) == SEC_TRUE) { + EC_KEY* ec = TestCreds::asOpenSslEcKey(key); + if (ec == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslEcKey failed"); + return nullptr; + } + + evp_key = EVP_PKEY_new(); + if (evp_key == nullptr) { + SEC_LOG_ERROR("EVP_PKEY_new failed"); + return nullptr; + } + + if (EVP_PKEY_set1_EC_KEY(evp_key, ec) == 0) { + SEC_EVPPKEY_FREE(evp_key); + SEC_ECC_FREE(ec); + SEC_LOG_ERROR("EVP_PKEY_set1_EC failed"); + return nullptr; + } + } else if (SecKey_IsRsa(g_keyData[key].type) == SEC_TRUE) { + RSA* rsa = TestCreds::asOpenSslRsa(key); + if (rsa == nullptr) { + SEC_LOG_ERROR("TestCreds::asOpenSslRsa failed"); + return nullptr; + } + + evp_key = EVP_PKEY_new(); + if (evp_key == nullptr) { + SEC_LOG_ERROR("EVP_PKEY_new failed"); + SEC_RSA_FREE(rsa); + return nullptr; + } + + if (EVP_PKEY_set1_RSA(evp_key, rsa) == 0) { + SEC_EVPPKEY_FREE(evp_key); + SEC_RSA_FREE(rsa); + SEC_LOG_ERROR("EVP_PKEY_set1_RSA failed"); + return nullptr; + } + + SEC_RSA_FREE(rsa); + } else { + SEC_LOG_ERROR("Not an asymetric key type"); + return nullptr; + } + + return evp_key; +} + +static bool Is_Valid_Point(EC_KEY* ec_key, const std::vector& data) { + if (data.size() != SEC_ECC_NISTP256_KEY_LEN) { + SEC_LOG_ERROR("Input size needed != One BIGNUM"); + return false; + } + + // Convert the input buffer to be encrypted to a BIGNUM + std::shared_ptr inputAsBN(BN_new(), BN_free); + if (inputAsBN == nullptr) { + SEC_LOG_ERROR("BN_new failed"); + return false; + } + + if (BN_bin2bn(&data[0], static_cast(data.size()), inputAsBN.get()) == nullptr) { + SEC_LOG_ERROR("BN_bin2bn failed. Error: %s", ERR_error_string(ERR_get_error(), nullptr)); + return false; + } + + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + if (group == nullptr) { + SEC_LOG_ERROR("EC_KEY_get0_group failed"); + return false; + } + + std::shared_ptr ctx(BN_CTX_new(), BN_CTX_free); + if (ctx == nullptr) { + SEC_LOG_ERROR("BN_CTX_new failed"); + return false; + } + + std::shared_ptr pt(EC_POINT_new(group), EC_POINT_free); + if (pt == nullptr) { + SEC_LOG_ERROR("EC_POINT_new failed"); + return false; + } + + if (EC_POINT_set_compressed_coordinates_GFp(group, pt.get(), inputAsBN.get(), 0, ctx.get()) != 1) { + SEC_LOG_ERROR("EC_POINT_set_compressed_coordinates_GFp failed"); + return false; + } + + return true; +} + +static int ElGamal_Encrypt_Rand(EC_KEY* ec_key, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* output, + SEC_SIZE outputSize, BIGNUM* sender_rand) { + int res = -1; + BIGNUM* inputAsBN = nullptr; + const EC_GROUP* group = nullptr; + const EC_POINT* P = nullptr; + const EC_POINT* PK_recipient = nullptr; + EC_POINT* shared_secret = nullptr; + EC_POINT* key_2_wrap_point = nullptr; + EC_POINT* sender_share = nullptr; + EC_POINT* wrapped_key = nullptr; + BIGNUM* x = nullptr; + BIGNUM* y = nullptr; + BN_CTX* ctx = nullptr; + + do { + if (inputSize != SEC_ECC_NISTP256_KEY_LEN) { + SEC_LOG_ERROR("Input size needed != One BIGNUM"); + break; + } + + if (outputSize < 4 * SEC_ECC_NISTP256_KEY_LEN) { + SEC_LOG_ERROR("Output size needed < Four BIGNUMs"); + break; + } + + // Convert the input buffer to be encrypted to a BIGNUM + inputAsBN = BN_new(); + if (inputAsBN == nullptr) { + SEC_LOG_ERROR("BN_new failed"); + break; + } + if (BN_bin2bn(input, static_cast(inputSize), inputAsBN) == nullptr) { + SEC_LOG_ERROR("BN_bin2bn failed. Error: %s", + ERR_error_string(ERR_get_error(), nullptr)); + break; + } + + group = EC_KEY_get0_group(ec_key); + if (group == nullptr) { + SEC_LOG_ERROR("EC_KEY_get0_group failed"); + break; + } + + ctx = BN_CTX_new(); + if (ctx == nullptr) { + SEC_LOG_ERROR("BN_CTX_new failed"); + break; + } + + // Convert the X coordinate to an EC Point. This takes the desired Y value in 1 bit (to choose + // which of the two possible Y values to use). This *calculates* an actual Y value for the point. + key_2_wrap_point = EC_POINT_new(group); + if (key_2_wrap_point == nullptr) { + SEC_LOG_ERROR("EC_POINT_new failed"); + break; + } + + if (EC_POINT_set_compressed_coordinates_GFp(group, key_2_wrap_point, inputAsBN, 0, ctx) != 1) { + // Don't print an error message if the error is "point not on curve" 100A906E, but still fail + if (ERR_get_error() != 0x100A906E) // i.e. error:100A906E:lib(16):func(169):reason(110) + { + SEC_LOG_ERROR("Set EC_POINT_set_compressed_coordinates_GFp failed. Error: %s", + ERR_error_string(ERR_get_error(), nullptr)); + } + break; + } + + // Calc sender's shared point 'wP' => this gets sent back to receiver + sender_share = EC_POINT_new(group); + if (sender_share == nullptr) { + SEC_LOG_ERROR("EC_POINT_new failed"); + break; + } + + P = EC_GROUP_get0_generator(group); + if (P == nullptr) { + SEC_LOG_ERROR("EC_GROUP_get0_generator failed"); + break; + } + EC_POINT_mul(group, sender_share, nullptr, P, sender_rand, ctx); + + // Calc sender's Shared Secret 'wRr' => this hides the key I want to send + shared_secret = EC_POINT_new(group); + if (shared_secret == nullptr) { + SEC_LOG_ERROR("EC_POINT_new failed"); + break; + } + + PK_recipient = EC_KEY_get0_public_key(ec_key); + if (PK_recipient == nullptr) { + SEC_LOG_ERROR("EC_KEY_get0_public_key failed"); + break; + } + EC_POINT_mul(group, shared_secret, nullptr, PK_recipient, sender_rand, ctx); + + // key_2_wrap_point is a point on the curve, we add the shared_secret + // to it and send the result, the wrapped_key, to the receiver. + wrapped_key = EC_POINT_new(group); + if (wrapped_key == nullptr) { + SEC_LOG_ERROR("EC_POINT_new failed"); + break; + } + EC_POINT_add(group, wrapped_key, key_2_wrap_point, shared_secret, ctx); + + // Dissect the wrapped point to get its coordinates + x = BN_new(); + if (x == nullptr) { + SEC_LOG_ERROR("BN_new failed"); + break; + } + y = BN_new(); + if (y == nullptr) { + SEC_LOG_ERROR("BN_new failed"); + break; + } + + // Dissect shared_secret to get its coordinates and output them + EC_POINT_get_affine_coordinates_GFp(group, sender_share, x, y, ctx); + + if (BigNumToBuffer(x, &output[0 * SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_BigNumToBuffer failed"); + break; + } + + if (BigNumToBuffer(y, &output[1 * SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_BigNumToBuffer failed"); + break; + } + + // Dissect wrapped_key to get its coordinates and output them + EC_POINT_get_affine_coordinates_GFp(group, wrapped_key, x, y, ctx); + + if (BigNumToBuffer(x, &output[2 * SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_BigNumToBuffer failed"); + break; + } + + if (BigNumToBuffer(y, &output[3 * SEC_ECC_NISTP256_KEY_LEN], SEC_ECC_NISTP256_KEY_LEN) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_BigNumToBuffer failed"); + break; + } + + res = 4 * SEC_ECC_NISTP256_KEY_LEN; + } while (false); + + if (nullptr != x) + BN_free(x); + if (nullptr != y) + BN_free(y); + if (nullptr != inputAsBN) + BN_free(inputAsBN); + if (nullptr != sender_rand) + BN_free(sender_rand); + if (nullptr != shared_secret) + EC_POINT_free(shared_secret); + if (nullptr != sender_share) + EC_POINT_free(sender_share); + if (nullptr != key_2_wrap_point) + EC_POINT_free(key_2_wrap_point); + if (nullptr != wrapped_key) + EC_POINT_free(wrapped_key); + BN_CTX_free(ctx); + + return res; +} + +static int ElGamal_Encrypt(EC_KEY* ec_key, SEC_BYTE* input, SEC_SIZE inputSize, SEC_BYTE* output, + SEC_SIZE outputSize) { + // Generate random number 'w' (multiplier) for the sender + BIGNUM* sender_rand = BN_new(); + + if (sender_rand == nullptr) { + SEC_LOG_ERROR("BN_new failed"); + return -1; + } + if (BN_rand(sender_rand, 256, -1, 0) == 0) { + SEC_LOG_ERROR("BN_rand failed"); + if (nullptr != sender_rand) + BN_free(sender_rand); + return -1; + } + + return ElGamal_Encrypt_Rand(ec_key, input, inputSize, output, outputSize, sender_rand); +} + +static std::vector opensslRsaCrypt(RSA* rsa, Sec_CipherAlgorithm algorithm, Sec_CipherMode mode, + const std::vector& input) { + int padding; + if (algorithm == SEC_CIPHERALGORITHM_RSA_PKCS1_PADDING) { + padding = RSA_PKCS1_PADDING; + } else { + padding = RSA_PKCS1_OAEP_PADDING; + } + + int openssl_res; + std::vector output; + output.resize(RSA_size(rsa)); + + if (mode == SEC_CIPHERMODE_ENCRYPT || mode == SEC_CIPHERMODE_ENCRYPT_NATIVEMEM) { + openssl_res = RSA_public_encrypt(static_cast(input.size()), &input[0], &output[0], rsa, padding); + } else { + openssl_res = RSA_private_decrypt(static_cast(input.size()), &input[0], &output[0], rsa, padding); + } + + if (openssl_res < 0) { + SEC_LOG_ERROR("%s", ERR_error_string(ERR_get_error(), nullptr)); + return {}; + } + + output.resize(openssl_res); + + return output; +} + +static Sec_Result RSAToDERPrivKeyInfo(RSA* rsa, SEC_BYTE* output, SEC_SIZE out_len, SEC_SIZE* written) { + BIO* bio = nullptr; + EVP_PKEY* evp_key = nullptr; + BUF_MEM* bptr = nullptr; + Sec_Result result = SEC_RESULT_FAILURE; + + do { + evp_key = EVP_PKEY_new(); + if (EVP_PKEY_set1_RSA(evp_key, rsa) == 0) { + SEC_LOG_ERROR("EVP_PKEY_set1_RSA failed"); + break; + } + + bio = BIO_new(BIO_s_mem()); + if (bio == nullptr) { + SEC_LOG_ERROR("BIO_new(BIO_s_mem()) failed"); + break; + } + + if (i2d_PKCS8PrivateKeyInfo_bio(bio, evp_key) < 0) { + SEC_LOG_ERROR("I2d_PKCS8_PRIV_KEY_INFO_bio failed"); + break; + } + + BIO_flush(bio); + BIO_get_mem_ptr(bio, &bptr); // NOLINT + + *written = bptr->length; + + if (output != nullptr) { + if (out_len < bptr->length) { + SEC_LOG_ERROR("Output buffer is not large enough"); + break; + } + memcpy(output, bptr->data, bptr->length); + } + + result = SEC_RESULT_SUCCESS; + } while (false); + + SEC_EVPPKEY_FREE(evp_key); + SEC_BIO_FREE(bio); + + return result; +} + +static std::vector toPkcs8(RSA* rsa) { + std::vector pkcs8; + pkcs8.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE pkcs8_len; + + if (RSAToDERPrivKeyInfo(rsa, &pkcs8[0], pkcs8.size(), &pkcs8_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_RSAToDERPriv failed"); + return {}; + } + + pkcs8.resize(pkcs8_len); + + return pkcs8; +} + +template +std::vector concat(std::vector& a, std::vector& b) { + std::vector ret = std::vector(); + std::copy(a.begin(), a.end(), std::back_inserter(ret)); + std::copy(b.begin(), b.end(), std::back_inserter(ret)); + return ret; +} + +ProvKey* TestCreds::wrapAesWithEc(const SEC_BYTE* clear, Sec_KeyType type, EC_KEY* ec_key, SEC_OBJECTID wrappingId, + Sec_CipherAlgorithm asymAlg) { + std::vector payload; + payload.resize(32); + + if (type == SEC_KEYTYPE_AES_128) { + memcpy(&payload[0], clear, SEC_AES_BLOCK_SIZE); + memcpy(&payload[16], clear, SEC_AES_BLOCK_SIZE); + } else { + memcpy(&payload[0], clear, 32); + } + + std::vector encrypted; + encrypted.resize(SEC_ECC_NISTP256_KEY_LEN * 4); + + int encrypted_len = ElGamal_Encrypt(ec_key, &payload[0], payload.size(), &encrypted[0], + encrypted.size()); + + if (encrypted_len <= 0) { + SEC_LOG_ERROR("_ElGamal_Encrypt failed"); + return nullptr; + } + + encrypted.resize(encrypted_len); + + std::vector res; + res.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE res_len; + if (SecKey_GenerateWrappedKeyAsn1Off(&encrypted[0], encrypted.size(), type, wrappingId, nullptr, asymAlg, &res[0], + res.size(), &res_len, 32 - SecKey_GetKeyLenForKeyType(type)) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GenerateWrappedKeyAsn1 failed"); + return nullptr; + } + res.resize(res_len); + + return new ProvKey(res, SEC_KEYCONTAINER_ASN1); +} + +ProvKey* TestCreds::wrapAesWithRsa(const SEC_BYTE* data, Sec_KeyType type, RSA* rsa_key, SEC_OBJECTID wrappingId, + Sec_CipherAlgorithm asymAlg) { + std::vector clear(data, data + SecKey_GetKeyLenForKeyType(type)); + std::vector wrapped = opensslRsaCrypt(rsa_key, asymAlg, SEC_CIPHERMODE_ENCRYPT, clear); + + if (wrapped.empty()) { + SEC_LOG_ERROR("OpensslRsaCrypt failed"); + return nullptr; + } + + std::vector res; + res.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE res_len; + + if (SecKey_GenerateWrappedKeyAsn1(&wrapped[0], wrapped.size(), type, wrappingId, nullptr, asymAlg, &res[0], + res.size(), &res_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GenerateWrappedKeyAsn1 failed"); + return nullptr; + } + + return new ProvKey(res, SEC_KEYCONTAINER_ASN1); +} + +ProvKey* TestCreds::wrapAesWithAes(const SEC_BYTE* clear, Sec_KeyType type, const SEC_BYTE* wrapping, + Sec_KeyType wrappingType, SEC_OBJECTID wrappingId, Sec_CipherAlgorithm symAlg) { + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + + TestCtx ctx; + ctx.init(); + + if (ctx.provisionKey(wrappingId, SEC_STORAGELOC_RAM, wrapping, SecKey_GetKeyLenForKeyType(wrappingType), + wrappingType == SEC_KEYTYPE_AES_128 ? SEC_KEYCONTAINER_RAW_AES_128 : SEC_KEYCONTAINER_RAW_AES_256) == + nullptr) { + SEC_LOG_ERROR("TestCtx::provisionKey failed"); + return nullptr; + } + + std::vector wrapped; + wrapped.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE wrapped_len; + if (SecUtils_WrapSymetric(ctx.proc(), wrappingId, symAlg, &iv[0], const_cast(clear), + SecKey_GetKeyLenForKeyType(type), &wrapped[0], wrapped.size(), &wrapped_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_WrapSymetric failed"); + return nullptr; + } + wrapped.resize(wrapped_len); + + std::vector asn1; + asn1.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE asn1_len; + + if (SecKey_GenerateWrappedKeyAsn1(&wrapped[0], wrapped.size(), type, wrappingId, &iv[0], symAlg, &asn1[0], + asn1.size(), &asn1_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GenerateWrappedKeyAsn1 failed"); + return nullptr; + } + asn1.resize(asn1_len); + + return new ProvKey(asn1, SEC_KEYCONTAINER_ASN1); +} + +ProvKey* TestCreds::wrapRsaWithAes(RSA* rsa, const SEC_BYTE* wrapping, Sec_KeyType wrappingType, + SEC_OBJECTID wrappingId, Sec_CipherAlgorithm symAlg) { + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + + TestCtx ctx; + ctx.init(); + + if (ctx.provisionKey(wrappingId, SEC_STORAGELOC_RAM, wrapping, SecKey_GetKeyLenForKeyType(wrappingType), + wrappingType == SEC_KEYTYPE_AES_128 ? SEC_KEYCONTAINER_RAW_AES_128 : SEC_KEYCONTAINER_RAW_AES_256) == + nullptr) { + SEC_LOG_ERROR("TestCtx::provisionKey failed"); + return nullptr; + } + + std::vector pkcs8 = toPkcs8(rsa); + if (pkcs8.empty()) { + SEC_LOG_ERROR("ToPkcs8 failed"); + return nullptr; + } + Sec_KeyType type = (RSA_size(rsa) == 128) ? SEC_KEYTYPE_RSA_1024 : SEC_KEYTYPE_RSA_2048; + + std::vector wrapped; + wrapped.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE wrapped_len; + if (SecUtils_WrapSymetric(ctx.proc(), wrappingId, symAlg, &iv[0], &pkcs8[0], pkcs8.size(), &wrapped[0], + wrapped.size(), &wrapped_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_WrapSymetric failed"); + return nullptr; + } + wrapped.resize(wrapped_len); + + std::vector asn1; + asn1.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE asn1_len; + + if (SecKey_GenerateWrappedKeyAsn1(&wrapped[0], wrapped.size(), type, wrappingId, &iv[0], symAlg, &asn1[0], + asn1.size(), &asn1_len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GenerateWrappedKeyAsn1 failed"); + return nullptr; + } + asn1.resize(asn1_len); + + return new ProvKey(asn1, SEC_KEYCONTAINER_ASN1); +} + +std::vector TestCreds::getWrappedContentKeyChainEcAes(TestKey contentKey, TestKc kc, SEC_OBJECTID base_id, + Sec_CipherAlgorithm asymAlg) { + std::vector res; + + //generate key0 + std::shared_ptr provKey(TestCreds::getKey(TESTKEY_EC_PRIV, kc, base_id)); + res.push_back(*provKey); + + //generate key1 + std::shared_ptr ec_key(TestCreds::asOpenSslEcKey(TESTKEY_EC_PRIV), EC_KEY_free); + std::shared_ptr wrappedKey1( + wrapAesWithEc(TestCreds::asOpenSslAes(contentKey).data(), TestCreds::getKeyType(contentKey), ec_key.get(), + base_id, asymAlg)); + res.push_back(*wrappedKey1); + + return res; +} + +std::vector TestCreds::getWrappedContentKeyChainEcAesAes(TestKey contentKey, TestKc kc, SEC_OBJECTID base_id, + Sec_KeyType aesType, Sec_CipherAlgorithm asymAlg, Sec_CipherAlgorithm symAlg) { + std::vector res; + + //generate key0 + std::shared_ptr provKey(TestCreds::getKey(TESTKEY_EC_PRIV, kc, base_id)); + + res.push_back(*provKey); + + //generate key1 + std::shared_ptr ec_key(TestCreds::asOpenSslEcKey(TESTKEY_EC_PRIV), EC_KEY_free); + std::vector key1 = TestCtx::random(SecKey_GetKeyLenForKeyType(aesType)); + while (!Is_Valid_Point(ec_key.get(), + (SecKey_GetKeyLenForKeyType(aesType) == SEC_AES_BLOCK_SIZE) ? concat(key1, key1) : key1)) { + SEC_PRINT("Not a valid point. Regenerating.\n"); + key1 = TestCtx::random(SecKey_GetKeyLenForKeyType(aesType)); + } + + std::shared_ptr wrappedKey1(wrapAesWithEc(&key1[0], aesType, ec_key.get(), base_id, asymAlg)); + if (wrappedKey1 == nullptr) + return res; + + res.push_back(*wrappedKey1); + + //generate key2 + std::shared_ptr wrappedKey2( + wrapAesWithAes(TestCreds::asOpenSslAes(contentKey).data(), TestCreds::getKeyType(contentKey), &key1[0], + aesType, base_id + 1, symAlg)); + if (wrappedKey2 == nullptr) + return res; + + res.push_back(*wrappedKey2); + + return res; +} + +std::vector TestCreds::getWrappedContentKeyChainRsaAesRsaAesAes(TestKey contentKey, TestKc kc, + SEC_OBJECTID base_id, Sec_KeyType rsaType, + Sec_CipherAlgorithm asymAlg, + Sec_KeyType aesType, + Sec_CipherAlgorithm symAlg, + Sec_CipherAlgorithm ckSymAlg) { + std::vector res; + + //generate key0 + TestKey rsaPrivKey = (rsaType == SEC_KEYTYPE_RSA_1024) ? TESTKEY_RSA1024_KEK_PRIV : TESTKEY_RSA2048_KEK_PRIV; + std::shared_ptr provKey(TestCreds::getKey(rsaPrivKey, kc, base_id)); + res.push_back(*provKey); + + //generate key1 + std::vector key1 = TestCtx::random(SecKey_GetKeyLenForKeyType(aesType)); + std::shared_ptr rsa_key(TestCreds::asOpenSslRsa(rsaPrivKey), RSA_free); + std::shared_ptr wrappedKey1(wrapAesWithRsa(&key1[0], aesType, rsa_key.get(), base_id, asymAlg)); + if (wrappedKey1 == nullptr) + return res; + + res.push_back(*wrappedKey1); + + //generate key2 + std::shared_ptr wrappedKey2(wrapRsaWithAes(rsa_key.get(), &key1[0], aesType, base_id + 1, symAlg)); + if (wrappedKey2 == nullptr) + return res; + + res.push_back(*wrappedKey2); + + //generate key3 + std::vector key3 = TestCtx::random(SecKey_GetKeyLenForKeyType(aesType)); + std::shared_ptr wrappedKey3(wrapAesWithRsa(&key3[0], aesType, rsa_key.get(), base_id + 2, asymAlg)); + if (wrappedKey3 == nullptr) + return res; + + res.push_back(*wrappedKey3); + + //generate key4 + std::shared_ptr wrappedKey4( + wrapAesWithAes(TestCreds::asOpenSslAes(contentKey).data(), TestCreds::getKeyType(contentKey), &key3[0], + aesType, base_id + 3, ckSymAlg)); + if (wrappedKey4 == nullptr) + return res; + + res.push_back(*wrappedKey4); + + return res; +} + +std::vector TestCreds::getWrappedContentKeyChainRsaAes(TestKey contentKey, TestKc kc, SEC_OBJECTID base_id, + Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg) { + std::vector res; + + //generate key0 + TestKey rsaKey = (rsaType == SEC_KEYTYPE_RSA_1024) ? TESTKEY_RSA1024_KEK_PRIV : TESTKEY_RSA2048_KEK_PRIV; + std::shared_ptr provKey(TestCreds::getKey(rsaKey, kc, base_id)); + res.push_back(*provKey); + + //generate key1 + std::shared_ptr rsa(TestCreds::asOpenSslRsa(rsaKey), RSA_free); + std::shared_ptr wrappedKey1( + wrapAesWithRsa(TestCreds::asOpenSslAes(contentKey).data(), TestCreds::getKeyType(contentKey), rsa.get(), + base_id, asymAlg)); + res.push_back(*wrappedKey1); + + return res; +} + +std::vector TestCreds::getWrappedContentKeyChainRsaAesAes(TestKey contentKey, TestKc kc, SEC_OBJECTID base_id, + Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, + Sec_KeyType aesType, Sec_CipherAlgorithm symAlg) { + std::vector res; + + //generate key0 + TestKey rsaPrivKey = (rsaType == SEC_KEYTYPE_RSA_1024) ? TESTKEY_RSA1024_KEK_PRIV : TESTKEY_RSA2048_KEK_PRIV; + std::shared_ptr provKey(TestCreds::getKey(rsaPrivKey, kc, base_id)); + res.push_back(*provKey); + + //generate key1 + std::vector key1 = TestCtx::random(SecKey_GetKeyLenForKeyType(aesType)); + + std::shared_ptr rsa_key(TestCreds::asOpenSslRsa(rsaPrivKey), RSA_free); + std::shared_ptr wrappedKey1(wrapAesWithRsa(&key1[0], aesType, rsa_key.get(), base_id, asymAlg)); + if (wrappedKey1 == nullptr) + return res; + + res.push_back(*wrappedKey1); + + //generate key2 + std::shared_ptr wrappedKey2( + wrapAesWithAes(TestCreds::asOpenSslAes(contentKey).data(), TestCreds::getKeyType(contentKey), &key1[0], + aesType, base_id + 1, symAlg)); + if (wrappedKey2 == nullptr) + return res; + + res.push_back(*wrappedKey2); + + return res; +} diff --git a/test/main/cpp/test_ctx.cpp b/test/main/cpp/test_ctx.cpp new file mode 100644 index 0000000..bf0d1f5 --- /dev/null +++ b/test/main/cpp/test_ctx.cpp @@ -0,0 +1,493 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_ctx.h" + +#include +#include + +std::string g_log_output; + +static void variable_logger(const char* fmt, ...) { // NOLINT + static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER; + + pthread_mutex_lock(&_log_mutex); + + va_list args; + va_start(args, fmt); + + char tmp[65536]; + memset(tmp, 0, sizeof(tmp)); + vsnprintf(tmp, sizeof(tmp) - 1, fmt, args); // NOLINT + + va_end(args); + + g_log_output += std::string(tmp); + + pthread_mutex_unlock(&_log_mutex); +} + +void Logger::init() { + g_log_output.clear(); + Sec_SetLogger(variable_logger); +} + +void Logger::shutdown() { + Sec_SetLogger(Sec_DefaultLoggerCb); +} + +const char* Logger::output() { + return g_log_output.c_str(); +} + +std::vector SuiteCtx::getFailed() const { + std::vector res; + + for (int i = 0; i < tests_.size(); ++i) { + if (tests_[i].second == TESTRESULT_FAILED) { + res.push_back(i + 1); + } + } + + return res; +} + +std::vector SuiteCtx::getSucceeded() const { + std::vector res; + + for (int i = 0; i < tests_.size(); ++i) { + if (tests_[i].second == TESTRESULT_SUCCEEDED) { + res.push_back(i + 1); + } + } + + return res; +} + +std::vector SuiteCtx::getSkipped() const { + std::vector res; + + for (int i = 0; i < tests_.size(); ++i) { + if (tests_[i].second == TESTRESULT_SKIPPED) { + res.push_back(i + 1); + } + } + + return res; +} + +std::vector SuiteCtx::getAttempted() const { + std::vector res; + + for (int i = 0; i < tests_.size(); ++i) { + if (tests_[i].second == TESTRESULT_SUCCEEDED || tests_[i].second == TESTRESULT_FAILED) { + res.push_back(i + 1); + } + } + + return res; +} + +std::vector SuiteCtx::getAll() const { + std::vector res; + + for (int i = 0; i < tests_.size(); ++i) { + res.push_back(i + 1); // NOLINT + } + + return res; +} + +Sec_Result TestCtx::init(const char* global_dir, const char* app_dir) { + if (SecProcessor_GetInstance_Directories(&proc_, global_dir, app_dir) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecProcessor_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + if (TestCreds::preprovisionSoc(this) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCreds::preprovisionSoc failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +TestCtx::~TestCtx() { + while (!macs_.empty()) { + SEC_BYTE mac[SEC_MAC_MAX_LEN]; + SEC_SIZE mac_len; + + SecMac_Release(macs_.back(), mac, &mac_len); + macs_.pop_back(); + } + + while (!ciphers_.empty()) { + releaseCipher(ciphers_.back()); + } + + while (!sigs_.empty()) { + releaseSignature(sigs_.back()); + } + + while (!digests_.empty()) { + releaseDigest(digests_.back()); + } + + while (!randoms_.empty()) { + releaseRandom(randoms_.back()); + } + + while (!keys_.empty()) { + releaseKey(keys_.back()); + } + + while (!provisionedKeys_.empty()) { + deleteKey(provisionedKeys_.back()); + } + + while (!certs_.empty()) { + releaseCert(certs_.back()); + } + + while (!provisionedCerts_.empty()) { + deleteCert(provisionedCerts_.back()); + } + + while (!bundles_.empty()) { + releaseBundle(bundles_.back()); + } + + while (!provisionedBundles_.empty()) { + deleteBundle(provisionedBundles_.back()); + } + + if (proc_ != nullptr) { + SecProcessor_Release(proc_); + proc_ = nullptr; + } +} + +Sec_KeyHandle* TestCtx::provisionKey(SEC_OBJECTID id, Sec_StorageLoc loc, const SEC_BYTE* data, SEC_SIZE len, + Sec_KeyContainer kc, bool softWrap) { + Sec_StorageLoc locToUse = loc; + + if (softWrap) { + if (loc == SEC_STORAGELOC_RAM) { + locToUse = SEC_STORAGELOC_RAM_SOFT_WRAPPED; + } else { + locToUse = SEC_STORAGELOC_FILE_SOFT_WRAPPED; + } + } + + if (SecKey_Provision(proc_, id, locToUse, kc, const_cast(data), len) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return nullptr; + } + + provisionedKeys_.push_back(id); + + return getKey(id); +} + +Sec_KeyHandle* TestCtx::provisionKey(SEC_OBJECTID id, Sec_StorageLoc loc, TestKey key, TestKc kc, bool softWrap) { + if (kc == TESTKC_GENERATED) { + Sec_StorageLoc locToUse = loc; + + //generate key with same key type as the known key + if (SecKey_Generate(proc_, id, TestCreds::getKeyType(key), locToUse) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Generate failed"); + return nullptr; + } + + provisionedKeys_.push_back(id); + + return getKey(id); + } + + if (kc == TESTKC_EXPORTED) { + std::shared_ptr prov(TestCreds::getKey(key, TESTKC_CONDITIONAL, id)); + if (!prov) { + SEC_LOG_ERROR("TestCreds::getKey failed"); + return nullptr; + } + + Sec_KeyHandle* keyHandle = provisionKey(id, loc, &prov->key[0], prov->key.size(), prov->kc, softWrap); + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + return nullptr; + } + exported_key.resize(exported_len); + + return provisionKey(id, loc, &exported_key[0], exported_key.size(), SEC_KEYCONTAINER_EXPORTED, SEC_FALSE); + } + + std::shared_ptr prov(TestCreds::getKey(key, kc, id)); + if (!prov) { + SEC_LOG_ERROR("TestCreds::getKey failed"); + return nullptr; + } + + return provisionKey(id, loc, &prov->key[0], prov->key.size(), prov->kc, softWrap); +} + +Sec_KeyHandle* TestCtx::getKey(SEC_OBJECTID id) { + Sec_KeyHandle* keyHandle = nullptr; + + if (SecKey_GetInstance(proc_, id, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return nullptr; + } + + keys_.push_back(keyHandle); + + return keyHandle; +} + +void TestCtx::releaseKey(Sec_KeyHandle* keyHandle) { + keys_.remove(keyHandle); + SecKey_Release(keyHandle); +} + +void TestCtx::deleteKey(SEC_OBJECTID id) { + provisionedKeys_.remove(id); + SecKey_Delete(proc_, id); +} + +void TestCtx::releaseCert(Sec_CertificateHandle* certificateHandle) { + certs_.remove(certificateHandle); + SecCertificate_Release(certificateHandle); +} + +Sec_CertificateHandle* TestCtx::provisionCert(SEC_OBJECTID id, Sec_StorageLoc loc, TestCert cert) { + std::shared_ptr prov(TestCreds::getCert(cert)); + if (!prov) { + SEC_LOG_ERROR("TestCreds::getCert failed"); + return nullptr; + } + + if (SecCertificate_Provision(proc_, id, loc, prov->cc, &prov->cert[0], prov->cert.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_Provision failed"); + return nullptr; + } + + provisionedCerts_.push_back(id); + + return getCert(id); +} + +Sec_CertificateHandle* TestCtx::getCert(SEC_OBJECTID id) { + Sec_CertificateHandle* certificateHandle = nullptr; + + if (SecCertificate_GetInstance(proc_, id, &certificateHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCertificate_GetInstance failed"); + return nullptr; + } + + certs_.push_back(certificateHandle); + + return certificateHandle; +} + +void TestCtx::deleteCert(SEC_OBJECTID id) { + provisionedCerts_.remove(id); + SecCertificate_Delete(proc_, id); +} + +Sec_BundleHandle* TestCtx::provisionBundle(SEC_OBJECTID id, Sec_StorageLoc location, + const std::vector& bundle) { + if (SecBundle_Provision(proc_, id, location, const_cast(&bundle[0]), bundle.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBundle_Provision failed"); + return nullptr; + } + + provisionedBundles_.push_back(id); + + return getBundle(id); +} + +Sec_BundleHandle* TestCtx::getBundle(SEC_OBJECTID id) { + Sec_BundleHandle* bundleHandle = nullptr; + + if (SecBundle_GetInstance(proc_, id, &bundleHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecBundle_GetInstance failed"); + return nullptr; + } + + bundles_.push_back(bundleHandle); + + return bundleHandle; +} + +void TestCtx::releaseBundle(Sec_BundleHandle* bundleHandle) { + bundles_.remove(bundleHandle); + SecBundle_Release(bundleHandle); +} + +void TestCtx::deleteBundle(SEC_OBJECTID id) { + provisionedBundles_.remove(id); + SecBundle_Delete(proc_, id); +} + +Sec_CipherHandle* TestCtx::acquireCipher(Sec_CipherAlgorithm algorithm, Sec_CipherMode mode, Sec_KeyHandle* keyHandle, + SEC_BYTE* iv) { + Sec_CipherHandle* cipherHandle = nullptr; + + if (SecCipher_GetInstance(proc_, algorithm, mode, keyHandle, iv, &cipherHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_GetInstance failed"); + return nullptr; + } + + ciphers_.push_back(cipherHandle); + + return cipherHandle; +} + +void TestCtx::releaseCipher(Sec_CipherHandle* cipherHandle) { + ciphers_.remove(cipherHandle); + SecCipher_Release(cipherHandle); +} + +Sec_RandomHandle* TestCtx::acquireRandom(Sec_RandomAlgorithm algorithm) { + Sec_RandomHandle* randomHandle = nullptr; + + if (SecRandom_GetInstance(proc_, algorithm, &randomHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecRandom_GetInstance failed"); + return nullptr; + } + + randoms_.push_back(randomHandle); + + return randomHandle; +} + +void TestCtx::releaseRandom(Sec_RandomHandle* randomHandle) { + randoms_.remove(randomHandle); + SecRandom_Release(randomHandle); +} + +Sec_SignatureHandle* TestCtx::acquireSignature(Sec_SignatureAlgorithm algorithm, Sec_SignatureMode mode, + Sec_KeyHandle* keyHandle) { + Sec_SignatureHandle* signatureHandle = nullptr; + + if (SecSignature_GetInstance(proc_, algorithm, mode, keyHandle, &signatureHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecSignature_GetInstance failed"); + return nullptr; + } + + sigs_.push_back(signatureHandle); + + return signatureHandle; +} + +void TestCtx::releaseSignature(Sec_SignatureHandle* signatureHandle) { + sigs_.remove(signatureHandle); + SecSignature_Release(signatureHandle); +} + +Sec_MacHandle* TestCtx::acquireMac(Sec_MacAlgorithm algorithm, Sec_KeyHandle* keyHandle) { + Sec_MacHandle* macHandle = nullptr; + + if (SecMac_GetInstance(proc_, algorithm, keyHandle, &macHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecMac_GetInstance failed"); + return nullptr; + } + + macs_.push_back(macHandle); + + return macHandle; +} + +Sec_Result TestCtx::releaseMac(Sec_MacHandle* macHandle, SEC_BYTE* macBuffer, SEC_SIZE* macSize) { + macs_.remove(macHandle); + return SecMac_Release(macHandle, macBuffer, macSize); +} + +void TestCtx::releaseMac(Sec_MacHandle* macHandle) { + SEC_BYTE macBuffer[SEC_DIGEST_MAX_LEN]; + SEC_SIZE macSize; + + releaseMac(macHandle, macBuffer, &macSize); +} + +Sec_DigestHandle* TestCtx::acquireDigest(Sec_DigestAlgorithm algorithm) { + Sec_DigestHandle* digestHandle = nullptr; + + if (SecDigest_GetInstance(proc_, algorithm, &digestHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecDigest_GetInstance failed"); + return nullptr; + } + + digests_.push_back(digestHandle); + + return digestHandle; +} + +Sec_Result TestCtx::releaseDigest(Sec_DigestHandle* digestHandle, SEC_BYTE* digestOutput, SEC_SIZE* digestSize) { + digests_.remove(digestHandle); + return SecDigest_Release(digestHandle, digestOutput, digestSize); +} + +void TestCtx::releaseDigest(Sec_DigestHandle* digestHandle) { + SEC_BYTE digestOutput[SEC_DIGEST_MAX_LEN]; + SEC_SIZE digestSize; + + releaseDigest(digestHandle, digestOutput, &digestSize); +} + +void TestCtx::printHex(const char* label, const std::vector& data) { + SEC_PRINT("%s[%d]: ", label, data.size()); + Sec_PrintHex((void*) &data[0], data.size()); // NOLINT + SEC_PRINT("\n"); +} + +std::vector TestCtx::random(SEC_SIZE len) { + std::vector output; + + output.resize(len); + + RAND_bytes(&output[0], static_cast(output.size())); + + return output; +} + +std::vector TestCtx::coalesceInputs(const std::vector>& inputs) { + std::vector input; + + for (const auto& i : inputs) { + input.insert(input.end(), i.begin(), i.end()); + } + + return input; +} + +SEC_SIZE TestCtx::coalesceInputSizes(const std::vector& inputSizes) { + SEC_SIZE out = 0; + + for (unsigned int inputSize : inputSizes) { + out += inputSize; + } + + return out; +} diff --git a/test/main/cpp/wrapped.cpp b/test/main/cpp/wrapped.cpp new file mode 100644 index 0000000..f476202 --- /dev/null +++ b/test/main/cpp/wrapped.cpp @@ -0,0 +1,1370 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "wrapped.h" // NOLINT +#include "cipher.h" +#include "mac.h" +#include "test_ctx.h" +#include + +static ProvKey convertV2ToV3(const std::vector& v2) { + ProvKey lastKey; + + for (unsigned int i = 0; i < v2.size(); ++i) { + const ProvKey& key = v2[i]; + + if (key.kc == SEC_KEYCONTAINER_ASN1) { + SEC_BYTE payload[SEC_KEYCONTAINER_MAX_LEN]; + SEC_SIZE payloadLen; + Sec_KeyType wrappedKeyType; + SEC_OBJECTID wrappingId; + SEC_BYTE wrappingIv[SEC_AES_BLOCK_SIZE]; + Sec_CipherAlgorithm wrappingAlg; + SEC_SIZE key_offset; + + if (SecKey_ExtractWrappedKeyParamsAsn1BufferOff(const_cast(&key.key[0]), key.key.size(), payload, + sizeof(payload), &payloadLen, &wrappedKeyType, &wrappingId, wrappingIv, &wrappingAlg, + &key_offset) != SEC_RESULT_SUCCESS) { + + SEC_LOG_ERROR("SecKey_ExtractWrappedKeyParamsAsn1BufferOff failed"); + return {}; + } + + SEC_PRINT("%d: wrappingId=" SEC_OBJECTID_PATTERN "\n", i, wrappingId); + + //special case for wrapping root key + if (wrappingId == 0) { + lastKey = key; + continue; + } + + std::vector v3Key; + v3Key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE v3KeyLen; + + if (i == 0) { + lastKey = key; + } else { + if (SecKey_GenerateWrappedKeyAsn1V3(payload, payloadLen, wrappedKeyType, &lastKey.key[0], + lastKey.key.size(), wrappingIv, wrappingAlg, &v3Key[0], v3Key.size(), &v3KeyLen, + key_offset) != SEC_RESULT_SUCCESS) { + + SEC_LOG_ERROR("SecKey_GenerateWrappedKeyAsn1V3 failed"); + return {}; + } + + v3Key.resize(v3KeyLen); + + lastKey = ProvKey(v3Key, SEC_KEYCONTAINER_ASN1); + } + } else { + lastKey = key; + } + } + + return lastKey; +} + +Sec_Result testWrappedCipherSingleRsaAesRsaAesAes(TestKey key, TestKc kc, Sec_KeyType rsaType, + Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, Sec_CipherAlgorithm symAlg, Sec_CipherAlgorithm ckSymAlg, + WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (!TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) + return SEC_RESULT_SUCCESS; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + std::vector keys = TestCreds::getWrappedContentKeyChainRsaAesRsaAesAes(key, kc, id, rsaType, asymAlg, + aesType, symAlg, ckSymAlg); + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChain failed"); + return SEC_RESULT_FAILURE; + } + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], v3Key.key.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (cipherEncDecSingle(&ctx, id - 1, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testWrappedCipherSingleRsaAes(TestKey key, TestKc kc, Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, + WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (!TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) + return SEC_RESULT_SUCCESS; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + std::vector keys = TestCreds::getWrappedContentKeyChainRsaAes(key, kc, id, rsaType, asymAlg); + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChain failed"); + return SEC_RESULT_FAILURE; + } + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], v3Key.key.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (cipherEncDecSingle(&ctx, id - 1, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testWrappedCipherSingleEcAes(TestKey key, TestKc kc, Sec_CipherAlgorithm asymAlg, + WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (!TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) + return SEC_RESULT_SUCCESS; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + std::vector keys = TestCreds::getWrappedContentKeyChainEcAes(key, kc, id, asymAlg); + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChain failed"); + return SEC_RESULT_FAILURE; + } + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], v3Key.key.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + //check enc/dec + if (cipherEncDecSingle(&ctx, id - 1, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testWrappedCipherSingleEcAesAes(TestKey key, TestKc kc, Sec_KeyType aesType, Sec_CipherAlgorithm asymAlg, + Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (!TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) + return SEC_RESULT_SUCCESS; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + std::vector keys = TestCreds::getWrappedContentKeyChainEcAesAes(key, kc, id, aesType, asymAlg, symAlg); + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChain failed"); + return SEC_RESULT_FAILURE; + } + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], v3Key.key.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + //check enc/dec + if (cipherEncDecSingle(&ctx, id - 1, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testExportWrappedRsaAesAes(TestKey key, TestKc kc, Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, + Sec_KeyType aesType, Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (!TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) + return SEC_RESULT_SUCCESS; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + std::vector keys = TestCreds::getWrappedContentKeyChainRsaAesAes(key, kc, id, rsaType, asymAlg, aesType, + symAlg); + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChain failed"); + return SEC_RESULT_FAILURE; + } + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], v3Key.key.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID idContentKey = id - 1; + + //export content key + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + Sec_KeyHandle* keyHandle; + if (SecKey_GetInstance(ctx.proc(), idContentKey, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + SecKey_Release(keyHandle); + return SEC_RESULT_FAILURE; + } + exported_key.resize(exported_len); + SecKey_Release(keyHandle); + + //provision exported + if (SecKey_Provision(ctx.proc(), idContentKey, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, &exported_key[0], + exported_key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (cipherEncDecSingle(&ctx, idContentKey, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idContentKey, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idContentKey, &clear[0], clear.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testWrappedCipherSingleRsaAesAes(TestKey key, TestKc kc, Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, + Sec_KeyType aesType, Sec_CipherAlgorithm symAlg, + WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (!TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) + return SEC_RESULT_SUCCESS; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + std::vector keys = TestCreds::getWrappedContentKeyChainRsaAesAes(key, kc, id, rsaType, asymAlg, aesType, + symAlg); + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChainRsaAesAes failed"); + return SEC_RESULT_FAILURE; + } + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], + v3Key.key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (cipherEncDecSingle(&ctx, id - 1, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, id - 1, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +static std::vector asn1(Sec_ProcessorHandle* processorHandle, const std::vector& clear, + Sec_KeyType type, SEC_OBJECTID wrappingId, Sec_CipherAlgorithm algorithm) { + std::vector wrapped; + wrapped.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE wrapped_len; + + std::vector iv = TestCtx::random(SEC_AES_BLOCK_SIZE); + + if (SecCipher_SingleInputId(processorHandle, algorithm, SEC_CIPHERMODE_ENCRYPT, wrappingId, &iv[0], + (SEC_BYTE*) &clear[0], clear.size(), &wrapped[0], wrapped.size(), &wrapped_len) != // NOLINT + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecCipher_SingleInputId failed"); + return {}; + } + wrapped.resize(wrapped_len); + + std::vector res; + SEC_SIZE written; + res.resize(SEC_KEYCONTAINER_MAX_LEN); + + if (SecKey_GenerateWrappedKeyAsn1Off(&wrapped[0], wrapped.size(), type, wrappingId, &iv[0], algorithm, &res[0], + res.size(), &written, 0) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GenerateWrappedKeyAsn1Off failed"); + return {}; + } + + res.resize(written); + + return res; +} + +Sec_Result testWrappedKDFCMACAES128(SEC_OBJECTID idDerived, SEC_OBJECTID idBase, SEC_OBJECTID idWrapped, + Sec_KeyType keyType, SEC_BYTE counter, uint32_t L) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (ctx.provisionKey(idBase, SEC_STORAGELOC_RAM, TESTKEY_AES128, TESTKC_CONDITIONAL) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //base key + TestCtx::printHex("baseKey", TestCreds::asOpenSslAes(TESTKEY_AES128)); + + //label + std::vector otherData = TestCtx::random(10); + //separator + otherData.push_back(0); + //ctx + std::vector ctx2 = TestCtx::random(32); + otherData.insert(otherData.end(), ctx2.begin(), ctx2.end()); + + otherData.push_back(0); + otherData.push_back(0); + otherData.push_back(0); + otherData.push_back(0); + Sec_Uint32ToBEBytes(L, &otherData[otherData.size() - 4]); + + TestCtx::printHex("otherData", otherData); + + if (SecKey_Derive_CMAC_AES128(ctx.proc(), idDerived, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, idBase, &otherData[0], + otherData.size(), &counter, 1) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_CMAC_AES128 failed"); + return SEC_RESULT_FAILURE; + } + + //create wrapped key protected by CMAC_AES128 derived key + std::vector clear = TestCtx::random(SecKey_GetKeyLenForKeyType(keyType)); + TestCtx::printHex("key", clear); + + std::vector wrapped = asn1(ctx.proc(), clear, keyType, idDerived, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING); + if (wrapped.empty()) { + SEC_LOG_ERROR("Asn1 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), idWrapped, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_ASN1, &wrapped[0], + wrapped.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idWrapped, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idWrapped, &clear[0], clear.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + SecKey_Delete(ctx.proc(), idDerived); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testExportedKDFCMACAES128(SEC_OBJECTID idDerived, SEC_OBJECTID idBase, SEC_OBJECTID idWrapped, + Sec_KeyType keyType, SEC_BYTE counter, uint32_t L) { + TestCtx ctx; + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + if (ctx.provisionKey(idBase, SEC_STORAGELOC_RAM, TESTKEY_AES128, TESTKC_CONDITIONAL) == nullptr) { + SEC_LOG_ERROR("ctx.provisionKey failed"); + return SEC_RESULT_FAILURE; + } + + //export content key + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + Sec_KeyHandle* keyHandle; + if (SecKey_GetInstance(ctx.proc(), idBase, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + SecKey_Release(keyHandle); + return SEC_RESULT_FAILURE; + } + exported_key.resize(exported_len); + SecKey_Release(keyHandle); + + //provision exported + if (SecKey_Provision(ctx.proc(), idBase, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, &exported_key[0], + exported_key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + //base key + TestCtx::printHex("baseKey", TestCreds::asOpenSslAes(TESTKEY_AES128)); + + //label + std::vector otherData = TestCtx::random(10); + //separator + otherData.push_back(0); + //ctx + std::vector ctx2 = TestCtx::random(32); + otherData.insert(otherData.end(), ctx2.begin(), ctx2.end()); + + otherData.push_back(0); + otherData.push_back(0); + otherData.push_back(0); + otherData.push_back(0); + Sec_Uint32ToBEBytes(L, &otherData[otherData.size() - 4]); + + TestCtx::printHex("otherData", otherData); + + if (SecKey_Derive_CMAC_AES128(ctx.proc(), idDerived, SEC_KEYTYPE_AES_128, SEC_STORAGELOC_RAM, idBase, &otherData[0], + otherData.size(), &counter, 1) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Derive_CMAC_AES128 failed"); + return SEC_RESULT_FAILURE; + } + + //create wrapped key protected by CMAC_AES128 derived key + std::vector clear = TestCtx::random(SecKey_GetKeyLenForKeyType(keyType)); + TestCtx::printHex("key", clear); + + std::vector wrapped = asn1(ctx.proc(), clear, keyType, idDerived, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING); + if (wrapped.empty()) { + SEC_LOG_ERROR("Asn1 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), idWrapped, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_ASN1, &wrapped[0], + wrapped.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idWrapped, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idWrapped, &clear[0], clear.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + SecKey_Delete(ctx.proc(), idDerived); + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testExportWrappedEccAesAes(TestKey key, TestKc kc, Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, + Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (!TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) + return SEC_RESULT_SUCCESS; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + std::vector keys = TestCreds::getWrappedContentKeyChainEcAesAes(key, kc, id, aesType, asymAlg, symAlg); + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChainEcAesAes failed"); + return SEC_RESULT_FAILURE; + } + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], v3Key.key.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID idContentKey = id - 1; + + //export content key + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + Sec_KeyHandle* keyHandle; + if (SecKey_GetInstance(ctx.proc(), idContentKey, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + SecKey_Release(keyHandle); + return SEC_RESULT_FAILURE; + } + exported_key.resize(exported_len); + SecKey_Release(keyHandle); + + //provision exported + if (SecKey_Provision(ctx.proc(), idContentKey, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, &exported_key[0], + exported_key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (cipherEncDecSingle(&ctx, idContentKey, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idContentKey, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idContentKey, &clear[0], clear.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testExportWrappedEccAes(TestKey key, TestKc kc, Sec_CipherAlgorithm asymAlg, WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (!TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC)) + return SEC_RESULT_SUCCESS; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + std::vector keys = TestCreds::getWrappedContentKeyChainEcAes(key, kc, id, asymAlg); + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChain failed"); + return SEC_RESULT_FAILURE; + } + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], v3Key.key.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID idContentKey = id - 1; + + //export content key + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + Sec_KeyHandle* keyHandle; + if (SecKey_GetInstance(ctx.proc(), idContentKey, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + SecKey_Release(keyHandle); + return SEC_RESULT_FAILURE; + } + exported_key.resize(exported_len); + SecKey_Release(keyHandle); + + //provision exported + if (SecKey_Provision(ctx.proc(), idContentKey, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, &exported_key[0], + exported_key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (cipherEncDecSingle(&ctx, idContentKey, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idContentKey, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idContentKey, &clear[0], clear.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +static std::vector getWrappedContentKeyChainGeneratedEcAes(TestKey contentKey, EC_KEY* ec_key, + SEC_OBJECTID base_id, Sec_CipherAlgorithm asymAlg) { + std::vector res; + + //generate key1 + std::shared_ptr wrappedKey1( + TestCreds::wrapAesWithEc(TestCreds::asOpenSslAes(contentKey).data(), TestCreds::getKeyType(contentKey), + ec_key, base_id, asymAlg)); + res.push_back(*wrappedKey1); + + return res; +} + +static bool Is_Valid_Point(EC_KEY* ec_key, const std::vector& data) { + if (data.size() != SEC_ECC_NISTP256_KEY_LEN) { + SEC_LOG_ERROR("Input size needed != One BIGNUM"); + return false; + } + + // Convert the input buffer to be encrypted to a BIGNUM + std::shared_ptr inputAsBN(BN_new(), BN_free); + if (inputAsBN == nullptr) { + SEC_LOG_ERROR("BN_new failed"); + return false; + } + + if (BN_bin2bn(&data[0], static_cast(data.size()), inputAsBN.get()) == nullptr) { + SEC_LOG_ERROR("BN_bin2bn failed."); + return false; + } + + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + if (group == nullptr) { + SEC_LOG_ERROR("EC_KEY_get0_group failed"); + return false; + } + + std::shared_ptr ctx(BN_CTX_new(), BN_CTX_free); + if (ctx == nullptr) { + SEC_LOG_ERROR("BN_CTX_new failed"); + return false; + } + + std::shared_ptr pt(EC_POINT_new(group), EC_POINT_free); + if (pt == nullptr) { + SEC_LOG_ERROR("EC_POINT_new failed"); + return false; + } + + if (EC_POINT_set_compressed_coordinates_GFp(group, pt.get(), inputAsBN.get(), 0, ctx.get()) != 1) { + SEC_LOG_ERROR("EC_POINT_set_compressed_coordinates_GFp failed"); + return false; + } + + return true; +} + +template +std::vector concat(std::vector& a, std::vector& b) { + std::vector ret = std::vector(); + std::copy(a.begin(), a.end(), std::back_inserter(ret)); + std::copy(b.begin(), b.end(), std::back_inserter(ret)); + return ret; +} + +static std::vector getWrappedContentKeyChainGeneratedEcAesAes(TestKey contentKey, EC_KEY* ec_key, + SEC_OBJECTID base_id, Sec_KeyType aesType, + Sec_CipherAlgorithm asymAlg, + Sec_CipherAlgorithm symAlg) { + std::vector res; + + //generate key1 + std::vector key1 = TestCtx::random(SecKey_GetKeyLenForKeyType(aesType)); + while (!Is_Valid_Point(ec_key, + (SecKey_GetKeyLenForKeyType(aesType) == SEC_AES_BLOCK_SIZE) ? concat(key1, key1) : key1)) { + SEC_PRINT("Not a valid point. Regenerating.\n"); + key1 = TestCtx::random(SecKey_GetKeyLenForKeyType(aesType)); + } + + std::shared_ptr wrappedKey1(TestCreds::wrapAesWithEc(&key1[0], aesType, ec_key, base_id, asymAlg)); + if (wrappedKey1 == nullptr) + return res; + + res.push_back(*wrappedKey1); + + //generate key2 + std::shared_ptr wrappedKey2( + TestCreds::wrapAesWithAes(TestCreds::asOpenSslAes(contentKey).data(), TestCreds::getKeyType(contentKey), + &key1[0], aesType, base_id + 1, symAlg)); + if (wrappedKey2 == nullptr) + return res; + + res.push_back(*wrappedKey2); + + return res; +} + +static EC_KEY* ECCFromPubBinary(Sec_ECCRawPublicKey* binary) { + BN_CTX* ctx = BN_CTX_new(); + + if (binary->type != SEC_KEYTYPE_ECC_NISTP256_PUBLIC && binary->type != SEC_KEYTYPE_ECC_NISTP256) + return nullptr; + + EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); //create ec_key structure with NIST p256 curve; + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + EC_POINT* ec_point = EC_POINT_new(group); + BN_CTX_start(ctx); + BIGNUM* xp; + BIGNUM* yp; + + do { + if (((xp = BN_CTX_get(ctx)) == nullptr) || ((yp = BN_CTX_get(ctx)) == nullptr)) + break; + + EC_POINT_set_affine_coordinates_GFp(group, ec_point, + BN_bin2bn(binary->x, static_cast(Sec_BEBytesToUint32(binary->key_len)), xp), + BN_bin2bn(binary->y, static_cast(Sec_BEBytesToUint32(binary->key_len)), yp), ctx); + EC_KEY_set_public_key(ec_key, ec_point); + } while (false); + + EC_POINT_free(ec_point); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return ec_key; +} + +static EC_KEY* generateEcAndGetPublic(TestCtx& ctx, SEC_OBJECTID id) { + Sec_KeyHandle* keyHandle = ctx.provisionKey(id, SEC_STORAGELOC_RAM, TESTKEY_EC_PRIV, TESTKC_GENERATED, SEC_FALSE); + if (keyHandle == nullptr) { + SEC_LOG_ERROR("ProvisionKey failed"); + return nullptr; + } + + Sec_ECCRawPublicKey public_key; + memset(&public_key, 0, sizeof(public_key)); + if (SecKey_ExtractECCPublicKey(keyHandle, &public_key) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExtractECCPublicKey failed"); + return nullptr; + } + + EC_KEY* openssl_key = ECCFromPubBinary(&public_key); + if (openssl_key == nullptr) { + SEC_LOG_ERROR("_ECCFromPubBinary failed"); + return nullptr; + } + + return openssl_key; +} + +Sec_Result testExportWrappedGeneratedEccAesAes(TestKey key, Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, + Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + EC_KEY* pub_ec = generateEcAndGetPublic(ctx, id); + std::vector keys = getWrappedContentKeyChainGeneratedEcAesAes(key, pub_ec, id, aesType, asymAlg, symAlg); + SEC_ECC_FREE(pub_ec); + + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChain failed"); + return SEC_RESULT_FAILURE; + } + + //generated key is alreay provisioned + id++; + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], v3Key.key.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID idContentKey = id - 1; + + //export content key + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + Sec_KeyHandle* keyHandle; + if (SecKey_GetInstance(ctx.proc(), idContentKey, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + SecKey_Release(keyHandle); + return SEC_RESULT_FAILURE; + } + exported_key.resize(exported_len); + SecKey_Release(keyHandle); + + //provision exported + if (SecKey_Provision(ctx.proc(), idContentKey, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, &exported_key[0], + exported_key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (cipherEncDecSingle(&ctx, idContentKey, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idContentKey, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idContentKey, &clear[0], clear.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} + +Sec_Result testExportWrappedGeneratedEccAes(TestKey key, Sec_CipherAlgorithm asymAlg, WrappedKeyFormatVersion wkfv) { + TestCtx ctx; + + if (ctx.init() != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("TestCtx.init failed"); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID id = SEC_OBJECTID_USER_BASE; + + EC_KEY* pub_ec = generateEcAndGetPublic(ctx, id); + std::vector keys = getWrappedContentKeyChainGeneratedEcAes(key, pub_ec, id, asymAlg); + SEC_ECC_FREE(pub_ec); + + if (keys.empty()) { + SEC_LOG_ERROR("TestCreds::getWrappedContentKeyChain failed"); + return SEC_RESULT_FAILURE; + } + + //generated key is alreay provisioned + id++; + + switch (wkfv) { + case WKFV_V2: { + for (unsigned int i = 0; i < keys.size(); ++i) { + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, keys[i].kc, &keys[i].key[0], + keys[i].key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision[%d] failed", i); + return SEC_RESULT_FAILURE; + } + } + + break; + } + + case WKFV_V3: { + ProvKey v3Key = convertV2ToV3(keys); + if (v3Key.key.empty()) { + SEC_LOG_ERROR("ConvertV2ToV3 failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_Provision(ctx.proc(), id++, SEC_STORAGELOC_RAM, v3Key.kc, &v3Key.key[0], + v3Key.key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + break; + } + + default: + SEC_LOG_ERROR("Unknown WKFT encountered: %d", wkfv); + return SEC_RESULT_FAILURE; + } + + SEC_OBJECTID idContentKey = id - 1; + + //export content key + std::vector derivation_input = TestCtx::random(SEC_AES_BLOCK_SIZE); + std::vector exported_key; + exported_key.resize(SEC_KEYCONTAINER_MAX_LEN); + SEC_SIZE exported_len; + + Sec_KeyHandle* keyHandle; + if (SecKey_GetInstance(ctx.proc(), idContentKey, &keyHandle) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_GetInstance failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_ExportKey(keyHandle, &derivation_input[0], &exported_key[0], exported_key.size(), &exported_len) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_ExportKey failed"); + SecKey_Release(keyHandle); + return SEC_RESULT_FAILURE; + } + exported_key.resize(exported_len); + SecKey_Release(keyHandle); + + //provision exported + if (SecKey_Provision(ctx.proc(), idContentKey, SEC_STORAGELOC_RAM, SEC_KEYCONTAINER_EXPORTED, &exported_key[0], + exported_key.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecKey_Provision failed"); + return SEC_RESULT_FAILURE; + } + + Sec_KeyType keyType = TestCreds::getKeyType(key); + std::vector clear = TestCreds::asOpenSslAes(key); + + if (cipherEncDecSingle(&ctx, idContentKey, SEC_CIPHERALGORITHM_AES_ECB_NO_PADDING, 256) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("CipherEncDecSingle failed"); + return SEC_RESULT_FAILURE; + } + + if (SecKey_IsAES(keyType) == SEC_TRUE) { + if (aesKeyCheck(ctx.proc(), idContentKey, &clear[0], clear.size()) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("AesKeyCheck failed"); + return SEC_RESULT_FAILURE; + } + } else { + if (macCheck(ctx.proc(), SEC_MACALGORITHM_HMAC_SHA256, idContentKey, &clear[0], clear.size()) != + SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("MacCheck failed"); + return SEC_RESULT_FAILURE; + } + } + + return SEC_RESULT_SUCCESS; +} diff --git a/test/main/cpp/wrapped.h b/test/main/cpp/wrapped.h new file mode 100644 index 0000000..01b565c --- /dev/null +++ b/test/main/cpp/wrapped.h @@ -0,0 +1,60 @@ +/** + * Copyright 2020 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef WRAPPED_H +#define WRAPPED_H + +#include "sec_security.h" +#include "test_creds.h" + +Sec_Result testWrappedCipherSingleRsaAes(TestKey key, TestKc kc, Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, + WrappedKeyFormatVersion wkfv); + +Sec_Result testWrappedCipherSingleRsaAesAes(TestKey key, TestKc kc, Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, + Sec_KeyType aesType, Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv); + +Sec_Result testWrappedCipherSingleRsaAesRsaAesAes(TestKey key, TestKc kc, Sec_KeyType rsaType, + Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, Sec_CipherAlgorithm symAlg, Sec_CipherAlgorithm ckSymAlg, + WrappedKeyFormatVersion wkfv); + +Sec_Result testWrappedCipherSingleEcAes(TestKey key, TestKc kc, Sec_CipherAlgorithm asymAlg, + WrappedKeyFormatVersion wkfv); + +Sec_Result testWrappedCipherSingleEcAesAes(TestKey key, TestKc kc, Sec_KeyType aesType, Sec_CipherAlgorithm asymAlg, + Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv); + +Sec_Result testExportWrappedRsaAesAes(TestKey key, TestKc kc, Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, + Sec_KeyType aesType, Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv); + +Sec_Result testWrappedKDFCMACAES128(SEC_OBJECTID idDerived, SEC_OBJECTID idBase, SEC_OBJECTID idWrapped, + Sec_KeyType keyType, SEC_BYTE counter, uint32_t L); + +Sec_Result testExportedKDFCMACAES128(SEC_OBJECTID idDerived, SEC_OBJECTID idBase, SEC_OBJECTID idWrapped, + Sec_KeyType keyType, SEC_BYTE counter, uint32_t L); + +Sec_Result testExportWrappedEccAesAes(TestKey key, TestKc kc, Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, + Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv); + +Sec_Result testExportWrappedEccAes(TestKey key, TestKc kc, Sec_CipherAlgorithm asymAlg, WrappedKeyFormatVersion wkfv); + +Sec_Result testExportWrappedGeneratedEccAesAes(TestKey key, Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, + Sec_CipherAlgorithm symAlg, WrappedKeyFormatVersion wkfv); + +Sec_Result testExportWrappedGeneratedEccAes(TestKey key, Sec_CipherAlgorithm asymAlg, WrappedKeyFormatVersion wkfv); + +#endif // WRAPPED_H diff --git a/test/main/headers/test_creds.h b/test/main/headers/test_creds.h new file mode 100644 index 0000000..ccd5f28 --- /dev/null +++ b/test/main/headers/test_creds.h @@ -0,0 +1,161 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_CREDS_H +#define TEST_CREDS_H + +#include "sec_security.h" +#include +#include +#include +#include + +#define TESTKC_CONDITIONAL TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC) ? TESTKC_SOC : TESTKC_RAW + +enum TestKey { + TESTKEY_AES128 = 0, + TESTKEY_AES256, + TESTKEY_HMAC128, + TESTKEY_HMAC160, + TESTKEY_HMAC256, + TESTKEY_RSA1024_SGN_PRIV, + TESTKEY_RSA1024_SGN_PUB, + TESTKEY_RSA1024_ENC_PRIV, + TESTKEY_RSA1024_ENC_PUB, + TESTKEY_RSA1024_KEK_PRIV, + TESTKEY_RSA1024_KEK_PUB, + TESTKEY_RSA2048_SGN_PRIV, + TESTKEY_RSA2048_SGN_PUB, + TESTKEY_RSA2048_ENC_PRIV, + TESTKEY_RSA2048_ENC_PUB, + TESTKEY_RSA2048_KEK_PRIV, + TESTKEY_RSA2048_KEK_PUB, + TESTKEY_EC_PRIV, + TESTKEY_EC_PUB, + TESTKEY_NUM +}; + +enum TestKc { + TESTKC_RAW, + TESTKC_STORE, + TESTKC_SOC, + TESTKC_GENERATED, + TESTKC_EXPORTED, + TESTKC_NUM +}; + +enum TestCert { + TESTCERT_RSA1024 = 0, + TESTCERT_RSA2048, + TESTCERT_EC, + TESTCERT_NUM +}; + +enum WrappedKeyFormatVersion { + WKFV_V2 = 2, //with offset field + WKFV_V3 //with embedded wrappedKey +}; + +enum Capability { + CAPABILITY_AES256 = 0, + CAPABILITY_HMAC_IN_HW, + CAPABILITY_CMAC_IN_HW, + CAPABILITY_DIGEST_OVER_HWKEY, + CAPABILITY_HMAC_OVER_HWKEY, + CAPABILITY_CMAC_OVER_HWKEY, + CAPABILITY_HKDF_CMAC, + CAPABILITY_EXTRACT_RSA_PUB, + CAPABILITY_WRAPPED_KEY_FORMAT_V3, //nested key containers + CAPABILITY_RSA_AES_M2M, + CAPABILITY_CLEAR_JTYPE_WRAPPING, // SOC only + CAPABILITY_SVP, + CAPABILITY_LOAD_SYM_SOC_KC, + CAPABILITY_EXPORT_RSA, + CAPABILITY_RSA_1024, + CAPABILITY_RSA_AESCBC_AES, + CAPABILITY_RSA_AESCTR_AES, + CAPABILITY_RSA_AESCTR_RSA, + CAPABILITY_NUM +}; + +class TestCtx; + +class ProvKey { +public: + ProvKey() { + } + + ProvKey(std::vector _key, Sec_KeyContainer _kc) { + key = _key; + kc = _kc; + } + std::vector key; + Sec_KeyContainer kc; +}; + +class ProvCert { +public: + ProvCert(std::vector _cert, Sec_CertificateContainer _cc) { + cert = _cert; + cc = _cc; + } + std::vector cert; + Sec_CertificateContainer cc; +}; + +class TestCreds { +public: + static ProvKey* getKey(TestKey key, TestKc kc, SEC_OBJECTID id); + static Sec_KeyType getKeyType(TestKey key); + static ProvCert* getCert(TestCert cert); + + static std::vector asOpenSslAes(TestKey key); + static RSA* asOpenSslRsa(TestKey key); + static EC_KEY* asOpenSslEcKey(TestKey key); + static EVP_PKEY* asOpenSslEvpPkey(TestKey key); + + //following stubs should be implemented by the SOC vendors in test_creds_soc.cpp + static ProvKey* getSocKey(TestKey key, SEC_OBJECTID id); + static Sec_Result preprovisionSoc(TestCtx* testCtx); + static SEC_BOOL supports(Capability cap); + static void init(); + static void shutdown(); + + static std::vector getWrappedContentKeyChainRsaAes(TestKey contentKey, TestKc kc, SEC_OBJECTID id, + Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg); + static std::vector getWrappedContentKeyChainRsaAesAes(TestKey contentKey, TestKc kc, SEC_OBJECTID id, + Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, Sec_CipherAlgorithm symAlg); + static std::vector getWrappedContentKeyChainRsaAesRsaAesAes(TestKey contentKey, TestKc kc, SEC_OBJECTID id, + Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, Sec_CipherAlgorithm symAlg, + Sec_CipherAlgorithm ckSymAlg); + static std::vector getWrappedContentKeyChainEcAes(TestKey contentKey, TestKc kc, SEC_OBJECTID id, + Sec_CipherAlgorithm asymAlg); + static std::vector getWrappedContentKeyChainEcAesAes(TestKey contentKey, TestKc kc, SEC_OBJECTID base_id, + Sec_KeyType aesType, Sec_CipherAlgorithm asymAlg, Sec_CipherAlgorithm symAlg); + + static ProvKey* wrapAesWithAes(const SEC_BYTE* clear, Sec_KeyType type, const SEC_BYTE* wrapping, + Sec_KeyType wrappingType, SEC_OBJECTID wrappingId, Sec_CipherAlgorithm symAlg); + static ProvKey* wrapAesWithEc(const SEC_BYTE* clear, Sec_KeyType type, EC_KEY* ec_key, SEC_OBJECTID wrappingId, + Sec_CipherAlgorithm asymAlg); + static ProvKey* wrapAesWithRsa(const SEC_BYTE* data, Sec_KeyType type, RSA* rsa_key, SEC_OBJECTID wrappingId, + Sec_CipherAlgorithm asymAlg); + static ProvKey* wrapRsaWithAes(RSA* rsa, const SEC_BYTE* wrapping, Sec_KeyType wrappingType, + SEC_OBJECTID wrappingId, Sec_CipherAlgorithm symAlg); +}; + +#endif // TEST_CREDS_H diff --git a/test/main/headers/test_ctx.h b/test/main/headers/test_ctx.h new file mode 100644 index 0000000..ff65798 --- /dev/null +++ b/test/main/headers/test_ctx.h @@ -0,0 +1,192 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_CTX_H +#define TEST_CTX_H + +#include "sec_security.h" // NOLINT +#include "test_creds.h" +#include +#include +#include +#include +#include + +//#define ENABLE_FULL_LOGS + +#ifdef ENABLE_FULL_LOGS +#define DELAYED_LOG 0 +#else +#define DELAYED_LOG 1 +#endif + +enum TestState { + TESTRESULT_SUCCEEDED = 0, + TESTRESULT_FAILED, + TESTRESULT_SKIPPED, + TESTRESULT_NUM +}; + +#define SEC_PRINT_HEX(name, ptr, size) \ + SEC_PRINT("%s[%d]: ", name, size); \ + Sec_PrintHex(ptr, size); \ + SEC_PRINT("\n"); +#define RUN_TEST(suite, function) \ + { \ + int testIdx = (suite)->addTest(#function); \ +\ + if ((suite)->shouldRun(testIdx)) { \ + if (DELAYED_LOG) { \ + Logger::init(); \ + } \ + SEC_PRINT("\n"); \ + SEC_PRINT("%d: " #function " STARTING\n", testIdx); \ + Sec_Result result = function; \ + std::string output = DELAYED_LOG ? Logger::output() : std::string(); \ + if (DELAYED_LOG) { \ + Logger::shutdown(); \ + } \ + if (res == SEC_RESULT_SUCCESS) { \ + SEC_PRINT("%d: " #function " SUCCEEDED\n", testIdx); \ + (suite)->setTestState(testIdx, TESTRESULT_SUCCEEDED); \ + } else { \ + SEC_PRINT(output.c_str()); \ + SEC_PRINT("%d: " #function " FAILED\n\n", testIdx); \ + (suite)->setTestState(testIdx, TESTRESULT_FAILED); \ + } \ + } else { \ + (suite)->setTestState(testIdx, TESTRESULT_SKIPPED); \ + if ((suite)->shouldPrint(testIdx)) { \ + SEC_PRINT("%d: " #function "\n", testIdx); \ + } \ + } \ + } + +class SuiteCtx { + typedef std::pair TestEntry; + +public: + SuiteCtx() = default; + ~SuiteCtx() = default; + + void setRunParams(const std::vector& runParams) { + runParams_ = runParams; + } + bool shouldRun(int id) const { + return runParams_.empty() || std::find(runParams_.begin(), runParams_.end(), id) != runParams_.end(); + } + bool shouldPrint(int id) const { + return shouldRun(id) || (runParams_.size() == 1 && runParams_[0] <= 0); + } + size_t addTest(const char* name) { + tests_.emplace_back(name, TESTRESULT_NUM); + return tests_.size(); + } + void setTestState(int id, TestState state) { + tests_[id - 1].second = state; + } + TestEntry getTestEntry(int id) const { + return tests_[id - 1]; + } + std::vector getFailed() const; + std::vector getSucceeded() const; + std::vector getSkipped() const; + std::vector getAttempted() const; + std::vector getAll() const; + +private: + std::vector tests_; + std::vector runParams_; +}; + +class TestCtx { +public: + TestCtx(); + ~TestCtx(); + + Sec_Result init(const char* global_dir = "/tmp/sec_api_test_global", const char* app_dir = "/tmp/sec_api_test_app"); + + Sec_KeyHandle* provisionKey(SEC_OBJECTID id, Sec_StorageLoc location, TestKey key, TestKc, + bool softWrap = SEC_FALSE); + Sec_KeyHandle* provisionKey(SEC_OBJECTID id, Sec_StorageLoc location, const SEC_BYTE* data, SEC_SIZE len, + Sec_KeyContainer kc, bool softWrap = SEC_FALSE); + Sec_KeyHandle* getKey(SEC_OBJECTID id); + void releaseKey(Sec_KeyHandle* keyHandle); + void deleteKey(SEC_OBJECTID id); + + Sec_CertificateHandle* provisionCert(SEC_OBJECTID id, Sec_StorageLoc location, TestCert cert); + Sec_CertificateHandle* getCert(SEC_OBJECTID id); + void releaseCert(Sec_CertificateHandle* certificateHandle); + void deleteCert(SEC_OBJECTID id); + + Sec_BundleHandle* provisionBundle(SEC_OBJECTID id, Sec_StorageLoc location, const std::vector& bundle); + Sec_BundleHandle* getBundle(SEC_OBJECTID id); + void releaseBundle(Sec_BundleHandle* bundleHandle); + void deleteBundle(SEC_OBJECTID id); + + Sec_MacHandle* acquireMac(Sec_MacAlgorithm algorithm, Sec_KeyHandle* keyHandle); + Sec_Result releaseMac(Sec_MacHandle* macHandle, SEC_BYTE* macBuffer, SEC_SIZE* macSize); + void releaseMac(Sec_MacHandle* macHandle); + + Sec_CipherHandle* acquireCipher(Sec_CipherAlgorithm algorithm, Sec_CipherMode mode, Sec_KeyHandle* keyHandle, + SEC_BYTE* iv); + void releaseCipher(Sec_CipherHandle* cipherHandle); + + Sec_SignatureHandle* signatureHandleacquireSignature(Sec_SignatureAlgorithm algorithm, Sec_SignatureMode mode, + Sec_KeyHandle* keyHandle); void releaseSignature(Sec_SignatureHandle* signatureHandlesig); + + Sec_DigestHandle* acquireDigest(Sec_DigestAlgorithm algorithm); + Sec_Result releaseDigest(Sec_DigestHandle* digestHandle, SEC_BYTE* digestOutput, SEC_SIZE* digestSize); + void releaseDigest(Sec_DigestHandle* digestHandle); + + Sec_RandomHandle* acquireRandom(Sec_RandomAlgorithm algorithm); + void releaseRandom(Sec_RandomHandle* randomHandle); + + Sec_ProcessorHandle* proc() { + return proc_; + } + + //utils + static void printHex(const char* label, const std::vector& data); + static std::vector random(SEC_SIZE len); + static std::vector coalesceInputs(const std::vector>& inputs); + static SEC_SIZE coalesceInputSizes(const std::vector& inputSizes); + +private: + Sec_ProcessorHandle* proc_; + std::list provisionedKeys_; + std::list keys_; + std::list provisionedCerts_; + std::list certs_; + std::list provisionedBundles_; + std::list bundles_; + std::list macs_; + std::list ciphers_; + std::list sigs_; + std::list digests_; + std::list randoms_; +}; + +class Logger { +public: + static void init(); + static void shutdown(); + static const char* output(); +}; + +#endif // TEST_CTX_H diff --git a/test/openssl/headers/sa_soc_key_container.h b/test/openssl/headers/sa_soc_key_container.h new file mode 100644 index 0000000..9c53688 --- /dev/null +++ b/test/openssl/headers/sa_soc_key_container.h @@ -0,0 +1,29 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SA_SOC_KEY_CONTAINER_H +#define SA_SOC_KEY_CONTAINER_H + +#include +#include +#include + +std::vector generate_sa_soc_key_container(std::vector& key_clear, std::string& key_type, + std::vector& tag); + +#endif diff --git a/test/openssl/headers/test_creds.h b/test/openssl/headers/test_creds.h new file mode 100644 index 0000000..c9d23ba --- /dev/null +++ b/test/openssl/headers/test_creds.h @@ -0,0 +1,164 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_CREDS_H +#define TEST_CREDS_H + +#include "sec_security.h" +#include +#include +#include +#include +#include +#include + +#define TESTKC_CONDITIONAL TestCreds::supports(CAPABILITY_LOAD_SYM_SOC_KC) ? TESTKC_SOC : TESTKC_RAW + +enum TestKey { + TESTKEY_AES128 = 0, + TESTKEY_AES256, + TESTKEY_HMAC128, + TESTKEY_HMAC160, + TESTKEY_HMAC256, + TESTKEY_RSA1024_SGN_PRIV, + TESTKEY_RSA1024_SGN_PUB, + TESTKEY_RSA1024_ENC_PRIV, + TESTKEY_RSA1024_ENC_PUB, + TESTKEY_RSA1024_KEK_PRIV, + TESTKEY_RSA1024_KEK_PUB, + TESTKEY_RSA2048_SGN_PRIV, + TESTKEY_RSA2048_SGN_PUB, + TESTKEY_RSA2048_ENC_PRIV, + TESTKEY_RSA2048_ENC_PUB, + TESTKEY_RSA2048_KEK_PRIV, + TESTKEY_RSA2048_KEK_PUB, + TESTKEY_EC_PRIV, + TESTKEY_EC_PUB, + TESTKEY_ROOT, + TESTKEY_NUM +}; + +enum TestKc { + TESTKC_RAW, + TESTKC_STORE, + TESTKC_SOC, + TESTKC_GENERATED, + TESTKC_EXPORTED, + TESTKC_NUM +}; + +enum TestCert { + TESTCERT_RSA1024 = 0, + TESTCERT_RSA2048, + TESTCERT_EC, + TESTCERT_NUM +}; + +enum WrappedKeyFormatVersion { + WKFV_V2 = 2, //with offset field + WKFV_V3 //with embedded wrappedKey +}; + +enum Capability { + CAPABILITY_AES256 = 0, + CAPABILITY_HMAC_IN_HW, + CAPABILITY_CMAC_IN_HW, + CAPABILITY_DIGEST_OVER_HWKEY, + CAPABILITY_HMAC_OVER_HWKEY, + CAPABILITY_CMAC_OVER_HWKEY, + CAPABILITY_HKDF_CMAC, + CAPABILITY_EXTRACT_RSA_PUB, + CAPABILITY_WRAPPED_KEY_FORMAT_V3, //nested key containers + CAPABILITY_RSA_AES_M2M, + CAPABILITY_CLEAR_JTYPE_WRAPPING, // SOC only + CAPABILITY_SVP, + CAPABILITY_LOAD_SYM_SOC_KC, + CAPABILITY_EXPORT_RSA, + CAPABILITY_RSA_1024, + CAPABILITY_RSA_AESCBC_AES, + CAPABILITY_RSA_AESCTR_AES, + CAPABILITY_RSA_AESCTR_RSA, + CAPABILITY_NUM +}; + +class TestCtx; + +class ProvKey { // NOLINT +public: + ProvKey() = default; // NOLINT + + ProvKey(std::vector _key, Sec_KeyContainer _kc) + : key(std::move(_key)), kc(_kc) { + } + + std::vector key; // NOLINT + Sec_KeyContainer kc; // NOLINT +}; + +class ProvCert { +public: + ProvCert(std::vector _cert, Sec_CertificateContainer _cc) + : cert(std::move(_cert)), cc(_cc) { + } + + std::vector cert; // NOLINT + Sec_CertificateContainer cc; // NOLINT +}; + +class TestCreds { +public: + static ProvKey* getKey(TestKey key, TestKc kc, SEC_OBJECTID id); + static Sec_KeyType getKeyType(TestKey key); + static ProvCert* getCert(TestCert cert); + + static std::vector asOpenSslAes(TestKey key); + static RSA* asOpenSslRsa(TestKey key); + static EC_KEY* asOpenSslEcKey(TestKey key); + static EVP_PKEY* asOpenSslEvpPkey(TestKey key); + + //following stubs should be implemented by the SOC vendors in test_creds_soc.cpp + static ProvKey* getSocKey(TestKey key, SEC_OBJECTID id); + static Sec_Result preprovisionSoc(TestCtx* testCtx); + static bool supports(Capability cap); + static void init(); + static void shutdown(); + + static std::vector getWrappedContentKeyChainRsaAes(TestKey contentKey, TestKc kc, SEC_OBJECTID id, + Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg); + static std::vector getWrappedContentKeyChainRsaAesAes(TestKey contentKey, TestKc kc, SEC_OBJECTID id, + Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, Sec_CipherAlgorithm symAlg); + static std::vector getWrappedContentKeyChainRsaAesRsaAesAes(TestKey contentKey, TestKc kc, SEC_OBJECTID id, + Sec_KeyType rsaType, Sec_CipherAlgorithm asymAlg, Sec_KeyType aesType, Sec_CipherAlgorithm symAlg, + Sec_CipherAlgorithm ckSymAlg); + static std::vector getWrappedContentKeyChainEcAes(TestKey contentKey, TestKc kc, SEC_OBJECTID id, + Sec_CipherAlgorithm asymAlg); + static std::vector getWrappedContentKeyChainEcAesAes(TestKey contentKey, TestKc kc, SEC_OBJECTID base_id, + Sec_KeyType aesType, Sec_CipherAlgorithm asymAlg, Sec_CipherAlgorithm symAlg); + + static ProvKey* wrapAesWithAes(const SEC_BYTE* clear, Sec_KeyType type, const SEC_BYTE* wrapping, + Sec_KeyType wrappingType, SEC_OBJECTID wrappingId, Sec_CipherAlgorithm symAlg); + static ProvKey* wrapAesWithEc(const SEC_BYTE* clear, Sec_KeyType type, EC_KEY* ec_key, SEC_OBJECTID wrappingId, + Sec_CipherAlgorithm asymAlg); + static ProvKey* wrapAesWithRsa(const SEC_BYTE* data, Sec_KeyType type, RSA* rsa_key, SEC_OBJECTID wrappingId, + Sec_CipherAlgorithm asymAlg); + static ProvKey* wrapRsaWithAes(RSA* rsa, const SEC_BYTE* wrapping, Sec_KeyType wrappingType, + SEC_OBJECTID wrappingId, Sec_CipherAlgorithm symAlg); + static std::string b64_encode(const void* in, size_t in_length); +}; + +#endif // TEST_CREDS_H diff --git a/test/openssl/headers/test_ctx.h b/test/openssl/headers/test_ctx.h new file mode 100644 index 0000000..b3bd4ef --- /dev/null +++ b/test/openssl/headers/test_ctx.h @@ -0,0 +1,192 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_CTX_H +#define TEST_CTX_H + +#include "test_creds.h" +#include +#include +#include +#include +#include + +//#define ENABLE_FULL_LOGS + +#ifdef ENABLE_FULL_LOGS +#define DELAYED_LOG 0 +#else +#define DELAYED_LOG 1 +#endif + +enum TestState { + TESTRESULT_SUCCEEDED = 0, + TESTRESULT_FAILED, + TESTRESULT_SKIPPED, + TESTRESULT_NUM +}; + +#define SEC_PRINT_HEX(name, ptr, size) \ + SEC_PRINT("%s[%d]: ", name, size); \ + Sec_PrintHex(ptr, size); \ + SEC_PRINT("\n"); +#define RUN_TEST(suite, function) \ + { \ + int testIdx = (suite)->addTest(#function); \ +\ + if ((suite)->shouldRun(testIdx)) { \ + if (DELAYED_LOG) { \ + Logger::init(); \ + } \ + SEC_PRINT("\n"); \ + SEC_PRINT("%d: " #function " STARTING\n", testIdx); \ + Sec_Result result = function; \ + std::string output = DELAYED_LOG ? Logger::output() : std::string(); \ + if (DELAYED_LOG) { \ + Logger::shutdown(); \ + } \ + if (result == SEC_RESULT_SUCCESS) { \ + SEC_PRINT("%d: " #function " SUCCEEDED\n", testIdx); \ + (suite)->setTestState(testIdx, TESTRESULT_SUCCEEDED); \ + } else { \ + SEC_PRINT(output.c_str()); \ + SEC_PRINT("%d: " #function " FAILED\n\n", testIdx); \ + (suite)->setTestState(testIdx, TESTRESULT_FAILED); \ + } \ + } else { \ + (suite)->setTestState(testIdx, TESTRESULT_SKIPPED); \ + if ((suite)->shouldPrint(testIdx)) { \ + SEC_PRINT("%d: " #function "\n", testIdx); \ + } \ + } \ + } + +class SuiteCtx { + typedef std::pair TestEntry; + +public: + SuiteCtx() = default; + ~SuiteCtx() = default; + + void setRunParams(const std::vector& runParams) { + runParams_ = runParams; + } + bool shouldRun(int id) const { + return runParams_.empty() || std::find(runParams_.begin(), runParams_.end(), id) != runParams_.end(); + } + bool shouldPrint(int id) const { + return shouldRun(id) || (runParams_.size() == 1 && runParams_[0] <= 0); + } + size_t addTest(const char* name) { + tests_.emplace_back(name, TESTRESULT_NUM); + return tests_.size(); + } + void setTestState(int id, TestState state) { + tests_[id - 1].second = state; + } + TestEntry getTestEntry(int id) const { + return tests_[id - 1]; + } + std::vector getFailed() const; + std::vector getSucceeded() const; + std::vector getSkipped() const; + std::vector getAttempted() const; + std::vector getAll() const; + +private: + std::vector tests_; + std::vector runParams_; +}; + +class TestCtx { +public: + TestCtx() = default; + ~TestCtx(); + + Sec_Result init(const char* global_dir = "/tmp/sec_api_test_global", const char* app_dir = "/tmp/sec_api_test_app"); + + Sec_KeyHandle* provisionKey(SEC_OBJECTID id, Sec_StorageLoc location, TestKey key, TestKc kc, + bool softWrap = false); + Sec_KeyHandle* provisionKey(SEC_OBJECTID id, Sec_StorageLoc location, const SEC_BYTE* data, SEC_SIZE len, + Sec_KeyContainer kc, bool softWrap = false); + Sec_KeyHandle* getKey(SEC_OBJECTID id); + void releaseKey(Sec_KeyHandle* keyHandle); + void deleteKey(SEC_OBJECTID id); + + Sec_CertificateHandle* provisionCert(SEC_OBJECTID id, Sec_StorageLoc location, TestCert cert); + Sec_CertificateHandle* getCert(SEC_OBJECTID id); + void releaseCert(Sec_CertificateHandle* certificateHandle); + void deleteCert(SEC_OBJECTID id); + + Sec_BundleHandle* provisionBundle(SEC_OBJECTID id, Sec_StorageLoc location, const std::vector& bundle); + Sec_BundleHandle* getBundle(SEC_OBJECTID id); + void releaseBundle(Sec_BundleHandle* bundleHandle); + void deleteBundle(SEC_OBJECTID id); + + Sec_MacHandle* acquireMac(Sec_MacAlgorithm algorithm, Sec_KeyHandle* keyHandle); + Sec_Result releaseMac(Sec_MacHandle* macHandle, SEC_BYTE* macBuffer, SEC_SIZE* macSize); + void releaseMac(Sec_MacHandle* macHandle); + + Sec_CipherHandle* acquireCipher(Sec_CipherAlgorithm algorithm, Sec_CipherMode mode, Sec_KeyHandle* keyHandle, + SEC_BYTE* iv); + void releaseCipher(Sec_CipherHandle* cipherHandle); + + Sec_SignatureHandle* acquireSignature(Sec_SignatureAlgorithm algorithm, Sec_SignatureMode mode, + Sec_KeyHandle* keyHandle); + void releaseSignature(Sec_SignatureHandle* signatureHandle); + + Sec_DigestHandle* acquireDigest(Sec_DigestAlgorithm algorithm); + Sec_Result releaseDigest(Sec_DigestHandle* digestHandle, SEC_BYTE* digestOutput, SEC_SIZE* digestSize); + void releaseDigest(Sec_DigestHandle* digestHandle); + + Sec_RandomHandle* acquireRandom(Sec_RandomAlgorithm algorithm); + void releaseRandom(Sec_RandomHandle* randomHandle); + + Sec_ProcessorHandle* proc() { + return proc_; + } + + //utils + static void printHex(const char* label, const std::vector& data); + static std::vector random(SEC_SIZE len); + static std::vector coalesceInputs(const std::vector>& inputs); + static SEC_SIZE coalesceInputSizes(const std::vector& inputSizes); + +private: + Sec_ProcessorHandle* proc_ = nullptr; + std::list provisionedKeys_; + std::list keys_; + std::list provisionedCerts_; + std::list certs_; + std::list provisionedBundles_; + std::list bundles_; + std::list macs_; + std::list ciphers_; + std::list sigs_; + std::list digests_; + std::list randoms_; +}; + +class Logger { +public: + static void init(); + static void shutdown(); + static const char* output(); +}; + +#endif // TEST_CTX_H diff --git a/test/openssl/src/sa_soc_key_container.cpp b/test/openssl/src/sa_soc_key_container.cpp new file mode 100644 index 0000000..cda1235 --- /dev/null +++ b/test/openssl/src/sa_soc_key_container.cpp @@ -0,0 +1,189 @@ +/** + * Copyright 2020-2021 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sa_soc_key_container.h" // NOLINT +#include "cipher.h" +#include +#include + +static std::vector ENTITLED_TA_IDS = { + "157f768f-bad0-470b-929d-0d7dec29d220", + "157f768f-bad0-470b-929d-0d7dec29d221", + "157f768f-bad0-470b-929d-0d7dec29d222", + "157f768f-bad0-470b-929d-0d7dec29d223", + "157f768f-bad0-470b-929d-0d7dec29d224", + "157f768f-bad0-470b-929d-0d7dec29d225", + "157f768f-bad0-470b-929d-0d7dec29d226", + "00000000-0000-0000-0000-000000000001"}; + +static std::vector TEST_C1 = { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}; + +static std::vector TEST_C2 = { + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}; + +static std::vector TEST_C3 = { + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33}; + +static std::vector TEST_IV = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC}; + +static std::vector derive_container_encryption_key( + std::vector& c1, + std::vector& c2, + std::vector& c3) { + + auto stage1 = opensslAesEcb(TESTKEY_ROOT, SEC_CIPHERMODE_DECRYPT, SEC_FALSE, nullptr, c1); + if (stage1.empty() || stage1.size() != 16) + return {}; + + auto stage2 = opensslAesEcb(stage1, SEC_CIPHERMODE_DECRYPT, SEC_FALSE, nullptr, c2); + if (stage2.empty() || stage2.size() != 16) + return {}; + + auto stage3 = opensslAesEcb(stage2, SEC_CIPHERMODE_DECRYPT, SEC_FALSE, nullptr, c3); + if (stage3.empty() || stage3.size() != 16) + return {}; + + return stage3; +} + +std::string generate_encrypted_key( + uint8_t container_version, + std::string& key_type, + std::vector& key, + std::vector& iv, + uint8_t key_usage, + uint8_t decrypted_key_usage, + std::vector& entitled_ta_ids, + std::vector& c1, + std::vector& c2, + std::vector& c3, + std::vector& tag) { + + std::string alg = "A128GCM"; + std::vector aad; + aad.insert(aad.end(), alg.begin(), alg.end()); + aad.insert(aad.end(), container_version); + aad.insert(aad.end(), key_type.begin(), key_type.end()); + aad.insert(aad.end(), key_usage); + if (container_version >= 3 && key_usage == 2) + aad.insert(aad.end(), decrypted_key_usage); + + aad.insert(aad.end(), iv.begin(), iv.end()); + aad.insert(aad.end(), c1.begin(), c1.end()); + aad.insert(aad.end(), c2.begin(), c2.end()); + aad.insert(aad.end(), c3.begin(), c3.end()); + for (auto& ta_id : entitled_ta_ids) { + aad.insert(aad.end(), ta_id.begin(), ta_id.end()); + } + + tag.resize(16); + + auto derived_key = derive_container_encryption_key(c1, c2, c3); + if (derived_key.empty()) + return ""; + + std::vector encrypted_key = opensslAesGcm(derived_key, SEC_CIPHERMODE_ENCRYPT, iv.data(), aad.data(), + aad.size(), tag.data(), tag.size(), key); + + if (encrypted_key.empty()) + return ""; + + return TestCreds::b64_encode(encrypted_key.data(), encrypted_key.size()); +} + +std::string generate_header() { + std::string hdr = R"({"alg": "A128GCM"})"; + return TestCreds::b64_encode(hdr.data(), hdr.size()); +} + +std::string generate_payload( + uint8_t container_version, + std::string& key_type, + std::vector& key, + std::vector& iv, + uint8_t key_usage, + uint8_t decrypted_key_usage, + std::vector& entitled_ta_ids, + std::vector& c1, + std::vector& c2, + std::vector& c3, + std::vector& tag) { + + std::ostringstream oss; + + oss << R"({"containerVersion": )" << static_cast(container_version); + if (!key_type.empty()) + oss << R"(, "keyType": ")" << key_type << "\""; + + std::string encrypted_key = generate_encrypted_key(container_version, key_type, key, iv, key_usage, + decrypted_key_usage, entitled_ta_ids, c1, c2, c3, tag); + if (encrypted_key.empty()) + return ""; + + oss << R"(, "encryptedKey": ")" << encrypted_key << "\""; + + if (!iv.empty()) + oss << R"(, "iv": ")" << TestCreds::b64_encode(iv.data(), iv.size()) << "\""; + + oss << R"(, "keyUsage": )" << static_cast(key_usage); + + if (container_version >= 3 && key_usage == 2) + oss << R"(, "decryptedKeyUsage": )" << static_cast(decrypted_key_usage); + + if (!entitled_ta_ids.empty()) { + oss << R"(, "entitledTaIds": [)"; + for (size_t i = 0; i < entitled_ta_ids.size(); i++) { + if (i > 0) + oss << ", "; + + oss << "\"" << entitled_ta_ids[i] << "\""; + } + + oss << "]"; + } + + if (!c1.empty()) + oss << R"(, "c1": ")" << TestCreds::b64_encode(c1.data(), c1.size()) << "\""; + + if (!c2.empty()) + oss << R"(, "c2": ")" << TestCreds::b64_encode(c2.data(), c2.size()) << "\""; + + if (!c1.empty()) + oss << R"(, "c3": ")" << TestCreds::b64_encode(c3.data(), c3.size()) << "\""; + + oss << "}"; + + return TestCreds::b64_encode(oss.str().data(), oss.str().size()); +} + +std::vector generate_sa_soc_key_container(std::vector& key_clear, + std::string& key_type, + std::vector& tag) { + auto jwt_header = generate_header(); + auto jwt_payload = generate_payload(3, key_type, key_clear, TEST_IV, 3, 3, ENTITLED_TA_IDS, TEST_C1, TEST_C2, + TEST_C3, tag); + std::string key_container = jwt_header + "." + jwt_payload + "." + TestCreds::b64_encode(tag.data(), tag.size()); + + auto kc = std::vector(key_container.begin(), key_container.end()); + return kc; +} diff --git a/test/openssl/src/test_creds_soc.cpp b/test/openssl/src/test_creds_soc.cpp new file mode 100644 index 0000000..6a18124 --- /dev/null +++ b/test/openssl/src/test_creds_soc.cpp @@ -0,0 +1,225 @@ +/** + * Copyright 2020-2022 Comcast Cable Communications Management, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sa.h" +#include "sec_adapter_utils.h" +#include "test_creds.h" +#include "test_ctx.h" +#include +#include + +#define SEC_OBJECTID_OPENSSL_KPK SEC_OBJECTID_RESERVEDPLATFORM_7 + +static std::vector random(SEC_SIZE len) { + std::vector res; + res.resize(len); + + if (RAND_bytes(&res[0], static_cast(len)) != OPENSSL_SUCCESS) { + SEC_LOG_ERROR("RAND_bytes failed"); + return {}; + } + + return res; +} + +static void rights_set_allow_all(sa_rights* rights, Sec_KeyContainer key_type) { + memset(rights->id, 0, sizeof(rights->id)); + + rights->not_before = 0; + rights->not_on_or_after = UINT64_MAX; + + rights->usage_flags = 0; + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_KEY_EXCHANGE); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_DERIVE); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_UNWRAP); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_ENCRYPT); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_DECRYPT); + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_SIGN); + rights->usage_flags |= SA_USAGE_OUTPUT_PROTECTIONS_MASK; + SA_USAGE_BIT_SET(rights->usage_flags, SA_USAGE_FLAG_CACHEABLE); + + memset(rights->allowed_tas, 0, sizeof(rights->allowed_tas)); + + const sa_uuid ALL_MATCH = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + memcpy(&rights->allowed_tas[7], &ALL_MATCH, sizeof(sa_uuid)); +} + +std::string TestCreds::b64_encode( + const void* in, + size_t in_length) { + + if (in == nullptr) { + SEC_LOG_ERROR("NULL in"); + throw; + } + + std::shared_ptr b64(BIO_new(BIO_f_base64()), BIO_free_all); + BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL); + + BIO* sink = BIO_new(BIO_s_mem()); + if (sink == nullptr) { + SEC_LOG_ERROR("BIO_new failed"); + throw; + } + + BIO_push(b64.get(), sink); + + if (BIO_write(b64.get(), in, static_cast(in_length)) < 0) { + SEC_LOG_ERROR("BIO_write failed"); + throw; + } + + if (BIO_flush(b64.get()) < 0) { + SEC_LOG_ERROR("BIO_flush failed"); + throw; + } + + const char* encoded; + const uint64_t len = BIO_get_mem_data(sink, &encoded); // NOLINT + return {encoded, len}; +} + +ProvKey* TestCreds::getSocKey(TestKey key, SEC_OBJECTID id) { + ProvKey* pk = TestCreds::getKey(key, TESTKC_RAW, id); + if (pk == nullptr) { + return nullptr; + } + + std::vector key_clear; + + std::string key_type; + switch (pk->kc) { + case SEC_KEYCONTAINER_DER_RSA_1024: + case SEC_KEYCONTAINER_DER_RSA_2048: { + RSA* rsa = SecUtils_RSAFromDERPriv(&pk->key[0], pk->key.size()); + if (rsa == nullptr) { + SEC_LOG_ERROR("SecUtils_RSAFromDERPriv failed "); + delete pk; + return nullptr; + } + + SEC_SIZE written; + key_clear.resize(SEC_KEYCONTAINER_MAX_LEN); + if (SecUtils_RSAToDERPrivKeyInfo(rsa, &key_clear[0], key_clear.size(), &written) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_RSAToDERPrivKeyInfo failed"); + SEC_RSA_FREE(rsa); + delete pk; + return nullptr; + } + + SEC_RSA_FREE(rsa); + + key_clear.resize(written); + key_type = pk->kc == SEC_KEYCONTAINER_DER_RSA_1024 ? "RSA-1024" : "RSA-2048"; + } break; + + case SEC_KEYCONTAINER_DER_ECC_NISTP256: { + EC_KEY* ec_key = SecUtils_ECCFromDERPriv(&pk->key[0], pk->key.size()); + if (ec_key == nullptr) { + SEC_LOG_ERROR("SecUtils_ECCFromDERPriv failed "); + delete pk; + return nullptr; + } + + Sec_ECCRawPrivateKey ec_bin; + if (SecUtils_ECCToPrivBinary(ec_key, &ec_bin) != SEC_RESULT_SUCCESS) { + SEC_LOG_ERROR("SecUtils_ECCToPrivBinary failed"); + SEC_ECC_FREE(ec_key); + delete pk; + return nullptr; + } + + SEC_ECC_FREE(ec_key); + + key_clear.resize(SEC_ECC_NISTP256_KEY_LEN); + memcpy(&key_clear[0], &ec_bin.prv[0], SEC_ECC_NISTP256_KEY_LEN); + key_type = "ECC-P256"; + } break; + + case SEC_KEYCONTAINER_RAW_AES_128: { + key_clear.resize(pk->key.size()); + memcpy(&key_clear[0], &pk->key[0], pk->key.size()); + key_type = "AES-128"; + } break; + + case SEC_KEYCONTAINER_RAW_AES_256: { + key_clear.resize(pk->key.size()); + memcpy(&key_clear[0], &pk->key[0], pk->key.size()); + key_type = "AES-256"; + } break; + + case SEC_KEYCONTAINER_RAW_HMAC_128: { + key_clear.resize(pk->key.size()); + memcpy(&key_clear[0], &pk->key[0], pk->key.size()); + key_type = "HMAC-128"; + } break; + + case SEC_KEYCONTAINER_RAW_HMAC_160: { + key_clear.resize(pk->key.size()); + memcpy(&key_clear[0], &pk->key[0], pk->key.size()); + key_type = "HMAC-160"; + } break; + + case SEC_KEYCONTAINER_RAW_HMAC_256: { + key_clear.resize(pk->key.size()); + memcpy(&key_clear[0], &pk->key[0], pk->key.size()); + key_type = "HMAC-256"; + } break; + + default: + SEC_LOG_ERROR("Unexpected kc encountered"); + delete pk; + return nullptr; + } + + std::vector tag; + std::vector kc = generate_sa_soc_key_container(key_clear, key_type, tag); + + delete pk; + return new ProvKey(kc, SEC_KEYCONTAINER_SOC); +} + +Sec_Result TestCreds::preprovisionSoc(TestCtx* ctx) { + //Here the soc vendors should add code to preprovision any credentials that + //are required for the rest of the system to operate properly. + + //For most platforms this can stay a NOP + + //provision kpk + ctx->provisionKey(SEC_OBJECTID_OPENSSL_KPK, SEC_STORAGELOC_RAM, TESTKEY_AES128, TESTKC_RAW, SEC_TRUE); + + return SEC_RESULT_SUCCESS; +} + +bool TestCreds::supports(Capability cap) { + //return whether a specific capability is supported in the target soc +#ifdef ENABLE_SOC_KEY_TESTS + return cap != CAPABILITY_HKDF_CMAC; +#else + return cap != CAPABILITY_HKDF_CMAC && cap != CAPABILITY_LOAD_SYM_SOC_KC; +#endif +} + +void TestCreds::init() { +} + +void TestCreds::shutdown() { +} diff --git a/test/valgrind.supp b/test/valgrind.supp new file mode 100644 index 0000000..aa0dfda --- /dev/null +++ b/test/valgrind.supp @@ -0,0 +1,70 @@ +{ + object_store_shutdown + Memcheck:Cond + fun:_store_remove + fun:object_store_shutdown + fun:*_store_shutdown + ... +} +{ + object_store_remove + Memcheck:Cond + fun:_store_remove + fun:object_store_remove + fun:*_store_remove +} +{ + object_store_release + Memcheck:Cond + fun:object_store_release + fun:key_store_unwrap + ... +} +{ + gmtsub-malloc + Memcheck:Leak + match-leak-kinds: possible + fun:malloc + ... + fun:gmt_init + fun:__pthread_once_handler + fun:_os_once_callout + fun:pthread_once + fun:gmtsub + fun:SecUtils_Epoch2IsoTime + fun:SecKey_GetProperties + fun:SecCipher_GetInstance + fun:SecCipher_SingleInput + fun:SecCipher_SingleInputId + fun:SecStore_ComputeMacKey + fun:SecStore_StoreDataWithKey + fun:SecStore_StoreData + fun:_Z9testStorehh + fun:_Z11runKeyTestsP8SuiteCtx + fun:testIt + fun:main +} +{ + gmtsub-calloc + Memcheck:Leak + match-leak-kinds: possible + fun:calloc + ... + fun:gmt_init + fun:__pthread_once_handler + fun:_os_once_callout + fun:pthread_once + fun:gmtsub + fun:SecUtils_Epoch2IsoTime + fun:SecKey_GetProperties + fun:SecCipher_GetInstance + fun:SecCipher_SingleInput + fun:SecCipher_SingleInputId + fun:SecStore_ComputeMacKey + fun:SecStore_StoreDataWithKey + fun:SecStore_StoreData + fun:_Z9testStorehh + fun:_Z11runKeyTestsP8SuiteCtx + fun:testIt + fun:main +} \ No newline at end of file