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 |