Loading identity/aidl/default/WritableIdentityCredential.cpp +35 −84 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ #define LOG_TAG "WritableIdentityCredential" #define LOG_TAG "WritableIdentityCredential" #include "WritableIdentityCredential.h" #include "IdentityCredentialStore.h" #include <android/hardware/identity/support/IdentityCredentialSupport.h> #include <android/hardware/identity/support/IdentityCredentialSupport.h> #include <android-base/logging.h> #include <android-base/logging.h> Loading @@ -23,6 +26,8 @@ #include <cppbor/cppbor.h> #include <cppbor/cppbor.h> #include <cppbor/cppbor_parse.h> #include <cppbor/cppbor_parse.h> #include <utility> #include "IdentityCredentialStore.h" #include "IdentityCredentialStore.h" #include "Util.h" #include "Util.h" #include "WritableIdentityCredential.h" #include "WritableIdentityCredential.h" Loading @@ -33,26 +38,6 @@ using ::std::optional; using namespace ::android::hardware::identity; using namespace ::android::hardware::identity; bool WritableIdentityCredential::initialize() { bool WritableIdentityCredential::initialize() { optional<vector<uint8_t>> keyPair = support::createEcKeyPair(); if (!keyPair) { LOG(ERROR) << "Error creating credentialKey"; return false; } optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value()); if (!pubKey) { LOG(ERROR) << "Error getting public part of credentialKey"; return false; } credentialPubKey_ = pubKey.value(); optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value()); if (!privKey) { LOG(ERROR) << "Error getting private part of credentialKey"; return false; } credentialPrivKey_ = privKey.value(); optional<vector<uint8_t>> random = support::getRandom(16); optional<vector<uint8_t>> random = support::getRandom(16); if (!random) { if (!random) { LOG(ERROR) << "Error creating storageKey"; LOG(ERROR) << "Error creating storageKey"; Loading @@ -63,88 +48,54 @@ bool WritableIdentityCredential::initialize() { return true; return true; } } // TODO: use |attestationApplicationId| and |attestationChallenge| and also // This function generates the attestation certificate using the passed in // ensure the returned certificate chain satisfy the requirements listed in // |attestationApplicationId| and |attestationChallenge|. It will generate an // the docs for IWritableIdentityCredential::getAttestationCertificate() // attestation certificate with current time and expires one year from now. The // // certificate shall contain all values as specified in hal. ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( const vector<int8_t>& /*attestationApplicationId*/, const vector<int8_t>& attestationApplicationId, // const vector<int8_t>& /*attestationChallenge*/, vector<Certificate>* outCertificateChain) { const vector<int8_t>& attestationChallenge, // // For now, we dynamically generate an attestion key on each and every vector<Certificate>* outCertificateChain) { // request and use that to sign CredentialKey. In a real implementation this if (!credentialPrivKey_.empty() || !credentialPubKey_.empty() || !certificateChain_.empty()) { // would look very differently. optional<vector<uint8_t>> attestationKeyPair = support::createEcKeyPair(); if (!attestationKeyPair) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error creating attestationKey")); IIdentityCredentialStore::STATUS_FAILED, "Error attestation certificate previously generated")); } } optional<vector<uint8_t>> attestationPubKey = vector<uint8_t> challenge(attestationChallenge.begin(), attestationChallenge.end()); support::ecKeyPairGetPublicKey(attestationKeyPair.value()); vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end()); if (!attestationPubKey) { optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair = support::createEcKeyPairAndAttestation(challenge, appId); if (!keyAttestationPair) { LOG(ERROR) << "Error creating credentialKey and attestation"; return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, IIdentityCredentialStore::STATUS_FAILED, "Error getting public part of attestationKey")); "Error creating credentialKey and attestation")); } } optional<vector<uint8_t>> attestationPrivKey = vector<uint8_t> keyPair = keyAttestationPair.value().first; support::ecKeyPairGetPrivateKey(attestationKeyPair.value()); certificateChain_ = keyAttestationPair.value().second; if (!attestationPrivKey) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair); IIdentityCredentialStore::STATUS_FAILED, if (!pubKey) { "Error getting private part of attestationKey")); } string serialDecimal; string issuer; string subject; time_t validityNotBefore = time(nullptr); time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600; // First create a certificate for |credentialPubKey| which is signed by // |attestationPrivKey|. // serialDecimal = "0"; // TODO: set serial to |attestationChallenge| issuer = "Android Open Source Project"; subject = "Android IdentityCredential CredentialKey"; optional<vector<uint8_t>> credentialPubKeyCertificate = support::ecPublicKeyGenerateCertificate( credentialPubKey_, attestationPrivKey.value(), serialDecimal, issuer, subject, validityNotBefore, validityNotAfter); if (!credentialPubKeyCertificate) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error creating certificate for credentialPubKey")); } // This is followed by a certificate for |attestationPubKey| self-signed by // |attestationPrivKey|. serialDecimal = "0"; // TODO: set serial issuer = "Android Open Source Project"; subject = "Android IdentityCredential AttestationKey"; optional<vector<uint8_t>> attestationKeyCertificate = support::ecPublicKeyGenerateCertificate( attestationPubKey.value(), attestationPrivKey.value(), serialDecimal, issuer, subject, validityNotBefore, validityNotAfter); if (!attestationKeyCertificate) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, IIdentityCredentialStore::STATUS_FAILED, "Error creating certificate for attestationPubKey")); "Error getting public part of credentialKey")); } } credentialPubKey_ = pubKey.value(); // Concatenate the certificates to form the chain. optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair); vector<uint8_t> certificateChain; if (!privKey) { certificateChain.insert(certificateChain.end(), credentialPubKeyCertificate.value().begin(), credentialPubKeyCertificate.value().end()); certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(), attestationKeyCertificate.value().end()); optional<vector<vector<uint8_t>>> splitCertChain = support::certificateChainSplit(certificateChain); if (!splitCertChain) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error splitting certificate chain")); IIdentityCredentialStore::STATUS_FAILED, "Error getting private part of credentialKey")); } } credentialPrivKey_ = privKey.value(); // convert from vector<vector<uint8_t>>> to vector<Certificate>* *outCertificateChain = vector<Certificate>(); *outCertificateChain = vector<Certificate>(); for (const vector<uint8_t>& cert : splitCertChain.value()) { for (const vector<uint8_t>& cert : certificateChain_) { Certificate c = Certificate(); Certificate c = Certificate(); c.encodedCertificate = byteStringToSigned(cert); c.encodedCertificate = byteStringToSigned(cert); outCertificateChain->push_back(std::move(c)); outCertificateChain->push_back(std::move(c)); Loading identity/aidl/default/WritableIdentityCredential.h +4 −1 Original line number Original line Diff line number Diff line Loading @@ -64,10 +64,13 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { string docType_; string docType_; bool testCredential_; bool testCredential_; // These are set in initialize(). // This is set in initialize(). vector<uint8_t> storageKey_; vector<uint8_t> storageKey_; // These are set in getAttestationCertificate(). vector<uint8_t> credentialPrivKey_; vector<uint8_t> credentialPrivKey_; vector<uint8_t> credentialPubKey_; vector<uint8_t> credentialPubKey_; vector<vector<uint8_t>> certificateChain_; // These fields are initialized during startPersonalization() // These fields are initialized during startPersonalization() size_t numAccessControlProfileRemaining_; size_t numAccessControlProfileRemaining_; Loading identity/support/Android.bp +4 −0 Original line number Original line Diff line number Diff line Loading @@ -23,10 +23,14 @@ cc_library { "include", "include", ], ], shared_libs: [ shared_libs: [ "android.hardware.keymaster@4.0", "libcrypto", "libcrypto", "libbase", "libbase", "libhidlbase", "libhidlbase", "libhardware", "libhardware", "libkeymaster_portable", "libsoft_attestation_cert", "libpuresoftkeymasterdevice", ], ], static_libs: [ static_libs: [ "libcppbor", "libcppbor", Loading identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h +12 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <optional> #include <optional> #include <string> #include <string> #include <tuple> #include <tuple> #include <utility> #include <vector> #include <vector> namespace android { namespace android { Loading Loading @@ -106,6 +107,17 @@ optional<vector<uint8_t>> encryptAes128Gcm(const vector<uint8_t>& key, const vec // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // EC crypto functionality / abstraction (only supports P-256). // EC crypto functionality / abstraction (only supports P-256). // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the // PKCS#8 encoded key-pair. Also generates an attestation // certificate using the |challenge| and |applicationId|, and returns the generated // certificate in X.509 certificate chain format. // // The attestation time fields used will be the current time, and expires in one year. // // The first parameter of the return value is the keyPair generated, second return in // the pair is the attestation certificate generated. optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation( const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId); // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the // PKCS#8 encoded key-pair. // PKCS#8 encoded key-pair. Loading identity/support/src/IdentityCredentialSupport.cpp +139 −0 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,13 @@ #include <cppbor.h> #include <cppbor.h> #include <cppbor_parse.h> #include <cppbor_parse.h> #include <android/hardware/keymaster/4.0/types.h> #include <keymaster/authorization_set.h> #include <keymaster/contexts/pure_soft_keymaster_context.h> #include <keymaster/contexts/soft_attestation_cert.h> #include <keymaster/keymaster_tags.h> #include <keymaster/km_openssl/attestation_utils.h> namespace android { namespace android { namespace hardware { namespace hardware { namespace identity { namespace identity { Loading Loading @@ -816,6 +823,138 @@ optional<vector<uint8_t>> hmacSha256(const vector<uint8_t>& key, const vector<ui return hmac; return hmac; } } // Generates the attestation certificate with the parameters passed in. Note // that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in // milli seconds since epoch. We are setting them to milliseconds due to // requirement in AuthorizationSet KM_DATE fields. The certificate created is // actually in seconds. optional<vector<vector<uint8_t>>> createAttestation(const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge, uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds) { ::keymaster::AuthorizationSet auth_set( ::keymaster::AuthorizationSetBuilder() .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(), challenge.size()) .Authorization(::keymaster::TAG_ACTIVE_DATETIME, activeTimeMilliSeconds) // Even though identity attestation hal said the application // id should be in software enforced authentication set, // keymaster portable lib expect the input in this // parameter because the software enforced in input to keymaster // refers to the key software enforced properties. And this // parameter refers to properties of the attestation which // includes app id. .Authorization(::keymaster::TAG_ATTESTATION_APPLICATION_ID, applicationId.data(), applicationId.size()) .Authorization(::keymaster::TAG_USAGE_EXPIRE_DATETIME, expireTimeMilliSeconds)); // Unique id and device id is not applicable for identity credential attestation, // so we don't need to set those or application id. ::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization( ::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds)); ::keymaster::AuthorizationSet hwEnforced( ::keymaster::AuthorizationSetBuilder() .Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN) .Authorization(::keymaster::TAG_KEY_SIZE, 256) .Authorization(::keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC) .Authorization(::keymaster::TAG_NO_AUTH_REQUIRED) .Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256) .Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256) .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY)); const keymaster_cert_chain_t* attestation_chain = ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr); if (attestation_chain == nullptr) { LOG(ERROR) << "Error getting attestation chain"; return {}; } const keymaster_key_blob_t* attestation_signing_key = ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr); if (attestation_signing_key == nullptr) { LOG(ERROR) << "Error getting attestation key"; return {}; } keymaster_error_t error; ::keymaster::CertChainPtr cert_chain_out; ::keymaster::PureSoftKeymasterContext context; // set identity version to 10 per hal requirements specified in IWriteableCredential.hal // For now, the identity version in the attestation is set in the keymaster // version field in the portable keymaster lib, which is a bit misleading. uint identity_version = 10; error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context, identity_version, *attestation_chain, *attestation_signing_key, &cert_chain_out); if (KM_ERROR_OK != error || !cert_chain_out) { LOG(ERROR) << "Error generate attestation from EVP key" << error; return {}; } // translate certificate format from keymaster_cert_chain_t to vector<uint8_t>. vector<vector<uint8_t>> attestationCertificate; for (int i = 0; i < cert_chain_out->entry_count; i++) { attestationCertificate.insert( attestationCertificate.end(), vector<uint8_t>( cert_chain_out->entries[i].data, cert_chain_out->entries[i].data + cert_chain_out->entries[i].data_length)); } return attestationCertificate; } optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation( const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) { auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new()); auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new()); auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); if (ec_key.get() == nullptr || pkey.get() == nullptr) { LOG(ERROR) << "Memory allocation failed"; return {}; } if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 || EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) { LOG(ERROR) << "Error generating key"; return {}; } if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1) { LOG(ERROR) << "Error getting private key"; return {}; } uint64_t now = time(nullptr); uint64_t secondsInOneYear = 365 * 24 * 60 * 60; uint64_t expireTimeMs = (now + secondsInOneYear) * 1000; optional<vector<vector<uint8_t>>> attestationCert = createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs); if (!attestationCert) { LOG(ERROR) << "Error create attestation from key and challenge"; return {}; } int size = i2d_PrivateKey(pkey.get(), nullptr); if (size == 0) { LOG(ERROR) << "Error generating public key encoding"; return {}; } vector<uint8_t> keyPair(size); unsigned char* p = keyPair.data(); i2d_PrivateKey(pkey.get(), &p); return make_pair(keyPair, attestationCert.value()); } optional<vector<uint8_t>> createEcKeyPair() { optional<vector<uint8_t>> createEcKeyPair() { auto ec_key = EC_KEY_Ptr(EC_KEY_new()); auto ec_key = EC_KEY_Ptr(EC_KEY_new()); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); Loading Loading
identity/aidl/default/WritableIdentityCredential.cpp +35 −84 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ #define LOG_TAG "WritableIdentityCredential" #define LOG_TAG "WritableIdentityCredential" #include "WritableIdentityCredential.h" #include "IdentityCredentialStore.h" #include <android/hardware/identity/support/IdentityCredentialSupport.h> #include <android/hardware/identity/support/IdentityCredentialSupport.h> #include <android-base/logging.h> #include <android-base/logging.h> Loading @@ -23,6 +26,8 @@ #include <cppbor/cppbor.h> #include <cppbor/cppbor.h> #include <cppbor/cppbor_parse.h> #include <cppbor/cppbor_parse.h> #include <utility> #include "IdentityCredentialStore.h" #include "IdentityCredentialStore.h" #include "Util.h" #include "Util.h" #include "WritableIdentityCredential.h" #include "WritableIdentityCredential.h" Loading @@ -33,26 +38,6 @@ using ::std::optional; using namespace ::android::hardware::identity; using namespace ::android::hardware::identity; bool WritableIdentityCredential::initialize() { bool WritableIdentityCredential::initialize() { optional<vector<uint8_t>> keyPair = support::createEcKeyPair(); if (!keyPair) { LOG(ERROR) << "Error creating credentialKey"; return false; } optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value()); if (!pubKey) { LOG(ERROR) << "Error getting public part of credentialKey"; return false; } credentialPubKey_ = pubKey.value(); optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value()); if (!privKey) { LOG(ERROR) << "Error getting private part of credentialKey"; return false; } credentialPrivKey_ = privKey.value(); optional<vector<uint8_t>> random = support::getRandom(16); optional<vector<uint8_t>> random = support::getRandom(16); if (!random) { if (!random) { LOG(ERROR) << "Error creating storageKey"; LOG(ERROR) << "Error creating storageKey"; Loading @@ -63,88 +48,54 @@ bool WritableIdentityCredential::initialize() { return true; return true; } } // TODO: use |attestationApplicationId| and |attestationChallenge| and also // This function generates the attestation certificate using the passed in // ensure the returned certificate chain satisfy the requirements listed in // |attestationApplicationId| and |attestationChallenge|. It will generate an // the docs for IWritableIdentityCredential::getAttestationCertificate() // attestation certificate with current time and expires one year from now. The // // certificate shall contain all values as specified in hal. ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( const vector<int8_t>& /*attestationApplicationId*/, const vector<int8_t>& attestationApplicationId, // const vector<int8_t>& /*attestationChallenge*/, vector<Certificate>* outCertificateChain) { const vector<int8_t>& attestationChallenge, // // For now, we dynamically generate an attestion key on each and every vector<Certificate>* outCertificateChain) { // request and use that to sign CredentialKey. In a real implementation this if (!credentialPrivKey_.empty() || !credentialPubKey_.empty() || !certificateChain_.empty()) { // would look very differently. optional<vector<uint8_t>> attestationKeyPair = support::createEcKeyPair(); if (!attestationKeyPair) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error creating attestationKey")); IIdentityCredentialStore::STATUS_FAILED, "Error attestation certificate previously generated")); } } optional<vector<uint8_t>> attestationPubKey = vector<uint8_t> challenge(attestationChallenge.begin(), attestationChallenge.end()); support::ecKeyPairGetPublicKey(attestationKeyPair.value()); vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end()); if (!attestationPubKey) { optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair = support::createEcKeyPairAndAttestation(challenge, appId); if (!keyAttestationPair) { LOG(ERROR) << "Error creating credentialKey and attestation"; return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, IIdentityCredentialStore::STATUS_FAILED, "Error getting public part of attestationKey")); "Error creating credentialKey and attestation")); } } optional<vector<uint8_t>> attestationPrivKey = vector<uint8_t> keyPair = keyAttestationPair.value().first; support::ecKeyPairGetPrivateKey(attestationKeyPair.value()); certificateChain_ = keyAttestationPair.value().second; if (!attestationPrivKey) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair); IIdentityCredentialStore::STATUS_FAILED, if (!pubKey) { "Error getting private part of attestationKey")); } string serialDecimal; string issuer; string subject; time_t validityNotBefore = time(nullptr); time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600; // First create a certificate for |credentialPubKey| which is signed by // |attestationPrivKey|. // serialDecimal = "0"; // TODO: set serial to |attestationChallenge| issuer = "Android Open Source Project"; subject = "Android IdentityCredential CredentialKey"; optional<vector<uint8_t>> credentialPubKeyCertificate = support::ecPublicKeyGenerateCertificate( credentialPubKey_, attestationPrivKey.value(), serialDecimal, issuer, subject, validityNotBefore, validityNotAfter); if (!credentialPubKeyCertificate) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error creating certificate for credentialPubKey")); } // This is followed by a certificate for |attestationPubKey| self-signed by // |attestationPrivKey|. serialDecimal = "0"; // TODO: set serial issuer = "Android Open Source Project"; subject = "Android IdentityCredential AttestationKey"; optional<vector<uint8_t>> attestationKeyCertificate = support::ecPublicKeyGenerateCertificate( attestationPubKey.value(), attestationPrivKey.value(), serialDecimal, issuer, subject, validityNotBefore, validityNotAfter); if (!attestationKeyCertificate) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, IIdentityCredentialStore::STATUS_FAILED, "Error creating certificate for attestationPubKey")); "Error getting public part of credentialKey")); } } credentialPubKey_ = pubKey.value(); // Concatenate the certificates to form the chain. optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair); vector<uint8_t> certificateChain; if (!privKey) { certificateChain.insert(certificateChain.end(), credentialPubKeyCertificate.value().begin(), credentialPubKeyCertificate.value().end()); certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(), attestationKeyCertificate.value().end()); optional<vector<vector<uint8_t>>> splitCertChain = support::certificateChainSplit(certificateChain); if (!splitCertChain) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error splitting certificate chain")); IIdentityCredentialStore::STATUS_FAILED, "Error getting private part of credentialKey")); } } credentialPrivKey_ = privKey.value(); // convert from vector<vector<uint8_t>>> to vector<Certificate>* *outCertificateChain = vector<Certificate>(); *outCertificateChain = vector<Certificate>(); for (const vector<uint8_t>& cert : splitCertChain.value()) { for (const vector<uint8_t>& cert : certificateChain_) { Certificate c = Certificate(); Certificate c = Certificate(); c.encodedCertificate = byteStringToSigned(cert); c.encodedCertificate = byteStringToSigned(cert); outCertificateChain->push_back(std::move(c)); outCertificateChain->push_back(std::move(c)); Loading
identity/aidl/default/WritableIdentityCredential.h +4 −1 Original line number Original line Diff line number Diff line Loading @@ -64,10 +64,13 @@ class WritableIdentityCredential : public BnWritableIdentityCredential { string docType_; string docType_; bool testCredential_; bool testCredential_; // These are set in initialize(). // This is set in initialize(). vector<uint8_t> storageKey_; vector<uint8_t> storageKey_; // These are set in getAttestationCertificate(). vector<uint8_t> credentialPrivKey_; vector<uint8_t> credentialPrivKey_; vector<uint8_t> credentialPubKey_; vector<uint8_t> credentialPubKey_; vector<vector<uint8_t>> certificateChain_; // These fields are initialized during startPersonalization() // These fields are initialized during startPersonalization() size_t numAccessControlProfileRemaining_; size_t numAccessControlProfileRemaining_; Loading
identity/support/Android.bp +4 −0 Original line number Original line Diff line number Diff line Loading @@ -23,10 +23,14 @@ cc_library { "include", "include", ], ], shared_libs: [ shared_libs: [ "android.hardware.keymaster@4.0", "libcrypto", "libcrypto", "libbase", "libbase", "libhidlbase", "libhidlbase", "libhardware", "libhardware", "libkeymaster_portable", "libsoft_attestation_cert", "libpuresoftkeymasterdevice", ], ], static_libs: [ static_libs: [ "libcppbor", "libcppbor", Loading
identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h +12 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <optional> #include <optional> #include <string> #include <string> #include <tuple> #include <tuple> #include <utility> #include <vector> #include <vector> namespace android { namespace android { Loading Loading @@ -106,6 +107,17 @@ optional<vector<uint8_t>> encryptAes128Gcm(const vector<uint8_t>& key, const vec // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // EC crypto functionality / abstraction (only supports P-256). // EC crypto functionality / abstraction (only supports P-256). // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the // PKCS#8 encoded key-pair. Also generates an attestation // certificate using the |challenge| and |applicationId|, and returns the generated // certificate in X.509 certificate chain format. // // The attestation time fields used will be the current time, and expires in one year. // // The first parameter of the return value is the keyPair generated, second return in // the pair is the attestation certificate generated. optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation( const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId); // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the // PKCS#8 encoded key-pair. // PKCS#8 encoded key-pair. Loading
identity/support/src/IdentityCredentialSupport.cpp +139 −0 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,13 @@ #include <cppbor.h> #include <cppbor.h> #include <cppbor_parse.h> #include <cppbor_parse.h> #include <android/hardware/keymaster/4.0/types.h> #include <keymaster/authorization_set.h> #include <keymaster/contexts/pure_soft_keymaster_context.h> #include <keymaster/contexts/soft_attestation_cert.h> #include <keymaster/keymaster_tags.h> #include <keymaster/km_openssl/attestation_utils.h> namespace android { namespace android { namespace hardware { namespace hardware { namespace identity { namespace identity { Loading Loading @@ -816,6 +823,138 @@ optional<vector<uint8_t>> hmacSha256(const vector<uint8_t>& key, const vector<ui return hmac; return hmac; } } // Generates the attestation certificate with the parameters passed in. Note // that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in // milli seconds since epoch. We are setting them to milliseconds due to // requirement in AuthorizationSet KM_DATE fields. The certificate created is // actually in seconds. optional<vector<vector<uint8_t>>> createAttestation(const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge, uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds) { ::keymaster::AuthorizationSet auth_set( ::keymaster::AuthorizationSetBuilder() .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(), challenge.size()) .Authorization(::keymaster::TAG_ACTIVE_DATETIME, activeTimeMilliSeconds) // Even though identity attestation hal said the application // id should be in software enforced authentication set, // keymaster portable lib expect the input in this // parameter because the software enforced in input to keymaster // refers to the key software enforced properties. And this // parameter refers to properties of the attestation which // includes app id. .Authorization(::keymaster::TAG_ATTESTATION_APPLICATION_ID, applicationId.data(), applicationId.size()) .Authorization(::keymaster::TAG_USAGE_EXPIRE_DATETIME, expireTimeMilliSeconds)); // Unique id and device id is not applicable for identity credential attestation, // so we don't need to set those or application id. ::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization( ::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds)); ::keymaster::AuthorizationSet hwEnforced( ::keymaster::AuthorizationSetBuilder() .Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN) .Authorization(::keymaster::TAG_KEY_SIZE, 256) .Authorization(::keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC) .Authorization(::keymaster::TAG_NO_AUTH_REQUIRED) .Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256) .Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256) .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY)); const keymaster_cert_chain_t* attestation_chain = ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr); if (attestation_chain == nullptr) { LOG(ERROR) << "Error getting attestation chain"; return {}; } const keymaster_key_blob_t* attestation_signing_key = ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr); if (attestation_signing_key == nullptr) { LOG(ERROR) << "Error getting attestation key"; return {}; } keymaster_error_t error; ::keymaster::CertChainPtr cert_chain_out; ::keymaster::PureSoftKeymasterContext context; // set identity version to 10 per hal requirements specified in IWriteableCredential.hal // For now, the identity version in the attestation is set in the keymaster // version field in the portable keymaster lib, which is a bit misleading. uint identity_version = 10; error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context, identity_version, *attestation_chain, *attestation_signing_key, &cert_chain_out); if (KM_ERROR_OK != error || !cert_chain_out) { LOG(ERROR) << "Error generate attestation from EVP key" << error; return {}; } // translate certificate format from keymaster_cert_chain_t to vector<uint8_t>. vector<vector<uint8_t>> attestationCertificate; for (int i = 0; i < cert_chain_out->entry_count; i++) { attestationCertificate.insert( attestationCertificate.end(), vector<uint8_t>( cert_chain_out->entries[i].data, cert_chain_out->entries[i].data + cert_chain_out->entries[i].data_length)); } return attestationCertificate; } optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation( const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) { auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new()); auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new()); auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); if (ec_key.get() == nullptr || pkey.get() == nullptr) { LOG(ERROR) << "Memory allocation failed"; return {}; } if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 || EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) { LOG(ERROR) << "Error generating key"; return {}; } if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1) { LOG(ERROR) << "Error getting private key"; return {}; } uint64_t now = time(nullptr); uint64_t secondsInOneYear = 365 * 24 * 60 * 60; uint64_t expireTimeMs = (now + secondsInOneYear) * 1000; optional<vector<vector<uint8_t>>> attestationCert = createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs); if (!attestationCert) { LOG(ERROR) << "Error create attestation from key and challenge"; return {}; } int size = i2d_PrivateKey(pkey.get(), nullptr); if (size == 0) { LOG(ERROR) << "Error generating public key encoding"; return {}; } vector<uint8_t> keyPair(size); unsigned char* p = keyPair.data(); i2d_PrivateKey(pkey.get(), &p); return make_pair(keyPair, attestationCert.value()); } optional<vector<uint8_t>> createEcKeyPair() { optional<vector<uint8_t>> createEcKeyPair() { auto ec_key = EC_KEY_Ptr(EC_KEY_new()); auto ec_key = EC_KEY_Ptr(EC_KEY_new()); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); Loading