Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Unified Diff: net/base/x509_certificate_nss.cc

Issue 8566056: This applies GUIDs to certificate and key nicknames when (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: minor fixes Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/base/x509_certificate_nss.cc
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc
index bbb5cef4b656bb88cfcb4bab30323010296f5545..d75e48110dddadab57fcde00341c26de0b907f2c 100644
--- a/net/base/x509_certificate_nss.cc
+++ b/net/base/x509_certificate_nss.cc
@@ -6,6 +6,7 @@
#include <cert.h>
#include <cryptohi.h>
+#include <keyhi.h>
#include <nss.h>
#include <pk11pub.h>
#include <prerror.h>
@@ -24,10 +25,14 @@
#include "net/base/asn1_util.h"
#include "net/base/cert_status_flags.h"
#include "net/base/cert_verify_result.h"
+#include "net/base/cert_type.h"
#include "net/base/crl_set.h"
#include "net/base/ev_root_ca_metadata.h"
#include "net/base/net_errors.h"
#include "net/base/x509_util_nss.h"
+#include "net/third_party/mozilla_security_manager/nsNSSCertTrust.h"
+
+namespace msm = mozilla_security_manager;
namespace net {
@@ -667,6 +672,55 @@ void AppendPublicKeyHashes(CERTCertList* cert_list,
hashes->push_back(CertPublicKeyHash(root_cert));
}
+bool SetPKCS11Nicknames(CERTCertificate* cert_handle,
+ const std::string& label) {
+ DCHECK(cert_handle);
+
+ // If the slot isn't initialized, then do nothing.
+ if (!cert_handle->slot)
+ return true;
+
+ // 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 the key's nickname
+ // to the given label.
Ryan Sleevi 2011/11/22 00:59:03 Rather than having to extract and encode the DER f
Greg Spencer (Chromium) 2011/11/29 00:21:49 That's a great idea, except that there's no way to
+ SECKEYPublicKey* public_key = CERT_ExtractPublicKey(cert_handle);
+ if (!public_key)
+ return false;
+
+ SECKEYPublicKeyList* pubkey_list =
+ PK11_ListPublicKeysInSlot(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_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_handle->slot, cert_handle, NULL);
+ if (private_key) {
+ PK11_SetPrivateKeyNickname(private_key, label.c_str());
+ SECKEY_DestroyPrivateKey(private_key);
+ }
+ return true;
+}
+
} // namespace
void X509Certificate::Initialize() {
@@ -707,6 +761,79 @@ X509Certificate* X509Certificate::CreateSelfSigned(
return x509_cert;
}
+bool X509Certificate::SetLabel(const std::string& label) {
+ if (!SetPKCS11Nicknames(cert_handle_, label))
+ return false;
+
+ // Now set the cert's nickname pointer.
+ char* nickname = reinterpret_cast<char*>(
+ PORT_ArenaAlloc(cert_handle_->arena, label.size() + 1));
+ if (!nickname)
+ return false;
+ PORT_Strcpy(nickname, label.c_str());
+ if (cert_handle_->nickname)
+ PORT_ArenaRelease(cert_handle_->arena, cert_handle_->nickname);
+ cert_handle_->nickname = nickname;
+ return true;
+}
+
+std::string X509Certificate::GetLabel() {
+ std::string result;
+ if (cert_handle_->nickname) {
+ // If the cert already has a nickname set, we use that.
+ result = std::string(cert_handle_->nickname);
+ } else {
+ switch(GetCertificateType()) {
+ case CA_CERT: {
+ char *nickname = CERT_MakeCANickname(cert_handle_);
+ result = nickname;
+ PORT_Free(nickname);
+ break;
+ }
+ case USER_CERT: {
+ // Create a nickname for this user certificate.
+ // We use the scheme used by Firefox:
+ // --> <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_handle_->subject);
+ char* temp_ca_name = CERT_GetCommonName(&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 = subject().GetDisplayName();
+ break;
+ }
+ case UNKNOWN_CERT:
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
+CertType X509Certificate::GetCertificateType() const {
+ msm::nsNSSCertTrust trust(cert_handle_->trust);
+ if (trust.HasAnyUser())
+ return USER_CERT;
+ if (trust.HasAnyCA() || CERT_IsCACert(cert_handle_, NULL))
+ return CA_CERT;
+ if (trust.HasPeer(PR_TRUE, PR_FALSE, PR_FALSE))
+ return SERVER_CERT;
+ return UNKNOWN_CERT;
+}
+
void X509Certificate::GetSubjectAltName(
std::vector<std::string>* dns_names,
std::vector<std::string>* ip_addrs) const {
@@ -922,6 +1049,13 @@ bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
// static
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
const char* data, int length) {
+ return CreateOSCertHandleFromBytesWithNickname(data, length, NULL);
+}
+
+// static
+X509Certificate::OSCertHandle
+X509Certificate::CreateOSCertHandleFromBytesWithNickname(
+ const char* data, int length, const char* nickname) {
if (length < 0)
return NULL;
@@ -936,8 +1070,22 @@ X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
der_cert.type = siDERCertBuffer;
// Parse into a certificate structure.
- return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL,
- PR_FALSE, PR_TRUE);
+ X509Certificate::OSCertHandle result =
+ CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert,
+ const_cast<char*>(nickname),
+ PR_FALSE, PR_TRUE);
+
+ // CERT_NewTempCertificate doesn't always fill in the nickname,
+ // so we have to.
+ if (result->nickname)
+ PORT_ArenaRelease(result->arena, result->nickname);
+ int len = strlen(nickname);
Ryan Sleevi 2011/11/22 00:59:03 Since |nickname| is optional (see line 1052), I be
Greg Spencer (Chromium) 2011/11/29 00:21:49 Good catch. Fixed.
+ char *arena_nickname = reinterpret_cast<char*>(
+ PORT_ArenaAlloc(result->arena, len + 1));
+ PORT_Strncpy(arena_nickname, nickname, len);
+ result->nickname = arena_nickname;
+
+ return result;
}
// static

Powered by Google App Engine
This is Rietveld 408576698