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