Chromium Code Reviews| Index: net/base/x509_util_nss.cc |
| diff --git a/net/base/x509_util_nss.cc b/net/base/x509_util_nss.cc |
| index fe3fb1731cb87297f228563892a69f6cbb8dc135..ed0927c0c0b09549a05ed0206a0dd2414f9515af 100644 |
| --- a/net/base/x509_util_nss.cc |
| +++ b/net/base/x509_util_nss.cc |
| @@ -20,6 +20,10 @@ |
| #include "crypto/nss_util_internal.h" |
| #include "crypto/rsa_private_key.h" |
| #include "crypto/scoped_nss_types.h" |
| +#include "net/base/x509_certificate.h" |
| +#include "net/third_party/mozilla_security_manager/nsNSSCertTrust.h" |
| + |
| +namespace msm = mozilla_security_manager; |
| namespace { |
| @@ -166,7 +170,6 @@ bool SignCertificate( |
| return true; |
| } |
| - |
|
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.
|
| } // namespace |
| namespace net { |
| @@ -313,6 +316,156 @@ bool CreateOriginBoundCert( |
| return true; |
| } |
| +CertType GetCertType(const X509Certificate* cert) { |
| + DCHECK(cert); |
| + msm::nsNSSCertTrust trust(cert->os_cert_handle()->trust); |
| + if (trust.HasAnyUser()) |
| + return USER_CERT; |
| + if (trust.HasAnyCA() || CERT_IsCACert(cert->os_cert_handle(), NULL)) |
| + return CA_CERT; |
| + if (trust.HasPeer(PR_TRUE, PR_FALSE, PR_FALSE)) |
| + return SERVER_CERT; |
| + return UNKNOWN_CERT; |
| +} |
| + |
| +std::string GetDefaultCertificateLabel(const X509Certificate* cert) { |
| + DCHECK(cert); |
| + std::string result; |
| + |
| +#if defined(OS_CHROMEOS) |
| + // When we have label support, we want to keep any existing label by default. |
| + result = GetLabel(cert); |
| + if (!result.empty()) |
| + return result; |
| +#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
|
| + |
| + switch (GetCertType(cert)) { |
| + case CA_CERT: { |
| + 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.
|
| + result = nickname; |
| + PORT_Free(nickname); |
| + break; |
| + } |
| + case USER_CERT: { |
| + // Create a nickname for this user certificate. |
| + // 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.
|
| + // --> <subject's common name>'s <issuer's common name> ID. |
| + // TODO(gspencer): internationalize this: it's wrong to |
| + // hard code English. |
| + |
| + std::string username, ca_name; |
| + char* temp_username = CERT_GetCommonName( |
| + &cert->os_cert_handle()->subject); |
| + char* temp_ca_name = CERT_GetCommonName(&cert->os_cert_handle()->issuer); |
| + if (temp_username) { |
| + username = temp_username; |
| + PORT_Free(temp_username); |
| + } |
| + if (temp_ca_name) { |
| + ca_name = temp_ca_name; |
| + PORT_Free(temp_ca_name); |
| + } |
| + result = username + "'s " + ca_name + " ID"; |
| + break; |
| + } |
| + case SERVER_CERT: { |
| + result = cert->subject().GetDisplayName(); |
| + break; |
| + } |
|
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.
|
| + case UNKNOWN_CERT: |
| + default: |
| + break; |
| + } |
| + return result; |
| +} |
| + |
| +#if defined(OS_CHROMEOS) |
| +bool SetLabel(X509Certificate* cert, const std::string& label) { |
| + DCHECK(cert); |
| + // If the slot isn't initialized, then do nothing. |
| + if (!cert->os_cert_handle()->slot) |
| + return true; |
| + |
| + // First we set the nickname on the cert itself. This doesn't |
| + // work on production NSS yet (it's not implemented), but ChromeOS |
| + // has a patched version that it will work on. |
| + SECItem sec_label; |
| + 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.
|
| + sec_label.data = reinterpret_cast<unsigned char*>( |
| + const_cast<char*>(label.c_str())); |
| + sec_label.len = label.size(); |
| + SECStatus srv = PK11_WriteRawAttribute(PK11_TypeCert, |
| + cert->os_cert_handle(), |
| + CKA_LABEL, |
| + &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
|
| + if (srv != SECSuccess) |
| + LOG(WARNING) << "Unable to set certificate label to " |
| + << 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.
|
| + |
| + // As far as I can tell, there is no API for PKCS11 that allows one |
| + // to get the valid public key (that has a valid PKCS11 slot and id) |
| + // associated with a certificate. So, instead, I extract the public |
| + // key using CERT_ExtractPublicKey (which returns a key that has no |
| + // slot or pkcs11 id set), and then we iterate through all of the |
| + // existing public keys (which do have this information), and look |
| + // for one that has the same DER encoding as the public key |
| + // extracted from this certificate. I then set that key's nickname |
| + // to the given label. |
| + SECKEYPublicKey* public_key = CERT_ExtractPublicKey(cert->os_cert_handle()); |
| + if (!public_key) |
| + return false; |
| + |
| + SECKEYPublicKeyList* pubkey_list = |
| + PK11_ListPublicKeysInSlot(cert->os_cert_handle()->slot, NULL); |
| + |
| + // If there are no public keys, that's OK. |
| + if (pubkey_list) { |
| + for (SECKEYPublicKeyListNode* node = PUBKEY_LIST_HEAD(pubkey_list); |
| + !PUBKEY_LIST_END(node, pubkey_list); |
| + node = PUBKEY_LIST_NEXT(node)) { |
| + SECItem* der_encoded = PK11_DEREncodePublicKey(node->key); |
| + if (SECITEM_CompareItem( |
| + der_encoded, |
| + &cert->os_cert_handle()->derPublicKey) == SECEqual) |
| + PK11_SetPublicKeyNickname(node->key, label.c_str()); |
| + SECITEM_FreeItem(der_encoded, PR_TRUE); |
| + } |
| + SECKEY_DestroyPublicKeyList(pubkey_list); |
| + } |
| + SECKEY_DestroyPublicKey(public_key); |
| + |
| + // Now set the nickname on the private key (if there is one) |
| + SECKEYPrivateKey* private_key = |
| + PK11_FindPrivateKeyFromCert(cert->os_cert_handle()->slot, |
| + cert->os_cert_handle(), |
| + NULL); |
| + if (private_key) { |
| + PK11_SetPrivateKeyNickname(private_key, label.c_str()); |
| + SECKEY_DestroyPrivateKey(private_key); |
| + } |
| + return true; |
| +} |
| + |
| +std::string GetLabel(const X509Certificate* cert) { |
| + std::string result; |
| + // This doesn't work on production NSS yet (it's not implemented), but |
| + // ChromeOS has a patched version that it will work on. |
| + SECItem sec_label; |
| + SECStatus srv = PK11_ReadRawAttribute(PK11_TypeCert, |
| + cert->os_cert_handle(), |
| + CKA_LABEL, |
| + &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
|
| + if (srv != SECSuccess) { |
| + return result; |
| + } |
| + |
| + result = std::string(reinterpret_cast<char *>(sec_label.data), sec_label.len); |
| + PORT_Free(sec_label.data); |
| + return result; |
| +} |
| +#endif // OS_CHROMEOS |
| + |
| + |
| } // namespace x509_util |
| } // namespace net |