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
37namespace {
38
39std::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
48namespace attestation {
49
50typedef crypto::ScopedOpenSSL<X509, X509_free> ScopedX509;
51
52// An arbitrary application ID to identify PKCS #11 objects.
53const char kApplicationID[] = "CrOS_d5bbc079d2497110feadfc97c40d718ae46f4658";
54
55// A helper class to scope a PKCS #11 session.
56class 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 {
80    return handle_;
81  }
82
83  bool IsValid() const {
84    return (handle_ != CK_INVALID_HANDLE);
85  }
86
87 private:
88  CK_SESSION_HANDLE handle_;
89
90  DISALLOW_COPY_AND_ASSIGN(ScopedSession);
91};
92
93Pkcs11KeyStore::Pkcs11KeyStore(chaps::TokenManagerClient* token_manager)
94    : token_manager_(token_manager) {}
95
96Pkcs11KeyStore::~Pkcs11KeyStore() {}
97
98bool Pkcs11KeyStore::Read(const std::string& username,
99                          const std::string& key_name,
100                          std::string* key_data) {
101  CK_SLOT_ID slot;
102  if (!GetUserSlot(username, &slot)) {
103    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
104    return false;
105  }
106  ScopedSession session(slot);
107  if (!session.IsValid()) {
108    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
109    return false;
110  }
111  CK_OBJECT_HANDLE key_handle = FindObject(session.handle(), key_name);
112  if (key_handle == CK_INVALID_HANDLE) {
113    LOG(WARNING) << "Pkcs11KeyStore: Key does not exist: " << key_name;
114    return false;
115  }
116  // First get the attribute with a NULL buffer which will give us the length.
117  CK_ATTRIBUTE attribute = {CKA_VALUE, nullptr, 0};
118  if (C_GetAttributeValue(session.handle(),
119                          key_handle,
120                          &attribute, 1) != CKR_OK) {
121    LOG(ERROR) << "Pkcs11KeyStore: Failed to read key data: " << key_name;
122    return false;
123  }
124  key_data->resize(attribute.ulValueLen);
125  attribute.pValue = string_as_array(key_data);
126  if (C_GetAttributeValue(session.handle(),
127                          key_handle,
128                          &attribute, 1) != CKR_OK) {
129    LOG(ERROR) << "Pkcs11KeyStore: Failed to read key data: " << key_name;
130    return false;
131  }
132  key_data->resize(attribute.ulValueLen);
133  return true;
134}
135
136bool Pkcs11KeyStore::Write(const std::string& username,
137                           const std::string& key_name,
138                           const std::string& key_data) {
139  // Delete any existing key with the same name.
140  if (!Delete(username, key_name)) {
141    return false;
142  }
143  CK_SLOT_ID slot;
144  if (!GetUserSlot(username, &slot)) {
145    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
146    return false;
147  }
148  ScopedSession session(slot);
149  if (!session.IsValid()) {
150    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
151    return false;
152  }
153  std::string mutable_key_name(key_name);
154  std::string mutable_key_data(key_data);
155  std::string mutable_application_id(kApplicationID);
156  // Create a new data object for the key.
157  CK_OBJECT_CLASS object_class = CKO_DATA;
158  CK_BBOOL true_value = CK_TRUE;
159  CK_BBOOL false_value = CK_FALSE;
160  CK_ATTRIBUTE attributes[] = {
161    {CKA_CLASS, &object_class, sizeof(object_class)},
162    {
163      CKA_LABEL,
164      string_as_array(&mutable_key_name),
165      mutable_key_name.size()
166    },
167    {
168      CKA_VALUE,
169      string_as_array(&mutable_key_data),
170      mutable_key_data.size()
171    },
172    {
173      CKA_APPLICATION,
174      string_as_array(&mutable_application_id),
175      mutable_application_id.size()
176    },
177    {CKA_TOKEN, &true_value, sizeof(true_value)},
178    {CKA_PRIVATE, &true_value, sizeof(true_value)},
179    {CKA_MODIFIABLE, &false_value, sizeof(false_value)}
180  };
181  CK_OBJECT_HANDLE key_handle = CK_INVALID_HANDLE;
182  if (C_CreateObject(session.handle(),
183                     attributes,
184                     arraysize(attributes),
185                     &key_handle) != CKR_OK) {
186    LOG(ERROR) << "Pkcs11KeyStore: Failed to write key data: " << key_name;
187    return false;
188  }
189  return true;
190}
191
192bool Pkcs11KeyStore::Delete(const std::string& username,
193                            const std::string& key_name) {
194  CK_SLOT_ID slot;
195  if (!GetUserSlot(username, &slot)) {
196    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
197    return false;
198  }
199  ScopedSession session(slot);
200  if (!session.IsValid()) {
201    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
202    return false;
203  }
204  CK_OBJECT_HANDLE key_handle = FindObject(session.handle(), key_name);
205  if (key_handle != CK_INVALID_HANDLE) {
206    if (C_DestroyObject(session.handle(), key_handle) != CKR_OK) {
207      LOG(ERROR) << "Pkcs11KeyStore: Failed to delete key data.";
208      return false;
209    }
210  }
211  return true;
212}
213
214bool Pkcs11KeyStore::DeleteByPrefix(const std::string& username,
215                                    const std::string& key_prefix) {
216  CK_SLOT_ID slot;
217  if (!GetUserSlot(username, &slot)) {
218    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
219    return false;
220  }
221  ScopedSession session(slot);
222  if (!session.IsValid()) {
223    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
224    return false;
225  }
226  EnumObjectsCallback callback = base::Bind(
227      &Pkcs11KeyStore::DeleteIfMatchesPrefix,
228      base::Unretained(this),
229      session.handle(),
230      key_prefix);
231  if (!EnumObjects(session.handle(), callback)) {
232    LOG(ERROR) << "Pkcs11KeyStore: Failed to delete key data.";
233    return false;
234  }
235  return true;
236}
237
238bool Pkcs11KeyStore::Register(const std::string& username,
239                              const std::string& label,
240                              KeyType key_type,
241                              KeyUsage key_usage,
242                              const std::string& private_key_blob,
243                              const std::string& public_key_der,
244                              const std::string& certificate) {
245  const CK_ATTRIBUTE_TYPE kKeyBlobAttribute = CKA_VENDOR_DEFINED + 1;
246
247  if (key_type != KEY_TYPE_RSA) {
248    LOG(ERROR) << "Pkcs11KeyStore: Only RSA supported.";
249    return false;
250  }
251  CK_SLOT_ID slot;
252  if (!GetUserSlot(username, &slot)) {
253    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
254    return false;
255  }
256  ScopedSession session(slot);
257  if (!session.IsValid()) {
258    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
259    return false;
260  }
261
262  // Extract the modulus from the public key.
263  const unsigned char* asn1_ptr = reinterpret_cast<const unsigned char*>(
264      public_key_der.data());
265  crypto::ScopedRSA public_key(d2i_RSAPublicKey(nullptr,
266                                                &asn1_ptr,
267                                                public_key_der.size()));
268  if (!public_key.get()) {
269    LOG(ERROR) << "Pkcs11KeyStore: Failed to decode public key.";
270    return false;
271  }
272  std::string modulus(BN_num_bytes(public_key.get()->n), 0);
273  int length = BN_bn2bin(public_key.get()->n, reinterpret_cast<unsigned char*>(
274      string_as_array(&modulus)));
275  if (length <= 0) {
276    LOG(ERROR) << "Pkcs11KeyStore: Failed to extract public key modulus.";
277    return false;
278  }
279  modulus.resize(length);
280
281  // Construct a PKCS #11 template for the public key object.
282  CK_BBOOL true_value = CK_TRUE;
283  CK_BBOOL false_value = CK_FALSE;
284  CK_KEY_TYPE p11_key_type = CKK_RSA;
285  CK_OBJECT_CLASS public_key_class = CKO_PUBLIC_KEY;
286  std::string id = Sha1(modulus);
287  std::string mutable_label(label);
288  CK_ULONG modulus_bits = modulus.size() * 8;
289  CK_BBOOL sign_usage = (key_usage == KEY_USAGE_SIGN);
290  CK_BBOOL decrypt_usage = (key_usage == KEY_USAGE_DECRYPT);
291  unsigned char public_exponent[] = {1, 0, 1};
292  CK_ATTRIBUTE public_key_attributes[] = {
293    {CKA_CLASS, &public_key_class, sizeof(public_key_class)},
294    {CKA_TOKEN, &true_value, sizeof(true_value)},
295    {CKA_DERIVE, &false_value, sizeof(false_value)},
296    {CKA_WRAP, &false_value, sizeof(false_value)},
297    {CKA_VERIFY, &sign_usage, sizeof(sign_usage)},
298    {CKA_VERIFY_RECOVER, &false_value, sizeof(false_value)},
299    {CKA_ENCRYPT, &decrypt_usage, sizeof(decrypt_usage)},
300    {CKA_KEY_TYPE, &p11_key_type, sizeof(p11_key_type)},
301    {CKA_ID, string_as_array(&id), id.size()},
302    {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
303    {CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits)},
304    {CKA_PUBLIC_EXPONENT, public_exponent, arraysize(public_exponent)},
305    {CKA_MODULUS, string_as_array(&modulus), modulus.size()}
306  };
307
308  CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
309  if (C_CreateObject(session.handle(),
310                     public_key_attributes,
311                     arraysize(public_key_attributes),
312                     &object_handle) != CKR_OK) {
313    LOG(ERROR) << "Pkcs11KeyStore: Failed to create public key object.";
314    return false;
315  }
316
317  // Construct a PKCS #11 template for the private key object.
318  std::string mutable_private_key_blob(private_key_blob);
319  CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY;
320  CK_ATTRIBUTE private_key_attributes[] = {
321    {CKA_CLASS, &private_key_class, sizeof(private_key_class)},
322    {CKA_TOKEN, &true_value, sizeof(true_value)},
323    {CKA_PRIVATE, &true_value, sizeof(true_value)},
324    {CKA_SENSITIVE, &true_value, sizeof(true_value)},
325    {CKA_EXTRACTABLE, &false_value, sizeof(false_value)},
326    {CKA_DERIVE, &false_value, sizeof(false_value)},
327    {CKA_UNWRAP, &false_value, sizeof(false_value)},
328    {CKA_SIGN, &sign_usage, sizeof(sign_usage)},
329    {CKA_SIGN_RECOVER, &false_value, sizeof(false_value)},
330    {CKA_DECRYPT, &decrypt_usage, sizeof(decrypt_usage)},
331    {CKA_KEY_TYPE, &p11_key_type, sizeof(p11_key_type)},
332    {CKA_ID, string_as_array(&id), id.size()},
333    {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
334    {CKA_PUBLIC_EXPONENT, public_exponent, arraysize(public_exponent)},
335    {CKA_MODULUS, string_as_array(&modulus), modulus.size()},
336    {
337      kKeyBlobAttribute,
338      string_as_array(&mutable_private_key_blob),
339      mutable_private_key_blob.size()
340    }
341  };
342
343  if (C_CreateObject(session.handle(),
344                     private_key_attributes,
345                     arraysize(private_key_attributes),
346                     &object_handle) != CKR_OK) {
347    LOG(ERROR) << "Pkcs11KeyStore: Failed to create private key object.";
348    return false;
349  }
350
351  if (!certificate.empty()) {
352    std::string subject;
353    std::string issuer;
354    std::string serial_number;
355    if (!GetCertificateFields(certificate, &subject, &issuer, &serial_number)) {
356      LOG(WARNING) << "Pkcs11KeyStore: Failed to find certificate fields.";
357    }
358    // Construct a PKCS #11 template for a certificate object.
359    std::string mutable_certificate = certificate;
360    CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE;
361    CK_CERTIFICATE_TYPE certificate_type = CKC_X_509;
362    CK_ATTRIBUTE certificate_attributes[] = {
363      {CKA_CLASS, &certificate_class, sizeof(certificate_class)},
364      {CKA_TOKEN, &true_value, sizeof(true_value)},
365      {CKA_PRIVATE, &false_value, sizeof(false_value)},
366      {CKA_ID, string_as_array(&id), id.size()},
367      {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
368      {CKA_CERTIFICATE_TYPE, &certificate_type, sizeof(certificate_type)},
369      {CKA_SUBJECT, string_as_array(&subject), subject.size()},
370      {CKA_ISSUER, string_as_array(&issuer), issuer.size()},
371      {
372        CKA_SERIAL_NUMBER,
373        string_as_array(&serial_number),
374        serial_number.size()
375      },
376      {
377        CKA_VALUE,
378        string_as_array(&mutable_certificate),
379        mutable_certificate.size()
380      }
381    };
382
383    if (C_CreateObject(session.handle(),
384                       certificate_attributes,
385                       arraysize(certificate_attributes),
386                       &object_handle) != CKR_OK) {
387      LOG(ERROR) << "Pkcs11KeyStore: Failed to create certificate object.";
388      return false;
389    }
390  }
391
392  // Close all sessions in an attempt to trigger other modules to find the new
393  // objects.
394  C_CloseAllSessions(slot);
395
396  return true;
397}
398
399bool Pkcs11KeyStore::RegisterCertificate(const std::string& username,
400                                         const std::string& certificate) {
401  CK_SLOT_ID slot;
402  if (!GetUserSlot(username, &slot)) {
403    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
404    return false;
405  }
406  ScopedSession session(slot);
407  if (!session.IsValid()) {
408    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
409    return false;
410  }
411
412  if (DoesCertificateExist(session.handle(), certificate)) {
413    LOG(INFO) << "Pkcs11KeyStore: Certificate already exists.";
414    return true;
415  }
416  std::string subject;
417  std::string issuer;
418  std::string serial_number;
419  if (!GetCertificateFields(certificate, &subject, &issuer, &serial_number)) {
420    LOG(WARNING) << "Pkcs11KeyStore: Failed to find certificate fields.";
421  }
422  // Construct a PKCS #11 template for a certificate object.
423  std::string mutable_certificate = certificate;
424  CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE;
425  CK_CERTIFICATE_TYPE certificate_type = CKC_X_509;
426  CK_BBOOL true_value = CK_TRUE;
427  CK_BBOOL false_value = CK_FALSE;
428  CK_ATTRIBUTE certificate_attributes[] = {
429    {CKA_CLASS, &certificate_class, sizeof(certificate_class)},
430    {CKA_TOKEN, &true_value, sizeof(true_value)},
431    {CKA_PRIVATE, &false_value, sizeof(false_value)},
432    {CKA_CERTIFICATE_TYPE, &certificate_type, sizeof(certificate_type)},
433    {CKA_SUBJECT, string_as_array(&subject), subject.size()},
434    {CKA_ISSUER, string_as_array(&issuer), issuer.size()},
435    {CKA_SERIAL_NUMBER, string_as_array(&serial_number), serial_number.size()},
436    {
437      CKA_VALUE,
438      string_as_array(&mutable_certificate),
439      mutable_certificate.size()
440    }
441  };
442  CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
443  if (C_CreateObject(session.handle(),
444                     certificate_attributes,
445                     arraysize(certificate_attributes),
446                     &object_handle) != CKR_OK) {
447    LOG(ERROR) << "Pkcs11KeyStore: Failed to create certificate object.";
448    return false;
449  }
450  return true;
451}
452
453CK_OBJECT_HANDLE Pkcs11KeyStore::FindObject(CK_SESSION_HANDLE session_handle,
454                                            const std::string& key_name) {
455  // Assemble a search template.
456  std::string mutable_key_name(key_name);
457  std::string mutable_application_id(kApplicationID);
458  CK_OBJECT_CLASS object_class = CKO_DATA;
459  CK_BBOOL true_value = CK_TRUE;
460  CK_BBOOL false_value = CK_FALSE;
461  CK_ATTRIBUTE attributes[] = {
462    {CKA_CLASS, &object_class, sizeof(object_class)},
463    {
464      CKA_LABEL,
465      string_as_array(&mutable_key_name),
466      mutable_key_name.size()
467    },
468    {
469      CKA_APPLICATION,
470      string_as_array(&mutable_application_id),
471      mutable_application_id.size()
472    },
473    {CKA_TOKEN, &true_value, sizeof(true_value)},
474    {CKA_PRIVATE, &true_value, sizeof(true_value)},
475    {CKA_MODIFIABLE, &false_value, sizeof(false_value)}
476  };
477  CK_OBJECT_HANDLE key_handle = CK_INVALID_HANDLE;
478  CK_ULONG count = 0;
479  if ((C_FindObjectsInit(session_handle,
480                         attributes,
481                         arraysize(attributes)) != CKR_OK) ||
482      (C_FindObjects(session_handle, &key_handle, 1, &count) != CKR_OK) ||
483      (C_FindObjectsFinal(session_handle) != CKR_OK)) {
484    LOG(ERROR) << "Key search failed: " << key_name;
485    return CK_INVALID_HANDLE;
486  }
487  if (count == 1)
488    return key_handle;
489  return CK_INVALID_HANDLE;
490}
491
492bool Pkcs11KeyStore::GetUserSlot(const std::string& username,
493                                 CK_SLOT_ID_PTR slot) {
494  const char kChapsDaemonName[] = "chaps";
495  const char kChapsSystemToken[] = "/var/lib/chaps";
496  base::FilePath token_path = username.empty() ?
497      base::FilePath(kChapsSystemToken) :
498      brillo::cryptohome::home::GetDaemonPath(username, kChapsDaemonName);
499  CK_RV rv;
500  rv = C_Initialize(nullptr);
501  if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
502    LOG(WARNING) << __func__ << ": C_Initialize failed.";
503    return false;
504  }
505  CK_ULONG num_slots = 0;
506  rv = C_GetSlotList(CK_TRUE, nullptr, &num_slots);
507  if (rv != CKR_OK) {
508    LOG(WARNING) << __func__ << ": C_GetSlotList(nullptr) failed.";
509    return false;
510  }
511  std::unique_ptr<CK_SLOT_ID[]> slot_list(new CK_SLOT_ID[num_slots]);
512  rv = C_GetSlotList(CK_TRUE, slot_list.get(), &num_slots);
513  if (rv != CKR_OK) {
514    LOG(WARNING) << __func__ << ": C_GetSlotList failed.";
515    return false;
516  }
517  // Look through all slots for |token_path|.
518  for (CK_ULONG i = 0; i < num_slots; ++i) {
519    base::FilePath slot_path;
520    if (token_manager_->GetTokenPath(
521        chaps::IsolateCredentialManager::GetDefaultIsolateCredential(),
522        slot_list[i],
523        &slot_path) && (token_path == slot_path)) {
524      *slot = slot_list[i];
525      return true;
526    }
527  }
528  LOG(WARNING) << __func__ << ": Path not found.";
529  return false;
530}
531
532bool Pkcs11KeyStore::EnumObjects(
533    CK_SESSION_HANDLE session_handle,
534    const Pkcs11KeyStore::EnumObjectsCallback& callback) {
535  std::string mutable_application_id(kApplicationID);
536  // Assemble a search template.
537  CK_OBJECT_CLASS object_class = CKO_DATA;
538  CK_BBOOL true_value = CK_TRUE;
539  CK_BBOOL false_value = CK_FALSE;
540  CK_ATTRIBUTE attributes[] = {
541    {CKA_CLASS, &object_class, sizeof(object_class)},
542    {
543      CKA_APPLICATION,
544      string_as_array(&mutable_application_id),
545      mutable_application_id.size()
546    },
547    {CKA_TOKEN, &true_value, sizeof(true_value)},
548    {CKA_PRIVATE, &true_value, sizeof(true_value)},
549    {CKA_MODIFIABLE, &false_value, sizeof(false_value)}
550  };
551  const CK_ULONG kMaxHandles = 100;  // Arbitrary.
552  CK_OBJECT_HANDLE handles[kMaxHandles];
553  CK_ULONG count = 0;
554  if ((C_FindObjectsInit(session_handle,
555                         attributes,
556                         arraysize(attributes)) != CKR_OK) ||
557      (C_FindObjects(session_handle, handles, kMaxHandles, &count) != CKR_OK)) {
558    LOG(ERROR) << "Key search failed.";
559    return false;
560  }
561  while (count > 0) {
562    for (CK_ULONG i = 0; i < count; ++i) {
563      std::string key_name;
564      if (!GetKeyName(session_handle, handles[i], &key_name)) {
565        LOG(WARNING) << "Found key object but failed to get name.";
566        continue;
567      }
568      if (!callback.Run(key_name, handles[i]))
569        return false;
570    }
571    if (C_FindObjects(session_handle, handles, kMaxHandles, &count) != CKR_OK) {
572      LOG(ERROR) << "Key search continuation failed.";
573      return false;
574    }
575  }
576  if (C_FindObjectsFinal(session_handle) != CKR_OK) {
577    LOG(WARNING) << "Failed to finalize key search.";
578  }
579  return true;
580}
581
582bool Pkcs11KeyStore::GetKeyName(CK_SESSION_HANDLE session_handle,
583                                CK_OBJECT_HANDLE object_handle,
584                                std::string* key_name) {
585  CK_ATTRIBUTE attribute = {CKA_LABEL, nullptr, 0};
586  if (C_GetAttributeValue(session_handle, object_handle, &attribute, 1) !=
587      CKR_OK) {
588    LOG(ERROR) << "C_GetAttributeValue(CKA_LABEL) [length] failed.";
589    return false;
590  }
591  key_name->resize(attribute.ulValueLen);
592  attribute.pValue = string_as_array(key_name);
593  if (C_GetAttributeValue(session_handle, object_handle, &attribute, 1) !=
594      CKR_OK) {
595    LOG(ERROR) << "C_GetAttributeValue(CKA_LABEL) failed.";
596    return false;
597  }
598  return true;
599}
600
601bool Pkcs11KeyStore::DeleteIfMatchesPrefix(CK_SESSION_HANDLE session_handle,
602                                           const std::string& key_prefix,
603                                           const std::string& key_name,
604                                           CK_OBJECT_HANDLE object_handle) {
605  if (base::StartsWith(key_name, key_prefix, base::CompareCase::SENSITIVE)) {
606    if (C_DestroyObject(session_handle, object_handle) != CKR_OK) {
607      LOG(ERROR) << "C_DestroyObject failed.";
608      return false;
609    }
610  }
611  return true;
612}
613
614bool Pkcs11KeyStore::GetCertificateFields(const std::string& certificate,
615                                          std::string* subject,
616                                          std::string* issuer,
617                                          std::string* serial_number) {
618  const unsigned char* asn1_ptr = reinterpret_cast<const unsigned char*>(
619      certificate.data());
620  ScopedX509 x509(d2i_X509(nullptr, &asn1_ptr, certificate.size()));
621  if (!x509.get() || !x509->cert_info || !x509->cert_info->subject) {
622    LOG(WARNING) << "Pkcs11KeyStore: Failed to decode certificate.";
623    return false;
624  }
625  unsigned char* subject_buffer = nullptr;
626  int length = i2d_X509_NAME(x509->cert_info->subject, &subject_buffer);
627  crypto::ScopedOpenSSLBytes scoped_subject_buffer(subject_buffer);
628  if (length <= 0) {
629    LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate subject.";
630    return false;
631  }
632  subject->assign(reinterpret_cast<char*>(subject_buffer), length);
633
634  unsigned char* issuer_buffer = nullptr;
635  length = i2d_X509_NAME(x509->cert_info->issuer, &issuer_buffer);
636  crypto::ScopedOpenSSLBytes scoped_issuer_buffer(issuer_buffer);
637  if (length <= 0) {
638    LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate issuer.";
639    return false;
640  }
641  issuer->assign(reinterpret_cast<char*>(issuer_buffer), length);
642
643  unsigned char* serial_number_buffer = nullptr;
644  length = i2d_ASN1_INTEGER(x509->cert_info->serialNumber,
645                            &serial_number_buffer);
646  crypto::ScopedOpenSSLBytes scoped_serial_number_buffer(serial_number_buffer);
647  if (length <= 0) {
648    LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate serial "
649                    "number.";
650    return false;
651  }
652  serial_number->assign(reinterpret_cast<char*>(serial_number_buffer), length);
653  return true;
654}
655
656bool Pkcs11KeyStore::DoesCertificateExist(
657    CK_SESSION_HANDLE session_handle,
658    const std::string& certificate) {
659  CK_OBJECT_CLASS object_class = CKO_CERTIFICATE;
660  CK_BBOOL true_value = CK_TRUE;
661  CK_BBOOL false_value = CK_FALSE;
662  std::string mutable_certificate = certificate;
663  CK_ATTRIBUTE attributes[] = {
664    {CKA_CLASS, &object_class, sizeof(object_class)},
665    {CKA_TOKEN, &true_value, sizeof(true_value)},
666    {CKA_PRIVATE, &false_value, sizeof(false_value)},
667    {
668      CKA_VALUE,
669      string_as_array(&mutable_certificate),
670      mutable_certificate.size()
671    }
672  };
673  CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
674  CK_ULONG count = 0;
675  if ((C_FindObjectsInit(session_handle,
676                         attributes,
677                         arraysize(attributes)) != CKR_OK) ||
678      (C_FindObjects(session_handle, &object_handle, 1, &count) != CKR_OK) ||
679      (C_FindObjectsFinal(session_handle) != CKR_OK)) {
680    return false;
681  }
682  return (count > 0);
683}
684
685}  // namespace attestation
686