OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/x509_util.h" | 5 #include "net/base/x509_util.h" |
6 #include "net/base/x509_util_nss.h" | 6 #include "net/base/x509_util_nss.h" |
7 | 7 |
8 #include <cert.h> | 8 #include <cert.h> |
9 #include <cryptohi.h> | 9 #include <cryptohi.h> |
10 #include <pk11pub.h> | 10 #include <pk11pub.h> |
11 #include <prerror.h> | 11 #include <prerror.h> |
12 #include <secmod.h> | 12 #include <secmod.h> |
13 #include <secport.h> | 13 #include <secport.h> |
14 | 14 |
15 #include "base/debug/leak_annotations.h" | 15 #include "base/debug/leak_annotations.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
18 #include "base/memory/singleton.h" | 18 #include "base/memory/singleton.h" |
19 #include "crypto/nss_util.h" | 19 #include "crypto/nss_util.h" |
20 #include "crypto/nss_util_internal.h" | 20 #include "crypto/nss_util_internal.h" |
21 #include "crypto/rsa_private_key.h" | 21 #include "crypto/rsa_private_key.h" |
22 #include "crypto/scoped_nss_types.h" | 22 #include "crypto/scoped_nss_types.h" |
23 #include "net/base/x509_certificate.h" | |
24 #include "net/third_party/mozilla_security_manager/nsNSSCertTrust.h" | |
25 | |
26 namespace msm = mozilla_security_manager; | |
23 | 27 |
24 namespace { | 28 namespace { |
25 | 29 |
26 class ObCertOIDWrapper { | 30 class ObCertOIDWrapper { |
27 public: | 31 public: |
28 static ObCertOIDWrapper* GetInstance() { | 32 static ObCertOIDWrapper* GetInstance() { |
29 // Instantiated as a leaky singleton to allow the singleton to be | 33 // Instantiated as a leaky singleton to allow the singleton to be |
30 // constructed on a worker thead that is not joined when a process | 34 // constructed on a worker thead that is not joined when a process |
31 // shuts down. | 35 // shuts down. |
32 return Singleton<ObCertOIDWrapper, | 36 return Singleton<ObCertOIDWrapper, |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 // Sign the ASN1 encoded cert and save it to |result|. | 163 // Sign the ASN1 encoded cert and save it to |result|. |
160 rv = SEC_DerSignData(arena, result, der.data, der.len, key, algo_id); | 164 rv = SEC_DerSignData(arena, result, der.data, der.len, key, algo_id); |
161 if (rv != SECSuccess) | 165 if (rv != SECSuccess) |
162 return false; | 166 return false; |
163 | 167 |
164 // Save the signed result to the cert. | 168 // Save the signed result to the cert. |
165 cert->derCert = *result; | 169 cert->derCert = *result; |
166 | 170 |
167 return true; | 171 return true; |
168 } | 172 } |
169 | |
wtc
2011/12/08 00:07:43
Nit: keep this blank line. This blank line matche
Greg Spencer (Chromium)
2011/12/09 18:51:38
Done.
| |
170 } // namespace | 173 } // namespace |
171 | 174 |
172 namespace net { | 175 namespace net { |
173 | 176 |
174 namespace x509_util { | 177 namespace x509_util { |
175 | 178 |
176 CERTCertificate* CreateSelfSignedCert( | 179 CERTCertificate* CreateSelfSignedCert( |
177 SECKEYPublicKey* public_key, | 180 SECKEYPublicKey* public_key, |
178 SECKEYPrivateKey* private_key, | 181 SECKEYPrivateKey* private_key, |
179 const std::string& subject, | 182 const std::string& subject, |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
306 | 309 |
307 DCHECK(cert->derCert.len); | 310 DCHECK(cert->derCert.len); |
308 // XXX copied from X509Certificate::GetDEREncoded | 311 // XXX copied from X509Certificate::GetDEREncoded |
309 der_cert->clear(); | 312 der_cert->clear(); |
310 der_cert->append(reinterpret_cast<char*>(cert->derCert.data), | 313 der_cert->append(reinterpret_cast<char*>(cert->derCert.data), |
311 cert->derCert.len); | 314 cert->derCert.len); |
312 CERT_DestroyCertificate(cert); | 315 CERT_DestroyCertificate(cert); |
313 return true; | 316 return true; |
314 } | 317 } |
315 | 318 |
319 CertType GetCertType(const X509Certificate* cert) { | |
320 DCHECK(cert); | |
321 msm::nsNSSCertTrust trust(cert->os_cert_handle()->trust); | |
322 if (trust.HasAnyUser()) | |
323 return USER_CERT; | |
324 if (trust.HasAnyCA() || CERT_IsCACert(cert->os_cert_handle(), NULL)) | |
325 return CA_CERT; | |
326 if (trust.HasPeer(PR_TRUE, PR_FALSE, PR_FALSE)) | |
327 return SERVER_CERT; | |
328 return UNKNOWN_CERT; | |
329 } | |
330 | |
331 std::string GetDefaultCertificateLabel(const X509Certificate* cert) { | |
332 DCHECK(cert); | |
333 std::string result; | |
334 | |
335 #if defined(OS_CHROMEOS) | |
336 // When we have label support, we want to keep any existing label by default. | |
337 result = GetLabel(cert); | |
338 if (!result.empty()) | |
339 return result; | |
340 #endif | |
wtc
2011/12/08 00:07:43
This behavior (lines 335-340) is difficult to docu
Greg Spencer (Chromium)
2011/12/09 18:51:38
We talked about this: I've removed this from the f
| |
341 | |
342 switch (GetCertType(cert)) { | |
343 case CA_CERT: { | |
344 char *nickname = CERT_MakeCANickname(cert->os_cert_handle()); | |
wtc
2011/12/08 00:07:43
Nit: put '*' next to 'char'.
Greg Spencer (Chromium)
2011/12/09 18:51:38
Done.
| |
345 result = nickname; | |
346 PORT_Free(nickname); | |
347 break; | |
348 } | |
349 case USER_CERT: { | |
350 // Create a nickname for this user certificate. | |
351 // We use the scheme used by Firefox: | |
wtc
2011/12/08 00:07:43
Nit: extraneous space before "We".
Greg Spencer (Chromium)
2011/12/09 18:51:38
Fixed.
| |
352 // --> <subject's common name>'s <issuer's common name> ID. | |
353 // TODO(gspencer): internationalize this: it's wrong to | |
354 // hard code English. | |
355 | |
356 std::string username, ca_name; | |
357 char* temp_username = CERT_GetCommonName( | |
358 &cert->os_cert_handle()->subject); | |
359 char* temp_ca_name = CERT_GetCommonName(&cert->os_cert_handle()->issuer); | |
360 if (temp_username) { | |
361 username = temp_username; | |
362 PORT_Free(temp_username); | |
363 } | |
364 if (temp_ca_name) { | |
365 ca_name = temp_ca_name; | |
366 PORT_Free(temp_ca_name); | |
367 } | |
368 result = username + "'s " + ca_name + " ID"; | |
369 break; | |
370 } | |
371 case SERVER_CERT: { | |
372 result = cert->subject().GetDisplayName(); | |
373 break; | |
374 } | |
wtc
2011/12/08 00:07:43
Nit: this case doesn't need curly braces because i
Greg Spencer (Chromium)
2011/12/09 18:51:38
Done.
| |
375 case UNKNOWN_CERT: | |
376 default: | |
377 break; | |
378 } | |
379 return result; | |
380 } | |
381 | |
382 #if defined(OS_CHROMEOS) | |
383 bool SetLabel(X509Certificate* cert, const std::string& label) { | |
384 DCHECK(cert); | |
385 // If the slot isn't initialized, then do nothing. | |
386 if (!cert->os_cert_handle()->slot) | |
387 return true; | |
388 | |
389 // First we set the nickname on the cert itself. This doesn't | |
390 // work on production NSS yet (it's not implemented), but ChromeOS | |
391 // has a patched version that it will work on. | |
392 SECItem sec_label; | |
393 sec_label.type = siUTF8String; | |
wtc
2011/12/08 00:07:43
PK11_WriteRawAttribute does not use the 'type' fie
Greg Spencer (Chromium)
2011/12/09 18:51:38
Done.
| |
394 sec_label.data = reinterpret_cast<unsigned char*>( | |
395 const_cast<char*>(label.c_str())); | |
396 sec_label.len = label.size(); | |
397 SECStatus srv = PK11_WriteRawAttribute(PK11_TypeCert, | |
398 cert->os_cert_handle(), | |
399 CKA_LABEL, | |
400 &sec_label); | |
wtc
2011/12/08 00:07:43
IMPORTANT: my concern about this solution is that
Greg Spencer (Chromium)
2011/12/09 18:51:38
I've stopped trying to set the nickname later, and
| |
401 if (srv != SECSuccess) | |
402 LOG(WARNING) << "Unable to set certificate label to " | |
403 << label; | |
wtc
2011/12/08 00:07:43
Nit: please add curly braces because the statement
Greg Spencer (Chromium)
2011/12/09 18:51:38
Done.
| |
404 | |
405 // As far as I can tell, there is no API for PKCS11 that allows one | |
406 // to get the valid public key (that has a valid PKCS11 slot and id) | |
407 // associated with a certificate. So, instead, I extract the public | |
408 // key using CERT_ExtractPublicKey (which returns a key that has no | |
409 // slot or pkcs11 id set), and then we iterate through all of the | |
410 // existing public keys (which do have this information), and look | |
411 // for one that has the same DER encoding as the public key | |
412 // extracted from this certificate. I then set that key's nickname | |
413 // to the given label. | |
414 SECKEYPublicKey* public_key = CERT_ExtractPublicKey(cert->os_cert_handle()); | |
415 if (!public_key) | |
416 return false; | |
417 | |
418 SECKEYPublicKeyList* pubkey_list = | |
419 PK11_ListPublicKeysInSlot(cert->os_cert_handle()->slot, NULL); | |
420 | |
421 // If there are no public keys, that's OK. | |
422 if (pubkey_list) { | |
423 for (SECKEYPublicKeyListNode* node = PUBKEY_LIST_HEAD(pubkey_list); | |
424 !PUBKEY_LIST_END(node, pubkey_list); | |
425 node = PUBKEY_LIST_NEXT(node)) { | |
426 SECItem* der_encoded = PK11_DEREncodePublicKey(node->key); | |
427 if (SECITEM_CompareItem( | |
428 der_encoded, | |
429 &cert->os_cert_handle()->derPublicKey) == SECEqual) | |
430 PK11_SetPublicKeyNickname(node->key, label.c_str()); | |
431 SECITEM_FreeItem(der_encoded, PR_TRUE); | |
432 } | |
433 SECKEY_DestroyPublicKeyList(pubkey_list); | |
434 } | |
435 SECKEY_DestroyPublicKey(public_key); | |
436 | |
437 // Now set the nickname on the private key (if there is one) | |
438 SECKEYPrivateKey* private_key = | |
439 PK11_FindPrivateKeyFromCert(cert->os_cert_handle()->slot, | |
440 cert->os_cert_handle(), | |
441 NULL); | |
442 if (private_key) { | |
443 PK11_SetPrivateKeyNickname(private_key, label.c_str()); | |
444 SECKEY_DestroyPrivateKey(private_key); | |
445 } | |
446 return true; | |
447 } | |
448 | |
449 std::string GetLabel(const X509Certificate* cert) { | |
450 std::string result; | |
451 // This doesn't work on production NSS yet (it's not implemented), but | |
452 // ChromeOS has a patched version that it will work on. | |
453 SECItem sec_label; | |
454 SECStatus srv = PK11_ReadRawAttribute(PK11_TypeCert, | |
455 cert->os_cert_handle(), | |
456 CKA_LABEL, | |
457 &sec_label); | |
wtc
2011/12/08 00:07:43
Why don't you just use the 'nickname' field of the
Greg Spencer (Chromium)
2011/12/09 18:51:38
For server and CA certs, this works because I can
| |
458 if (srv != SECSuccess) { | |
459 return result; | |
460 } | |
461 | |
462 result = std::string(reinterpret_cast<char *>(sec_label.data), sec_label.len); | |
463 PORT_Free(sec_label.data); | |
464 return result; | |
465 } | |
466 #endif // OS_CHROMEOS | |
467 | |
468 | |
316 } // namespace x509_util | 469 } // namespace x509_util |
317 | 470 |
318 } // namespace net | 471 } // namespace net |
OLD | NEW |