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 
Sha1(const std::string & input)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:
ScopedSession(CK_SLOT_ID slot)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 
~ScopedSession()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 
handle() const79   CK_SESSION_HANDLE handle() const { return handle_; }
80 
IsValid() const81   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 
Pkcs11KeyStore(chaps::TokenManagerClient * token_manager)89 Pkcs11KeyStore::Pkcs11KeyStore(chaps::TokenManagerClient* token_manager)
90     : token_manager_(token_manager) {}
91 
~Pkcs11KeyStore()92 Pkcs11KeyStore::~Pkcs11KeyStore() {}
93 
Read(const std::string & username,const std::string & key_name,std::string * key_data)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 
Write(const std::string & username,const std::string & key_name,const std::string & key_data)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 
Delete(const std::string & username,const std::string & key_name)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 
DeleteByPrefix(const std::string & username,const std::string & key_prefix)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 
Register(const std::string & username,const std::string & label,KeyType key_type,KeyUsage key_usage,const std::string & private_key_blob,const std::string & public_key_der,const std::string & certificate)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 
RegisterCertificate(const std::string & username,const std::string & certificate)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 
FindObject(CK_SESSION_HANDLE session_handle,const std::string & key_name)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 
GetUserSlot(const std::string & username,CK_SLOT_ID_PTR slot)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 
EnumObjects(CK_SESSION_HANDLE session_handle,const Pkcs11KeyStore::EnumObjectsCallback & callback)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 
GetKeyName(CK_SESSION_HANDLE session_handle,CK_OBJECT_HANDLE object_handle,std::string * key_name)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 
DeleteIfMatchesPrefix(CK_SESSION_HANDLE session_handle,const std::string & key_prefix,const std::string & key_name,CK_OBJECT_HANDLE object_handle)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 
GetCertificateFields(const std::string & certificate,std::string * subject,std::string * issuer,std::string * serial_number)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 
DoesCertificateExist(CK_SESSION_HANDLE session_handle,const std::string & certificate)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