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