// // Copyright (C) 2015 The Android Open Source Project // // 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. // #include "attestation/common/tpm_utility_v1.h" #include <base/files/file_path.h> #include <base/files/file_util.h> #include <base/logging.h> #include <base/memory/scoped_ptr.h> #include <base/stl_util.h> #include <crypto/scoped_openssl_types.h> #include <crypto/sha2.h> #include <openssl/rsa.h> #include <openssl/sha.h> #include <trousers/scoped_tss_type.h> #include <trousers/trousers.h> #include <trousers/tss.h> #define TPM_LOG(severity, result) \ LOG(severity) << "TPM error 0x" << std::hex << result \ << " (" << Trspi_Error_String(result) << "): " using trousers::ScopedTssContext; using trousers::ScopedTssKey; using trousers::ScopedTssMemory; using trousers::ScopedTssPcrs; namespace { using ScopedByteArray = scoped_ptr<BYTE, base::FreeDeleter>; using ScopedTssEncryptedData = trousers::ScopedTssObject<TSS_HENCDATA>; using ScopedTssHash = trousers::ScopedTssObject<TSS_HHASH>; const char* kTpmTpmEnabledFile = "/sys/class/tpm/tpm0/device/enabled"; const char* kMscTpmEnabledFile = "/sys/class/misc/tpm0/device/enabled"; const char* kTpmTpmOwnedFile = "/sys/class/tpm/tpm0/device/owned"; const char* kMscTpmOwnedFile = "/sys/class/misc/tpm0/device/owned"; const unsigned int kWellKnownExponent = 65537; const unsigned char kSha256DigestInfo[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; std::string GetFirstByte(const char* file_name) { std::string content; base::ReadFileToString(base::FilePath(file_name), &content); if (content.size() > 1) { content.resize(1); } return content; } BYTE* StringAsTSSBuffer(std::string* s) { return reinterpret_cast<BYTE*>(string_as_array(s)); } std::string TSSBufferAsString(const BYTE* buffer, size_t length) { return std::string(reinterpret_cast<const char*>(buffer), length); } } // namespace namespace attestation { TpmUtilityV1::~TpmUtilityV1() {} bool TpmUtilityV1::Initialize() { if (!ConnectContext(&context_handle_, &tpm_handle_)) { LOG(ERROR) << __func__ << ": Failed to connect to the TPM."; return false; } if (!IsTpmReady()) { LOG(WARNING) << __func__ << ": TPM is not owned; attestation services will " << "not be available until ownership is taken."; } return true; } bool TpmUtilityV1::IsTpmReady() { if (!is_ready_) { if (base::PathExists(base::FilePath(kMscTpmEnabledFile))) { is_ready_ = (GetFirstByte(kMscTpmEnabledFile) == "1" && GetFirstByte(kMscTpmOwnedFile) == "1"); } else { is_ready_ = (GetFirstByte(kTpmTpmEnabledFile) == "1" && GetFirstByte(kTpmTpmOwnedFile) == "1"); } } return is_ready_; } bool TpmUtilityV1::ActivateIdentity(const std::string& delegate_blob, const std::string& delegate_secret, const std::string& identity_key_blob, const std::string& asym_ca_contents, const std::string& sym_ca_attestation, std::string* credential) { CHECK(credential); if (!SetupSrk()) { LOG(ERROR) << "SRK is not ready."; return false; } // Connect to the TPM as the owner delegate. ScopedTssContext context_handle; TSS_HTPM tpm_handle; if (!ConnectContextAsDelegate(delegate_blob, delegate_secret, &context_handle, &tpm_handle)) { LOG(ERROR) << __func__ << ": Could not connect to the TPM."; return false; } // Load the Storage Root Key. TSS_RESULT result; ScopedTssKey srk_handle(context_handle); if (!LoadSrk(context_handle, &srk_handle)) { LOG(ERROR) << __func__ << ": Failed to load SRK."; return false; } // Load the AIK (which is wrapped by the SRK). std::string mutable_identity_key_blob(identity_key_blob); BYTE* identity_key_blob_buffer = StringAsTSSBuffer( &mutable_identity_key_blob); ScopedTssKey identity_key(context_handle); result = Tspi_Context_LoadKeyByBlob( context_handle, srk_handle, identity_key_blob.size(), identity_key_blob_buffer, identity_key.ptr()); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to load AIK."; return false; } std::string mutable_asym_ca_contents(asym_ca_contents); BYTE* asym_ca_contents_buffer = StringAsTSSBuffer(&mutable_asym_ca_contents); std::string mutable_sym_ca_attestation(sym_ca_attestation); BYTE* sym_ca_attestation_buffer = StringAsTSSBuffer( &mutable_sym_ca_attestation); UINT32 credential_length = 0; ScopedTssMemory credential_buffer(context_handle); result = Tspi_TPM_ActivateIdentity(tpm_handle, identity_key, asym_ca_contents.size(), asym_ca_contents_buffer, sym_ca_attestation.size(), sym_ca_attestation_buffer, &credential_length, credential_buffer.ptr()); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to activate identity."; return false; } credential->assign(TSSBufferAsString(credential_buffer.value(), credential_length)); return true; } bool TpmUtilityV1::CreateCertifiedKey(KeyType key_type, KeyUsage key_usage, const std::string& identity_key_blob, const std::string& external_data, std::string* key_blob, std::string* public_key, std::string* public_key_tpm_format, std::string* key_info, std::string* proof) { CHECK(key_blob && public_key && public_key_tpm_format && key_info && proof); if (!SetupSrk()) { LOG(ERROR) << "SRK is not ready."; return false; } if (key_type != KEY_TYPE_RSA) { LOG(ERROR) << "Only RSA supported on TPM v1.2."; return false; } // Load the AIK (which is wrapped by the SRK). ScopedTssKey identity_key(context_handle_); if (!LoadKeyFromBlob(identity_key_blob, context_handle_, srk_handle_, &identity_key)) { LOG(ERROR) << __func__ << "Failed to load AIK."; return false; } // Create a non-migratable RSA key. ScopedTssKey key(context_handle_); UINT32 tss_key_type = (key_usage == KEY_USAGE_SIGN) ? TSS_KEY_TYPE_SIGNING : TSS_KEY_TYPE_BIND; UINT32 init_flags = tss_key_type | TSS_KEY_NOT_MIGRATABLE | TSS_KEY_VOLATILE | TSS_KEY_NO_AUTHORIZATION | TSS_KEY_SIZE_2048; TSS_RESULT result = Tspi_Context_CreateObject(context_handle_, TSS_OBJECT_TYPE_RSAKEY, init_flags, key.ptr()); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to create object."; return false; } if (key_usage == KEY_USAGE_SIGN) { result = Tspi_SetAttribUint32(key, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME, TSS_SS_RSASSAPKCS1V15_DER); } else { result = Tspi_SetAttribUint32(key, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_ENCSCHEME, TSS_ES_RSAESOAEP_SHA1_MGF1); } if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to set scheme."; return false; } result = Tspi_Key_CreateKey(key, srk_handle_, 0); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to create key."; return false; } result = Tspi_Key_LoadKey(key, srk_handle_); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to load key."; return false; } // Certify the key. TSS_VALIDATION validation; memset(&validation, 0, sizeof(validation)); validation.ulExternalDataLength = external_data.size(); std::string mutable_external_data(external_data); validation.rgbExternalData = StringAsTSSBuffer(&mutable_external_data); result = Tspi_Key_CertifyKey(key, identity_key, &validation); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to certify key."; return false; } ScopedTssMemory scoped_certified_data(0, validation.rgbData); ScopedTssMemory scoped_proof(0, validation.rgbValidationData); // Get the certified public key. if (!GetDataAttribute(context_handle_, key, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, public_key_tpm_format)) { LOG(ERROR) << __func__ << ": Failed to read public key."; return false; } if (!ConvertPublicKeyToDER(*public_key_tpm_format, public_key)) { return false; } // Get the certified key blob so we can load it later. if (!GetDataAttribute(context_handle_, key, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, key_blob)) { LOG(ERROR) << __func__ << ": Failed to read key blob."; return false; } // Get the data that was certified. key_info->assign(TSSBufferAsString(validation.rgbData, validation.ulDataLength)); // Get the certification proof. proof->assign(TSSBufferAsString(validation.rgbValidationData, validation.ulValidationDataLength)); return true; } bool TpmUtilityV1::SealToPCR0(const std::string& data, std::string* sealed_data) { CHECK(sealed_data); if (!SetupSrk()) { LOG(ERROR) << "SRK is not ready."; return false; } // Create a PCRS object which holds the value of PCR0. ScopedTssPcrs pcrs_handle(context_handle_); TSS_RESULT result; if (TPM_ERROR(result = Tspi_Context_CreateObject(context_handle_, TSS_OBJECT_TYPE_PCRS, TSS_PCRS_STRUCT_INFO, pcrs_handle.ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_CreateObject"; return false; } UINT32 pcr_length = 0; ScopedTssMemory pcr_value(context_handle_); Tspi_TPM_PcrRead(tpm_handle_, 0, &pcr_length, pcr_value.ptr()); Tspi_PcrComposite_SetPcrValue(pcrs_handle, 0, pcr_length, pcr_value.value()); // Create a ENCDATA object to receive the sealed data. ScopedTssKey encrypted_data_handle(context_handle_); if (TPM_ERROR(result = Tspi_Context_CreateObject( context_handle_, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_SEAL, encrypted_data_handle.ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_CreateObject"; return false; } // Seal the given value with the SRK. std::string mutable_data(data); BYTE* data_buffer = StringAsTSSBuffer(&mutable_data); if (TPM_ERROR(result = Tspi_Data_Seal( encrypted_data_handle, srk_handle_, data.size(), data_buffer, pcrs_handle))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Data_Seal"; return false; } // Extract the sealed value. ScopedTssMemory encrypted_data(context_handle_); UINT32 encrypted_data_length = 0; if (TPM_ERROR(result = Tspi_GetAttribData(encrypted_data_handle, TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB, &encrypted_data_length, encrypted_data.ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_GetAttribData"; return false; } sealed_data->assign(TSSBufferAsString(encrypted_data.value(), encrypted_data_length)); return true; } bool TpmUtilityV1::Unseal(const std::string& sealed_data, std::string* data) { CHECK(data); if (!SetupSrk()) { LOG(ERROR) << "SRK is not ready."; return false; } // Create an ENCDATA object with the sealed value. ScopedTssKey encrypted_data_handle(context_handle_); TSS_RESULT result; if (TPM_ERROR(result = Tspi_Context_CreateObject( context_handle_, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_SEAL, encrypted_data_handle.ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_CreateObject"; return false; } std::string mutable_sealed_data(sealed_data); BYTE* sealed_data_buffer = StringAsTSSBuffer(&mutable_sealed_data); if (TPM_ERROR(result = Tspi_SetAttribData(encrypted_data_handle, TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB, sealed_data.size(), sealed_data_buffer))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_SetAttribData"; return false; } // Unseal using the SRK. ScopedTssMemory decrypted_data(context_handle_); UINT32 decrypted_data_length = 0; if (TPM_ERROR(result = Tspi_Data_Unseal(encrypted_data_handle, srk_handle_, &decrypted_data_length, decrypted_data.ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Data_Unseal"; return false; } data->assign(TSSBufferAsString(decrypted_data.value(), decrypted_data_length)); return true; } bool TpmUtilityV1::GetEndorsementPublicKey(std::string* public_key) { // Get a handle to the EK public key. ScopedTssKey ek_public_key_object(context_handle_); TSS_RESULT result = Tspi_TPM_GetPubEndorsementKey(tpm_handle_, false, nullptr, ek_public_key_object.ptr()); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to get key."; return false; } // Get the public key in TPM_PUBKEY form. std::string ek_public_key_blob; if (!GetDataAttribute(context_handle_, ek_public_key_object, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &ek_public_key_blob)) { LOG(ERROR) << __func__ << ": Failed to read public key."; return false; } // Get the public key in DER encoded form. if (!ConvertPublicKeyToDER(ek_public_key_blob, public_key)) { return false; } return true; } bool TpmUtilityV1::Unbind(const std::string& key_blob, const std::string& bound_data, std::string* data) { CHECK(data); if (!SetupSrk()) { LOG(ERROR) << "SRK is not ready."; return false; } ScopedTssKey key_handle(context_handle_); if (!LoadKeyFromBlob(key_blob, context_handle_, srk_handle_, &key_handle)) { return false; } TSS_RESULT result; ScopedTssEncryptedData data_handle(context_handle_); if (TPM_ERROR(result = Tspi_Context_CreateObject(context_handle_, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, data_handle.ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Tspi_Context_CreateObject failed."; return false; } std::string mutable_bound_data(bound_data); if (TPM_ERROR(result = Tspi_SetAttribData( data_handle, TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB, bound_data.size(), StringAsTSSBuffer(&mutable_bound_data)))) { TPM_LOG(ERROR, result) << __func__ << ": Tspi_SetAttribData failed."; return false; } ScopedTssMemory decrypted_data(context_handle_); UINT32 length = 0; if (TPM_ERROR(result = Tspi_Data_Unbind(data_handle, key_handle, &length, decrypted_data.ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Tspi_Data_Unbind failed."; return false; } data->assign(TSSBufferAsString(decrypted_data.value(), length)); return true; } bool TpmUtilityV1::Sign(const std::string& key_blob, const std::string& data_to_sign, std::string* signature) { CHECK(signature); if (!SetupSrk()) { LOG(ERROR) << "SRK is not ready."; return false; } ScopedTssKey key_handle(context_handle_); if (!LoadKeyFromBlob(key_blob, context_handle_, srk_handle_, &key_handle)) { return false; } // Construct an ASN.1 DER DigestInfo. std::string digest_to_sign(std::begin(kSha256DigestInfo), std::end(kSha256DigestInfo)); digest_to_sign += crypto::SHA256HashString(data_to_sign); // Create a hash object to hold the digest. ScopedTssHash hash_handle(context_handle_); TSS_RESULT result = Tspi_Context_CreateObject(context_handle_, TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, hash_handle.ptr()); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to create hash object."; return false; } result = Tspi_Hash_SetHashValue(hash_handle, digest_to_sign.size(), StringAsTSSBuffer(&digest_to_sign)); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to set hash data."; return false; } UINT32 length = 0; ScopedTssMemory buffer(context_handle_); result = Tspi_Hash_Sign(hash_handle, key_handle, &length, buffer.ptr()); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to generate signature."; return false; } signature->assign(TSSBufferAsString(buffer.value(), length)); return true; } bool TpmUtilityV1::ConnectContext(ScopedTssContext* context, TSS_HTPM* tpm) { *tpm = 0; TSS_RESULT result; if (TPM_ERROR(result = Tspi_Context_Create(context->ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_Create"; return false; } if (TPM_ERROR(result = Tspi_Context_Connect(*context, nullptr))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_Connect"; return false; } if (TPM_ERROR(result = Tspi_Context_GetTpmObject(*context, tpm))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_GetTpmObject"; return false; } return true; } bool TpmUtilityV1::ConnectContextAsDelegate(const std::string& delegate_blob, const std::string& delegate_secret, ScopedTssContext* context, TSS_HTPM* tpm) { *tpm = 0; if (!ConnectContext(context, tpm)) { return false; } TSS_RESULT result; TSS_HPOLICY tpm_usage_policy; if (TPM_ERROR(result = Tspi_GetPolicyObject(*tpm, TSS_POLICY_USAGE, &tpm_usage_policy))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_GetPolicyObject"; return false; } std::string mutable_delegate_secret(delegate_secret); BYTE* secret_buffer = StringAsTSSBuffer(&mutable_delegate_secret); if (TPM_ERROR(result = Tspi_Policy_SetSecret(tpm_usage_policy, TSS_SECRET_MODE_PLAIN, delegate_secret.size(), secret_buffer))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Policy_SetSecret"; return false; } std::string mutable_delegate_blob(delegate_blob); BYTE* blob_buffer = StringAsTSSBuffer(&mutable_delegate_blob); if (TPM_ERROR(result = Tspi_SetAttribData( tpm_usage_policy, TSS_TSPATTRIB_POLICY_DELEGATION_INFO, TSS_TSPATTRIB_POLDEL_OWNERBLOB, delegate_blob.size(), blob_buffer))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_SetAttribData"; return false; } return true; } bool TpmUtilityV1::SetupSrk() { if (!IsTpmReady()) { return false; } if (srk_handle_) { return true; } srk_handle_.reset(context_handle_, 0); if (!LoadSrk(context_handle_, &srk_handle_)) { LOG(ERROR) << __func__ << ": Failed to load SRK."; return false; } // In order to wrap a key with the SRK we need access to the SRK public key // and we need to get it manually. Once it's in the key object, we don't need // to do this again. UINT32 length = 0; ScopedTssMemory buffer(context_handle_); TSS_RESULT result; result = Tspi_Key_GetPubKey(srk_handle_, &length, buffer.ptr()); if (result != TSS_SUCCESS) { TPM_LOG(INFO, result) << __func__ << ": Failed to read SRK public key."; return false; } return true; } bool TpmUtilityV1::LoadSrk(TSS_HCONTEXT context_handle, ScopedTssKey* srk_handle) { TSS_RESULT result; TSS_UUID uuid = TSS_UUID_SRK; if (TPM_ERROR(result = Tspi_Context_LoadKeyByUUID(context_handle, TSS_PS_TYPE_SYSTEM, uuid, srk_handle->ptr()))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_LoadKeyByUUID"; return false; } // Check if the SRK wants a password. UINT32 auth_usage; if (TPM_ERROR(result = Tspi_GetAttribUint32(*srk_handle, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_AUTHUSAGE, &auth_usage))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_GetAttribUint32"; return false; } if (auth_usage) { // Give it an empty password if needed. TSS_HPOLICY usage_policy; if (TPM_ERROR(result = Tspi_GetPolicyObject(*srk_handle, TSS_POLICY_USAGE, &usage_policy))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_GetPolicyObject"; return false; } BYTE empty_password[] = {}; if (TPM_ERROR(result = Tspi_Policy_SetSecret(usage_policy, TSS_SECRET_MODE_PLAIN, 0, empty_password))) { TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Policy_SetSecret"; return false; } } return true; } bool TpmUtilityV1::LoadKeyFromBlob(const std::string& key_blob, TSS_HCONTEXT context_handle, TSS_HKEY parent_key_handle, ScopedTssKey* key_handle) { std::string mutable_key_blob(key_blob); BYTE* key_blob_buffer = StringAsTSSBuffer(&mutable_key_blob); TSS_RESULT result = Tspi_Context_LoadKeyByBlob( context_handle, parent_key_handle, key_blob.size(), key_blob_buffer, key_handle->ptr()); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << ": Failed to load key by blob."; return false; } return true; } bool TpmUtilityV1::GetDataAttribute(TSS_HCONTEXT context, TSS_HOBJECT object, TSS_FLAG flag, TSS_FLAG sub_flag, std::string* data) { UINT32 length = 0; ScopedTssMemory buffer(context); TSS_RESULT result = Tspi_GetAttribData(object, flag, sub_flag, &length, buffer.ptr()); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << __func__ << "Failed to read object attribute."; return false; } data->assign(TSSBufferAsString(buffer.value(), length)); return true; } bool TpmUtilityV1::ConvertPublicKeyToDER(const std::string& public_key, std::string* public_key_der) { // Parse the serialized TPM_PUBKEY. UINT64 offset = 0; std::string mutable_public_key(public_key); BYTE* buffer = StringAsTSSBuffer(&mutable_public_key); TPM_PUBKEY parsed; TSS_RESULT result = Trspi_UnloadBlob_PUBKEY(&offset, buffer, &parsed); if (TPM_ERROR(result)) { TPM_LOG(ERROR, result) << "Failed to parse TPM_PUBKEY."; return false; } ScopedByteArray scoped_key(parsed.pubKey.key); ScopedByteArray scoped_parms(parsed.algorithmParms.parms); TPM_RSA_KEY_PARMS* parms = reinterpret_cast<TPM_RSA_KEY_PARMS*>(parsed.algorithmParms.parms); crypto::ScopedRSA rsa(RSA_new()); CHECK(rsa.get()); // Get the public exponent. if (parms->exponentSize == 0) { rsa.get()->e = BN_new(); CHECK(rsa.get()->e); BN_set_word(rsa.get()->e, kWellKnownExponent); } else { rsa.get()->e = BN_bin2bn(parms->exponent, parms->exponentSize, nullptr); CHECK(rsa.get()->e); } // Get the modulus. rsa.get()->n = BN_bin2bn(parsed.pubKey.key, parsed.pubKey.keyLength, nullptr); CHECK(rsa.get()->n); // DER encode. int der_length = i2d_RSAPublicKey(rsa.get(), nullptr); if (der_length < 0) { LOG(ERROR) << "Failed to DER-encode public key."; return false; } public_key_der->resize(der_length); unsigned char* der_buffer = reinterpret_cast<unsigned char*>( string_as_array(public_key_der)); der_length = i2d_RSAPublicKey(rsa.get(), &der_buffer); if (der_length < 0) { LOG(ERROR) << "Failed to DER-encode public key."; return false; } public_key_der->resize(der_length); return true; } } // namespace attestation