Home | History | Annotate | Download | only in server
      1 //
      2 // Copyright (C) 2015 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "attestation/server/pkcs11_key_store.h"
     18 
     19 #include <memory>
     20 #include <string>
     21 
     22 #include <base/bind.h>
     23 #include <base/callback.h>
     24 #include <base/files/file_path.h>
     25 #include <base/logging.h>
     26 #include <base/stl_util.h>
     27 #include <base/strings/string_util.h>
     28 #include <chaps/isolate.h>
     29 #include <chaps/pkcs11/cryptoki.h>
     30 #include <chaps/token_manager_client.h>
     31 #include <brillo/cryptohome.h>
     32 #include <crypto/scoped_openssl_types.h>
     33 #include <openssl/rsa.h>
     34 #include <openssl/sha.h>
     35 #include <openssl/x509.h>
     36 
     37 namespace {
     38 
     39 std::string Sha1(const std::string& input) {
     40   unsigned char output[SHA_DIGEST_LENGTH];
     41   SHA1(reinterpret_cast<const unsigned char*>(input.data()), input.size(),
     42        output);
     43   return std::string(reinterpret_cast<char*>(output), SHA_DIGEST_LENGTH);
     44 }
     45 
     46 }  // namespace
     47 
     48 namespace attestation {
     49 
     50 typedef crypto::ScopedOpenSSL<X509, X509_free> ScopedX509;
     51 
     52 // An arbitrary application ID to identify PKCS #11 objects.
     53 const char kApplicationID[] = "CrOS_d5bbc079d2497110feadfc97c40d718ae46f4658";
     54 
     55 // A helper class to scope a PKCS #11 session.
     56 class ScopedSession {
     57  public:
     58   explicit ScopedSession(CK_SLOT_ID slot) : handle_(CK_INVALID_HANDLE) {
     59     CK_RV rv = C_Initialize(nullptr);
     60     if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
     61       // This may be normal in a test environment.
     62       LOG(INFO) << "PKCS #11 is not available.";
     63       return;
     64     }
     65     CK_FLAGS flags = CKF_RW_SESSION | CKF_SERIAL_SESSION;
     66     if (C_OpenSession(slot, flags, nullptr, nullptr, &handle_) != CKR_OK) {
     67       LOG(ERROR) << "Failed to open PKCS #11 session.";
     68       return;
     69     }
     70   }
     71 
     72   ~ScopedSession() {
     73     if (IsValid() && (C_CloseSession(handle_) != CKR_OK)) {
     74       LOG(WARNING) << "Failed to close PKCS #11 session.";
     75       handle_ = CK_INVALID_HANDLE;
     76     }
     77   }
     78 
     79   CK_SESSION_HANDLE handle() const { return handle_; }
     80 
     81   bool IsValid() const { return (handle_ != CK_INVALID_HANDLE); }
     82 
     83  private:
     84   CK_SESSION_HANDLE handle_;
     85 
     86   DISALLOW_COPY_AND_ASSIGN(ScopedSession);
     87 };
     88 
     89 Pkcs11KeyStore::Pkcs11KeyStore(chaps::TokenManagerClient* token_manager)
     90     : token_manager_(token_manager) {}
     91 
     92 Pkcs11KeyStore::~Pkcs11KeyStore() {}
     93 
     94 bool Pkcs11KeyStore::Read(const std::string& username,
     95                           const std::string& key_name,
     96                           std::string* key_data) {
     97   CK_SLOT_ID slot;
     98   if (!GetUserSlot(username, &slot)) {
     99     LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
    100     return false;
    101   }
    102   ScopedSession session(slot);
    103   if (!session.IsValid()) {
    104     LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
    105     return false;
    106   }
    107   CK_OBJECT_HANDLE key_handle = FindObject(session.handle(), key_name);
    108   if (key_handle == CK_INVALID_HANDLE) {
    109     LOG(WARNING) << "Pkcs11KeyStore: Key does not exist: " << key_name;
    110     return false;
    111   }
    112   // First get the attribute with a NULL buffer which will give us the length.
    113   CK_ATTRIBUTE attribute = {CKA_VALUE, nullptr, 0};
    114   if (C_GetAttributeValue(session.handle(), key_handle, &attribute, 1) !=
    115       CKR_OK) {
    116     LOG(ERROR) << "Pkcs11KeyStore: Failed to read key data: " << key_name;
    117     return false;
    118   }
    119   key_data->resize(attribute.ulValueLen);
    120   attribute.pValue = string_as_array(key_data);
    121   if (C_GetAttributeValue(session.handle(), key_handle, &attribute, 1) !=
    122       CKR_OK) {
    123     LOG(ERROR) << "Pkcs11KeyStore: Failed to read key data: " << key_name;
    124     return false;
    125   }
    126   key_data->resize(attribute.ulValueLen);
    127   return true;
    128 }
    129 
    130 bool Pkcs11KeyStore::Write(const std::string& username,
    131                            const std::string& key_name,
    132                            const std::string& key_data) {
    133   // Delete any existing key with the same name.
    134   if (!Delete(username, key_name)) {
    135     return false;
    136   }
    137   CK_SLOT_ID slot;
    138   if (!GetUserSlot(username, &slot)) {
    139     LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
    140     return false;
    141   }
    142   ScopedSession session(slot);
    143   if (!session.IsValid()) {
    144     LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
    145     return false;
    146   }
    147   std::string mutable_key_name(key_name);
    148   std::string mutable_key_data(key_data);
    149   std::string mutable_application_id(kApplicationID);
    150   // Create a new data object for the key.
    151   CK_OBJECT_CLASS object_class = CKO_DATA;
    152   CK_BBOOL true_value = CK_TRUE;
    153   CK_BBOOL false_value = CK_FALSE;
    154   CK_ATTRIBUTE attributes[] = {
    155       {CKA_CLASS, &object_class, sizeof(object_class)},
    156       {CKA_LABEL, string_as_array(&mutable_key_name), mutable_key_name.size()},
    157       {CKA_VALUE, string_as_array(&mutable_key_data), mutable_key_data.size()},
    158       {CKA_APPLICATION, string_as_array(&mutable_application_id),
    159        mutable_application_id.size()},
    160       {CKA_TOKEN, &true_value, sizeof(true_value)},
    161       {CKA_PRIVATE, &true_value, sizeof(true_value)},
    162       {CKA_MODIFIABLE, &false_value, sizeof(false_value)}};
    163   CK_OBJECT_HANDLE key_handle = CK_INVALID_HANDLE;
    164   if (C_CreateObject(session.handle(), attributes, arraysize(attributes),
    165                      &key_handle) != CKR_OK) {
    166     LOG(ERROR) << "Pkcs11KeyStore: Failed to write key data: " << key_name;
    167     return false;
    168   }
    169   return true;
    170 }
    171 
    172 bool Pkcs11KeyStore::Delete(const std::string& username,
    173                             const std::string& key_name) {
    174   CK_SLOT_ID slot;
    175   if (!GetUserSlot(username, &slot)) {
    176     LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
    177     return false;
    178   }
    179   ScopedSession session(slot);
    180   if (!session.IsValid()) {
    181     LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
    182     return false;
    183   }
    184   CK_OBJECT_HANDLE key_handle = FindObject(session.handle(), key_name);
    185   if (key_handle != CK_INVALID_HANDLE) {
    186     if (C_DestroyObject(session.handle(), key_handle) != CKR_OK) {
    187       LOG(ERROR) << "Pkcs11KeyStore: Failed to delete key data.";
    188       return false;
    189     }
    190   }
    191   return true;
    192 }
    193 
    194 bool Pkcs11KeyStore::DeleteByPrefix(const std::string& username,
    195                                     const std::string& key_prefix) {
    196   CK_SLOT_ID slot;
    197   if (!GetUserSlot(username, &slot)) {
    198     LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
    199     return false;
    200   }
    201   ScopedSession session(slot);
    202   if (!session.IsValid()) {
    203     LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
    204     return false;
    205   }
    206   EnumObjectsCallback callback =
    207       base::Bind(&Pkcs11KeyStore::DeleteIfMatchesPrefix, base::Unretained(this),
    208                  session.handle(), key_prefix);
    209   if (!EnumObjects(session.handle(), callback)) {
    210     LOG(ERROR) << "Pkcs11KeyStore: Failed to delete key data.";
    211     return false;
    212   }
    213   return true;
    214 }
    215 
    216 bool Pkcs11KeyStore::Register(const std::string& username,
    217                               const std::string& label,
    218                               KeyType key_type,
    219                               KeyUsage key_usage,
    220                               const std::string& private_key_blob,
    221                               const std::string& public_key_der,
    222                               const std::string& certificate) {
    223   const CK_ATTRIBUTE_TYPE kKeyBlobAttribute = CKA_VENDOR_DEFINED + 1;
    224 
    225   if (key_type != KEY_TYPE_RSA) {
    226     LOG(ERROR) << "Pkcs11KeyStore: Only RSA supported.";
    227     return false;
    228   }
    229   CK_SLOT_ID slot;
    230   if (!GetUserSlot(username, &slot)) {
    231     LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
    232     return false;
    233   }
    234   ScopedSession session(slot);
    235   if (!session.IsValid()) {
    236     LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
    237     return false;
    238   }
    239 
    240   // Extract the modulus from the public key.
    241   const unsigned char* asn1_ptr =
    242       reinterpret_cast<const unsigned char*>(public_key_der.data());
    243   crypto::ScopedRSA public_key(
    244       d2i_RSAPublicKey(nullptr, &asn1_ptr, public_key_der.size()));
    245   if (!public_key.get()) {
    246     LOG(ERROR) << "Pkcs11KeyStore: Failed to decode public key.";
    247     return false;
    248   }
    249   std::string modulus(BN_num_bytes(public_key.get()->n), 0);
    250   int length =
    251       BN_bn2bin(public_key.get()->n,
    252                 reinterpret_cast<unsigned char*>(string_as_array(&modulus)));
    253   if (length <= 0) {
    254     LOG(ERROR) << "Pkcs11KeyStore: Failed to extract public key modulus.";
    255     return false;
    256   }
    257   modulus.resize(length);
    258 
    259   // Construct a PKCS #11 template for the public key object.
    260   CK_BBOOL true_value = CK_TRUE;
    261   CK_BBOOL false_value = CK_FALSE;
    262   CK_KEY_TYPE p11_key_type = CKK_RSA;
    263   CK_OBJECT_CLASS public_key_class = CKO_PUBLIC_KEY;
    264   std::string id = Sha1(modulus);
    265   std::string mutable_label(label);
    266   CK_ULONG modulus_bits = modulus.size() * 8;
    267   CK_BBOOL sign_usage = (key_usage == KEY_USAGE_SIGN);
    268   CK_BBOOL decrypt_usage = (key_usage == KEY_USAGE_DECRYPT);
    269   unsigned char public_exponent[] = {1, 0, 1};
    270   CK_ATTRIBUTE public_key_attributes[] = {
    271       {CKA_CLASS, &public_key_class, sizeof(public_key_class)},
    272       {CKA_TOKEN, &true_value, sizeof(true_value)},
    273       {CKA_DERIVE, &false_value, sizeof(false_value)},
    274       {CKA_WRAP, &false_value, sizeof(false_value)},
    275       {CKA_VERIFY, &sign_usage, sizeof(sign_usage)},
    276       {CKA_VERIFY_RECOVER, &false_value, sizeof(false_value)},
    277       {CKA_ENCRYPT, &decrypt_usage, sizeof(decrypt_usage)},
    278       {CKA_KEY_TYPE, &p11_key_type, sizeof(p11_key_type)},
    279       {CKA_ID, string_as_array(&id), id.size()},
    280       {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
    281       {CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits)},
    282       {CKA_PUBLIC_EXPONENT, public_exponent, arraysize(public_exponent)},
    283       {CKA_MODULUS, string_as_array(&modulus), modulus.size()}};
    284 
    285   CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
    286   if (C_CreateObject(session.handle(), public_key_attributes,
    287                      arraysize(public_key_attributes),
    288                      &object_handle) != CKR_OK) {
    289     LOG(ERROR) << "Pkcs11KeyStore: Failed to create public key object.";
    290     return false;
    291   }
    292 
    293   // Construct a PKCS #11 template for the private key object.
    294   std::string mutable_private_key_blob(private_key_blob);
    295   CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY;
    296   CK_ATTRIBUTE private_key_attributes[] = {
    297       {CKA_CLASS, &private_key_class, sizeof(private_key_class)},
    298       {CKA_TOKEN, &true_value, sizeof(true_value)},
    299       {CKA_PRIVATE, &true_value, sizeof(true_value)},
    300       {CKA_SENSITIVE, &true_value, sizeof(true_value)},
    301       {CKA_EXTRACTABLE, &false_value, sizeof(false_value)},
    302       {CKA_DERIVE, &false_value, sizeof(false_value)},
    303       {CKA_UNWRAP, &false_value, sizeof(false_value)},
    304       {CKA_SIGN, &sign_usage, sizeof(sign_usage)},
    305       {CKA_SIGN_RECOVER, &false_value, sizeof(false_value)},
    306       {CKA_DECRYPT, &decrypt_usage, sizeof(decrypt_usage)},
    307       {CKA_KEY_TYPE, &p11_key_type, sizeof(p11_key_type)},
    308       {CKA_ID, string_as_array(&id), id.size()},
    309       {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
    310       {CKA_PUBLIC_EXPONENT, public_exponent, arraysize(public_exponent)},
    311       {CKA_MODULUS, string_as_array(&modulus), modulus.size()},
    312       {kKeyBlobAttribute, string_as_array(&mutable_private_key_blob),
    313        mutable_private_key_blob.size()}};
    314 
    315   if (C_CreateObject(session.handle(), private_key_attributes,
    316                      arraysize(private_key_attributes),
    317                      &object_handle) != CKR_OK) {
    318     LOG(ERROR) << "Pkcs11KeyStore: Failed to create private key object.";
    319     return false;
    320   }
    321 
    322   if (!certificate.empty()) {
    323     std::string subject;
    324     std::string issuer;
    325     std::string serial_number;
    326     if (!GetCertificateFields(certificate, &subject, &issuer, &serial_number)) {
    327       LOG(WARNING) << "Pkcs11KeyStore: Failed to find certificate fields.";
    328     }
    329     // Construct a PKCS #11 template for a certificate object.
    330     std::string mutable_certificate = certificate;
    331     CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE;
    332     CK_CERTIFICATE_TYPE certificate_type = CKC_X_509;
    333     CK_ATTRIBUTE certificate_attributes[] = {
    334         {CKA_CLASS, &certificate_class, sizeof(certificate_class)},
    335         {CKA_TOKEN, &true_value, sizeof(true_value)},
    336         {CKA_PRIVATE, &false_value, sizeof(false_value)},
    337         {CKA_ID, string_as_array(&id), id.size()},
    338         {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
    339         {CKA_CERTIFICATE_TYPE, &certificate_type, sizeof(certificate_type)},
    340         {CKA_SUBJECT, string_as_array(&subject), subject.size()},
    341         {CKA_ISSUER, string_as_array(&issuer), issuer.size()},
    342         {CKA_SERIAL_NUMBER, string_as_array(&serial_number),
    343          serial_number.size()},
    344         {CKA_VALUE, string_as_array(&mutable_certificate),
    345          mutable_certificate.size()}};
    346 
    347     if (C_CreateObject(session.handle(), certificate_attributes,
    348                        arraysize(certificate_attributes),
    349                        &object_handle) != CKR_OK) {
    350       LOG(ERROR) << "Pkcs11KeyStore: Failed to create certificate object.";
    351       return false;
    352     }
    353   }
    354 
    355   // Close all sessions in an attempt to trigger other modules to find the new
    356   // objects.
    357   C_CloseAllSessions(slot);
    358 
    359   return true;
    360 }
    361 
    362 bool Pkcs11KeyStore::RegisterCertificate(const std::string& username,
    363                                          const std::string& certificate) {
    364   CK_SLOT_ID slot;
    365   if (!GetUserSlot(username, &slot)) {
    366     LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
    367     return false;
    368   }
    369   ScopedSession session(slot);
    370   if (!session.IsValid()) {
    371     LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
    372     return false;
    373   }
    374 
    375   if (DoesCertificateExist(session.handle(), certificate)) {
    376     LOG(INFO) << "Pkcs11KeyStore: Certificate already exists.";
    377     return true;
    378   }
    379   std::string subject;
    380   std::string issuer;
    381   std::string serial_number;
    382   if (!GetCertificateFields(certificate, &subject, &issuer, &serial_number)) {
    383     LOG(WARNING) << "Pkcs11KeyStore: Failed to find certificate fields.";
    384   }
    385   // Construct a PKCS #11 template for a certificate object.
    386   std::string mutable_certificate = certificate;
    387   CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE;
    388   CK_CERTIFICATE_TYPE certificate_type = CKC_X_509;
    389   CK_BBOOL true_value = CK_TRUE;
    390   CK_BBOOL false_value = CK_FALSE;
    391   CK_ATTRIBUTE certificate_attributes[] = {
    392       {CKA_CLASS, &certificate_class, sizeof(certificate_class)},
    393       {CKA_TOKEN, &true_value, sizeof(true_value)},
    394       {CKA_PRIVATE, &false_value, sizeof(false_value)},
    395       {CKA_CERTIFICATE_TYPE, &certificate_type, sizeof(certificate_type)},
    396       {CKA_SUBJECT, string_as_array(&subject), subject.size()},
    397       {CKA_ISSUER, string_as_array(&issuer), issuer.size()},
    398       {CKA_SERIAL_NUMBER, string_as_array(&serial_number),
    399        serial_number.size()},
    400       {CKA_VALUE, string_as_array(&mutable_certificate),
    401        mutable_certificate.size()}};
    402   CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
    403   if (C_CreateObject(session.handle(), certificate_attributes,
    404                      arraysize(certificate_attributes),
    405                      &object_handle) != CKR_OK) {
    406     LOG(ERROR) << "Pkcs11KeyStore: Failed to create certificate object.";
    407     return false;
    408   }
    409   return true;
    410 }
    411 
    412 CK_OBJECT_HANDLE Pkcs11KeyStore::FindObject(CK_SESSION_HANDLE session_handle,
    413                                             const std::string& key_name) {
    414   // Assemble a search template.
    415   std::string mutable_key_name(key_name);
    416   std::string mutable_application_id(kApplicationID);
    417   CK_OBJECT_CLASS object_class = CKO_DATA;
    418   CK_BBOOL true_value = CK_TRUE;
    419   CK_BBOOL false_value = CK_FALSE;
    420   CK_ATTRIBUTE attributes[] = {
    421       {CKA_CLASS, &object_class, sizeof(object_class)},
    422       {CKA_LABEL, string_as_array(&mutable_key_name), mutable_key_name.size()},
    423       {CKA_APPLICATION, string_as_array(&mutable_application_id),
    424        mutable_application_id.size()},
    425       {CKA_TOKEN, &true_value, sizeof(true_value)},
    426       {CKA_PRIVATE, &true_value, sizeof(true_value)},
    427       {CKA_MODIFIABLE, &false_value, sizeof(false_value)}};
    428   CK_OBJECT_HANDLE key_handle = CK_INVALID_HANDLE;
    429   CK_ULONG count = 0;
    430   if ((C_FindObjectsInit(session_handle, attributes, arraysize(attributes)) !=
    431        CKR_OK) ||
    432       (C_FindObjects(session_handle, &key_handle, 1, &count) != CKR_OK) ||
    433       (C_FindObjectsFinal(session_handle) != CKR_OK)) {
    434     LOG(ERROR) << "Key search failed: " << key_name;
    435     return CK_INVALID_HANDLE;
    436   }
    437   if (count == 1)
    438     return key_handle;
    439   return CK_INVALID_HANDLE;
    440 }
    441 
    442 bool Pkcs11KeyStore::GetUserSlot(const std::string& username,
    443                                  CK_SLOT_ID_PTR slot) {
    444   const char kChapsDaemonName[] = "chaps";
    445   const char kChapsSystemToken[] = "/var/lib/chaps";
    446   base::FilePath token_path =
    447       username.empty()
    448           ? base::FilePath(kChapsSystemToken)
    449           : brillo::cryptohome::home::GetDaemonPath(username, kChapsDaemonName);
    450   CK_RV rv;
    451   rv = C_Initialize(nullptr);
    452   if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
    453     LOG(WARNING) << __func__ << ": C_Initialize failed.";
    454     return false;
    455   }
    456   CK_ULONG num_slots = 0;
    457   rv = C_GetSlotList(CK_TRUE, nullptr, &num_slots);
    458   if (rv != CKR_OK) {
    459     LOG(WARNING) << __func__ << ": C_GetSlotList(nullptr) failed.";
    460     return false;
    461   }
    462   std::unique_ptr<CK_SLOT_ID[]> slot_list(new CK_SLOT_ID[num_slots]);
    463   rv = C_GetSlotList(CK_TRUE, slot_list.get(), &num_slots);
    464   if (rv != CKR_OK) {
    465     LOG(WARNING) << __func__ << ": C_GetSlotList failed.";
    466     return false;
    467   }
    468   // Look through all slots for |token_path|.
    469   for (CK_ULONG i = 0; i < num_slots; ++i) {
    470     base::FilePath slot_path;
    471     if (token_manager_->GetTokenPath(
    472             chaps::IsolateCredentialManager::GetDefaultIsolateCredential(),
    473             slot_list[i], &slot_path) &&
    474         (token_path == slot_path)) {
    475       *slot = slot_list[i];
    476       return true;
    477     }
    478   }
    479   LOG(WARNING) << __func__ << ": Path not found.";
    480   return false;
    481 }
    482 
    483 bool Pkcs11KeyStore::EnumObjects(
    484     CK_SESSION_HANDLE session_handle,
    485     const Pkcs11KeyStore::EnumObjectsCallback& callback) {
    486   std::string mutable_application_id(kApplicationID);
    487   // Assemble a search template.
    488   CK_OBJECT_CLASS object_class = CKO_DATA;
    489   CK_BBOOL true_value = CK_TRUE;
    490   CK_BBOOL false_value = CK_FALSE;
    491   CK_ATTRIBUTE attributes[] = {
    492       {CKA_CLASS, &object_class, sizeof(object_class)},
    493       {CKA_APPLICATION, string_as_array(&mutable_application_id),
    494        mutable_application_id.size()},
    495       {CKA_TOKEN, &true_value, sizeof(true_value)},
    496       {CKA_PRIVATE, &true_value, sizeof(true_value)},
    497       {CKA_MODIFIABLE, &false_value, sizeof(false_value)}};
    498   const CK_ULONG kMaxHandles = 100;  // Arbitrary.
    499   CK_OBJECT_HANDLE handles[kMaxHandles];
    500   CK_ULONG count = 0;
    501   if ((C_FindObjectsInit(session_handle, attributes, arraysize(attributes)) !=
    502        CKR_OK) ||
    503       (C_FindObjects(session_handle, handles, kMaxHandles, &count) != CKR_OK)) {
    504     LOG(ERROR) << "Key search failed.";
    505     return false;
    506   }
    507   while (count > 0) {
    508     for (CK_ULONG i = 0; i < count; ++i) {
    509       std::string key_name;
    510       if (!GetKeyName(session_handle, handles[i], &key_name)) {
    511         LOG(WARNING) << "Found key object but failed to get name.";
    512         continue;
    513       }
    514       if (!callback.Run(key_name, handles[i]))
    515         return false;
    516     }
    517     if (C_FindObjects(session_handle, handles, kMaxHandles, &count) != CKR_OK) {
    518       LOG(ERROR) << "Key search continuation failed.";
    519       return false;
    520     }
    521   }
    522   if (C_FindObjectsFinal(session_handle) != CKR_OK) {
    523     LOG(WARNING) << "Failed to finalize key search.";
    524   }
    525   return true;
    526 }
    527 
    528 bool Pkcs11KeyStore::GetKeyName(CK_SESSION_HANDLE session_handle,
    529                                 CK_OBJECT_HANDLE object_handle,
    530                                 std::string* key_name) {
    531   CK_ATTRIBUTE attribute = {CKA_LABEL, nullptr, 0};
    532   if (C_GetAttributeValue(session_handle, object_handle, &attribute, 1) !=
    533       CKR_OK) {
    534     LOG(ERROR) << "C_GetAttributeValue(CKA_LABEL) [length] failed.";
    535     return false;
    536   }
    537   key_name->resize(attribute.ulValueLen);
    538   attribute.pValue = string_as_array(key_name);
    539   if (C_GetAttributeValue(session_handle, object_handle, &attribute, 1) !=
    540       CKR_OK) {
    541     LOG(ERROR) << "C_GetAttributeValue(CKA_LABEL) failed.";
    542     return false;
    543   }
    544   return true;
    545 }
    546 
    547 bool Pkcs11KeyStore::DeleteIfMatchesPrefix(CK_SESSION_HANDLE session_handle,
    548                                            const std::string& key_prefix,
    549                                            const std::string& key_name,
    550                                            CK_OBJECT_HANDLE object_handle) {
    551   if (base::StartsWith(key_name, key_prefix, base::CompareCase::SENSITIVE)) {
    552     if (C_DestroyObject(session_handle, object_handle) != CKR_OK) {
    553       LOG(ERROR) << "C_DestroyObject failed.";
    554       return false;
    555     }
    556   }
    557   return true;
    558 }
    559 
    560 bool Pkcs11KeyStore::GetCertificateFields(const std::string& certificate,
    561                                           std::string* subject,
    562                                           std::string* issuer,
    563                                           std::string* serial_number) {
    564   const unsigned char* asn1_ptr =
    565       reinterpret_cast<const unsigned char*>(certificate.data());
    566   ScopedX509 x509(d2i_X509(nullptr, &asn1_ptr, certificate.size()));
    567   if (!x509.get() || !x509->cert_info || !x509->cert_info->subject) {
    568     LOG(WARNING) << "Pkcs11KeyStore: Failed to decode certificate.";
    569     return false;
    570   }
    571   unsigned char* subject_buffer = nullptr;
    572   int length = i2d_X509_NAME(x509->cert_info->subject, &subject_buffer);
    573   crypto::ScopedOpenSSLBytes scoped_subject_buffer(subject_buffer);
    574   if (length <= 0) {
    575     LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate subject.";
    576     return false;
    577   }
    578   subject->assign(reinterpret_cast<char*>(subject_buffer), length);
    579 
    580   unsigned char* issuer_buffer = nullptr;
    581   length = i2d_X509_NAME(x509->cert_info->issuer, &issuer_buffer);
    582   crypto::ScopedOpenSSLBytes scoped_issuer_buffer(issuer_buffer);
    583   if (length <= 0) {
    584     LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate issuer.";
    585     return false;
    586   }
    587   issuer->assign(reinterpret_cast<char*>(issuer_buffer), length);
    588 
    589   unsigned char* serial_number_buffer = nullptr;
    590   length =
    591       i2d_ASN1_INTEGER(x509->cert_info->serialNumber, &serial_number_buffer);
    592   crypto::ScopedOpenSSLBytes scoped_serial_number_buffer(serial_number_buffer);
    593   if (length <= 0) {
    594     LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate serial "
    595                     "number.";
    596     return false;
    597   }
    598   serial_number->assign(reinterpret_cast<char*>(serial_number_buffer), length);
    599   return true;
    600 }
    601 
    602 bool Pkcs11KeyStore::DoesCertificateExist(CK_SESSION_HANDLE session_handle,
    603                                           const std::string& certificate) {
    604   CK_OBJECT_CLASS object_class = CKO_CERTIFICATE;
    605   CK_BBOOL true_value = CK_TRUE;
    606   CK_BBOOL false_value = CK_FALSE;
    607   std::string mutable_certificate = certificate;
    608   CK_ATTRIBUTE attributes[] = {
    609       {CKA_CLASS, &object_class, sizeof(object_class)},
    610       {CKA_TOKEN, &true_value, sizeof(true_value)},
    611       {CKA_PRIVATE, &false_value, sizeof(false_value)},
    612       {CKA_VALUE, string_as_array(&mutable_certificate),
    613        mutable_certificate.size()}};
    614   CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
    615   CK_ULONG count = 0;
    616   if ((C_FindObjectsInit(session_handle, attributes, arraysize(attributes)) !=
    617        CKR_OK) ||
    618       (C_FindObjects(session_handle, &object_handle, 1, &count) != CKR_OK) ||
    619       (C_FindObjectsFinal(session_handle) != CKR_OK)) {
    620     return false;
    621   }
    622   return (count > 0);
    623 }
    624 
    625 }  // namespace attestation
    626