Loading security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -24,4 +24,5 @@ enum KeyPurpose { SIGN = 2, VERIFY = 3, WRAP_KEY = 5, AGREE_KEY = 6, } security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl +3 −3 Original line number Diff line number Diff line Loading @@ -681,9 +681,9 @@ interface IKeyMintDevice { * values less than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH. * * @param inPurpose The purpose of the operation, one of KeyPurpose::ENCRYPT, * KeyPurpose::DECRYPT, KeyPurpose::SIGN or KeyPurpose::VERIFY. Note that for AEAD * modes, encryption and decryption imply signing and verification, respectively, but * must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT. * KeyPurpose::DECRYPT, KeyPurpose::SIGN, KeyPurpose::VERIFY, or KeyPurpose::AGREE_KEY. * Note that for AEAD modes, encryption and decryption imply signing and verification, * respectively, but must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT. * * @param inKeyBlob The opaque key descriptor returned by generateKey() or importKey(). The key * must have a purpose compatible with purpose and all of its usage requirements must be Loading security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl +4 −1 Original line number Diff line number Diff line Loading @@ -39,5 +39,8 @@ enum KeyPurpose { /* Usable with wrapping keys. */ WRAP_KEY = 5, /* TODO(seleneh) add AGREE_KEY and ATTEST_KEY and their corresponding codes and tests later*/ /* Key Agreement, usable with EC keys. */ AGREE_KEY = 6, /* TODO(seleneh) add ATTEST_KEY and their corresponding codes and tests later*/ } security/keymint/aidl/vts/functional/KeyMintTest.cpp +117 −0 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ #include <signal.h> #include <iostream> #include <openssl/ec.h> #include <openssl/evp.h> #include <openssl/mem.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include <cutils/properties.h> Loading Loading @@ -4424,6 +4426,121 @@ TEST_P(TransportLimitTest, LargeFinishInput) { INSTANTIATE_KEYMINT_AIDL_TEST(TransportLimitTest); typedef KeyMintAidlTestBase KeyAgreementTest; int CurveToOpenSslCurveName(EcCurve curve) { switch (curve) { case EcCurve::P_224: return NID_secp224r1; case EcCurve::P_256: return NID_X9_62_prime256v1; case EcCurve::P_384: return NID_secp384r1; case EcCurve::P_521: return NID_secp521r1; } } /* * KeyAgreementTest.Ecdh * * Verifies that ECDH works for all curves */ TEST_P(KeyAgreementTest, Ecdh) { // Because it's possible to use this API with keys on different curves, we // check all N^2 combinations where N is the number of supported // curves. // // This is not a big deal as N is 4 so we only do 16 runs. If we end up with a // lot more curves we can be smart about things and just pick |otherCurve| so // it's not |curve| and that way we end up with only 2*N runs // for (auto curve : ValidCurves()) { for (auto localCurve : ValidCurves()) { // Generate EC key locally (with access to private key material) auto ecKey = EC_KEY_Ptr(EC_KEY_new()); int curveName = CurveToOpenSslCurveName(localCurve); auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(curveName)); ASSERT_NE(group, nullptr); ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1); ASSERT_EQ(EC_KEY_generate_key(ecKey.get()), 1); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); ASSERT_EQ(EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()), 1); // Get encoded form of the public part of the locally generated key... unsigned char* p = nullptr; int encodedPublicKeySize = i2d_PUBKEY(pkey.get(), &p); ASSERT_GT(encodedPublicKeySize, 0); vector<uint8_t> encodedPublicKey( reinterpret_cast<const uint8_t*>(p), reinterpret_cast<const uint8_t*>(p + encodedPublicKeySize)); OPENSSL_free(p); // Generate EC key in KeyMint (only access to public key material) vector<uint8_t> challenge = {0x41, 0x42}; EXPECT_EQ( ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() .Authorization(TAG_NO_AUTH_REQUIRED) .Authorization(TAG_EC_CURVE, curve) .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY) .Authorization(TAG_ALGORITHM, Algorithm::EC) .Authorization(TAG_ATTESTATION_APPLICATION_ID, {0x61, 0x62}) .Authorization(TAG_ATTESTATION_CHALLENGE, challenge))) << "Failed to generate key"; ASSERT_GT(cert_chain_.size(), 0); X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate)); ASSERT_NE(kmKeyCert, nullptr); // Check that keyAgreement (bit 4) is set in KeyUsage EXPECT_TRUE((X509_get_key_usage(kmKeyCert.get()) & X509v3_KU_KEY_AGREEMENT) != 0); auto kmPkey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get())); ASSERT_NE(kmPkey, nullptr); if (dump_Attestations) { for (size_t n = 0; n < cert_chain_.size(); n++) { std::cout << bin2hex(cert_chain_[n].encodedCertificate) << std::endl; } } // Now that we have the two keys, we ask KeyMint to perform ECDH... if (curve != localCurve) { // If the keys are using different curves KeyMint should fail with // ErrorCode:INVALID_ARGUMENT. Check that. EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder())); string ZabFromKeyMintStr; EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()), &ZabFromKeyMintStr)); } else { // Otherwise if the keys are using the same curve, it should work. EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder())); string ZabFromKeyMintStr; EXPECT_EQ(ErrorCode::OK, Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()), &ZabFromKeyMintStr)); vector<uint8_t> ZabFromKeyMint(ZabFromKeyMintStr.begin(), ZabFromKeyMintStr.end()); // Perform local ECDH between the two keys so we can check if we get the same Zab.. auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(pkey.get(), nullptr)); ASSERT_NE(ctx, nullptr); ASSERT_EQ(EVP_PKEY_derive_init(ctx.get()), 1); ASSERT_EQ(EVP_PKEY_derive_set_peer(ctx.get(), kmPkey.get()), 1); size_t ZabFromTestLen = 0; ASSERT_EQ(EVP_PKEY_derive(ctx.get(), nullptr, &ZabFromTestLen), 1); vector<uint8_t> ZabFromTest; ZabFromTest.resize(ZabFromTestLen); ASSERT_EQ(EVP_PKEY_derive(ctx.get(), ZabFromTest.data(), &ZabFromTestLen), 1); EXPECT_EQ(ZabFromKeyMint, ZabFromTest); } CheckedDeleteKey(); } } } INSTANTIATE_KEYMINT_AIDL_TEST(KeyAgreementTest); } // namespace aidl::android::hardware::security::keymint::test int main(int argc, char** argv) { Loading security/keymint/support/include/keymint_support/openssl_utils.h +3 −0 Original line number Diff line number Diff line Loading @@ -34,7 +34,10 @@ typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete; typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr; MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT) MAKE_OPENSSL_PTR_TYPE(EC_KEY) MAKE_OPENSSL_PTR_TYPE(EC_GROUP) MAKE_OPENSSL_PTR_TYPE(EVP_PKEY) MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX) MAKE_OPENSSL_PTR_TYPE(RSA) MAKE_OPENSSL_PTR_TYPE(X509) MAKE_OPENSSL_PTR_TYPE(BN_CTX) Loading Loading
security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -24,4 +24,5 @@ enum KeyPurpose { SIGN = 2, VERIFY = 3, WRAP_KEY = 5, AGREE_KEY = 6, }
security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl +3 −3 Original line number Diff line number Diff line Loading @@ -681,9 +681,9 @@ interface IKeyMintDevice { * values less than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH. * * @param inPurpose The purpose of the operation, one of KeyPurpose::ENCRYPT, * KeyPurpose::DECRYPT, KeyPurpose::SIGN or KeyPurpose::VERIFY. Note that for AEAD * modes, encryption and decryption imply signing and verification, respectively, but * must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT. * KeyPurpose::DECRYPT, KeyPurpose::SIGN, KeyPurpose::VERIFY, or KeyPurpose::AGREE_KEY. * Note that for AEAD modes, encryption and decryption imply signing and verification, * respectively, but must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT. * * @param inKeyBlob The opaque key descriptor returned by generateKey() or importKey(). The key * must have a purpose compatible with purpose and all of its usage requirements must be Loading
security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl +4 −1 Original line number Diff line number Diff line Loading @@ -39,5 +39,8 @@ enum KeyPurpose { /* Usable with wrapping keys. */ WRAP_KEY = 5, /* TODO(seleneh) add AGREE_KEY and ATTEST_KEY and their corresponding codes and tests later*/ /* Key Agreement, usable with EC keys. */ AGREE_KEY = 6, /* TODO(seleneh) add ATTEST_KEY and their corresponding codes and tests later*/ }
security/keymint/aidl/vts/functional/KeyMintTest.cpp +117 −0 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ #include <signal.h> #include <iostream> #include <openssl/ec.h> #include <openssl/evp.h> #include <openssl/mem.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include <cutils/properties.h> Loading Loading @@ -4424,6 +4426,121 @@ TEST_P(TransportLimitTest, LargeFinishInput) { INSTANTIATE_KEYMINT_AIDL_TEST(TransportLimitTest); typedef KeyMintAidlTestBase KeyAgreementTest; int CurveToOpenSslCurveName(EcCurve curve) { switch (curve) { case EcCurve::P_224: return NID_secp224r1; case EcCurve::P_256: return NID_X9_62_prime256v1; case EcCurve::P_384: return NID_secp384r1; case EcCurve::P_521: return NID_secp521r1; } } /* * KeyAgreementTest.Ecdh * * Verifies that ECDH works for all curves */ TEST_P(KeyAgreementTest, Ecdh) { // Because it's possible to use this API with keys on different curves, we // check all N^2 combinations where N is the number of supported // curves. // // This is not a big deal as N is 4 so we only do 16 runs. If we end up with a // lot more curves we can be smart about things and just pick |otherCurve| so // it's not |curve| and that way we end up with only 2*N runs // for (auto curve : ValidCurves()) { for (auto localCurve : ValidCurves()) { // Generate EC key locally (with access to private key material) auto ecKey = EC_KEY_Ptr(EC_KEY_new()); int curveName = CurveToOpenSslCurveName(localCurve); auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(curveName)); ASSERT_NE(group, nullptr); ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1); ASSERT_EQ(EC_KEY_generate_key(ecKey.get()), 1); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); ASSERT_EQ(EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()), 1); // Get encoded form of the public part of the locally generated key... unsigned char* p = nullptr; int encodedPublicKeySize = i2d_PUBKEY(pkey.get(), &p); ASSERT_GT(encodedPublicKeySize, 0); vector<uint8_t> encodedPublicKey( reinterpret_cast<const uint8_t*>(p), reinterpret_cast<const uint8_t*>(p + encodedPublicKeySize)); OPENSSL_free(p); // Generate EC key in KeyMint (only access to public key material) vector<uint8_t> challenge = {0x41, 0x42}; EXPECT_EQ( ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() .Authorization(TAG_NO_AUTH_REQUIRED) .Authorization(TAG_EC_CURVE, curve) .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY) .Authorization(TAG_ALGORITHM, Algorithm::EC) .Authorization(TAG_ATTESTATION_APPLICATION_ID, {0x61, 0x62}) .Authorization(TAG_ATTESTATION_CHALLENGE, challenge))) << "Failed to generate key"; ASSERT_GT(cert_chain_.size(), 0); X509_Ptr kmKeyCert(parse_cert_blob(cert_chain_[0].encodedCertificate)); ASSERT_NE(kmKeyCert, nullptr); // Check that keyAgreement (bit 4) is set in KeyUsage EXPECT_TRUE((X509_get_key_usage(kmKeyCert.get()) & X509v3_KU_KEY_AGREEMENT) != 0); auto kmPkey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get())); ASSERT_NE(kmPkey, nullptr); if (dump_Attestations) { for (size_t n = 0; n < cert_chain_.size(); n++) { std::cout << bin2hex(cert_chain_[n].encodedCertificate) << std::endl; } } // Now that we have the two keys, we ask KeyMint to perform ECDH... if (curve != localCurve) { // If the keys are using different curves KeyMint should fail with // ErrorCode:INVALID_ARGUMENT. Check that. EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder())); string ZabFromKeyMintStr; EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()), &ZabFromKeyMintStr)); } else { // Otherwise if the keys are using the same curve, it should work. EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder())); string ZabFromKeyMintStr; EXPECT_EQ(ErrorCode::OK, Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()), &ZabFromKeyMintStr)); vector<uint8_t> ZabFromKeyMint(ZabFromKeyMintStr.begin(), ZabFromKeyMintStr.end()); // Perform local ECDH between the two keys so we can check if we get the same Zab.. auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(pkey.get(), nullptr)); ASSERT_NE(ctx, nullptr); ASSERT_EQ(EVP_PKEY_derive_init(ctx.get()), 1); ASSERT_EQ(EVP_PKEY_derive_set_peer(ctx.get(), kmPkey.get()), 1); size_t ZabFromTestLen = 0; ASSERT_EQ(EVP_PKEY_derive(ctx.get(), nullptr, &ZabFromTestLen), 1); vector<uint8_t> ZabFromTest; ZabFromTest.resize(ZabFromTestLen); ASSERT_EQ(EVP_PKEY_derive(ctx.get(), ZabFromTest.data(), &ZabFromTestLen), 1); EXPECT_EQ(ZabFromKeyMint, ZabFromTest); } CheckedDeleteKey(); } } } INSTANTIATE_KEYMINT_AIDL_TEST(KeyAgreementTest); } // namespace aidl::android::hardware::security::keymint::test int main(int argc, char** argv) { Loading
security/keymint/support/include/keymint_support/openssl_utils.h +3 −0 Original line number Diff line number Diff line Loading @@ -34,7 +34,10 @@ typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete; typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr; MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT) MAKE_OPENSSL_PTR_TYPE(EC_KEY) MAKE_OPENSSL_PTR_TYPE(EC_GROUP) MAKE_OPENSSL_PTR_TYPE(EVP_PKEY) MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX) MAKE_OPENSSL_PTR_TYPE(RSA) MAKE_OPENSSL_PTR_TYPE(X509) MAKE_OPENSSL_PTR_TYPE(BN_CTX) Loading