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