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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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_certificate.h" 5 #include "net/base/x509_certificate.h"
6 6
7 #include <cert.h> 7 #include <cert.h>
8 #include <cryptohi.h> 8 #include <cryptohi.h>
9 #include <keyhi.h>
9 #include <nss.h> 10 #include <nss.h>
10 #include <pk11pub.h> 11 #include <pk11pub.h>
11 #include <prerror.h> 12 #include <prerror.h>
12 #include <prtime.h> 13 #include <prtime.h>
13 #include <secder.h> 14 #include <secder.h>
14 #include <secerr.h> 15 #include <secerr.h>
15 #include <sechash.h> 16 #include <sechash.h>
16 #include <sslerr.h> 17 #include <sslerr.h>
17 18
18 #include "base/logging.h" 19 #include "base/logging.h"
19 #include "base/memory/scoped_ptr.h" 20 #include "base/memory/scoped_ptr.h"
20 #include "base/pickle.h" 21 #include "base/pickle.h"
21 #include "base/time.h" 22 #include "base/time.h"
22 #include "crypto/nss_util.h" 23 #include "crypto/nss_util.h"
23 #include "crypto/rsa_private_key.h" 24 #include "crypto/rsa_private_key.h"
24 #include "net/base/asn1_util.h" 25 #include "net/base/asn1_util.h"
25 #include "net/base/cert_status_flags.h" 26 #include "net/base/cert_status_flags.h"
26 #include "net/base/cert_verify_result.h" 27 #include "net/base/cert_verify_result.h"
28 #include "net/base/cert_type.h"
27 #include "net/base/crl_set.h" 29 #include "net/base/crl_set.h"
28 #include "net/base/ev_root_ca_metadata.h" 30 #include "net/base/ev_root_ca_metadata.h"
29 #include "net/base/net_errors.h" 31 #include "net/base/net_errors.h"
30 #include "net/base/x509_util_nss.h" 32 #include "net/base/x509_util_nss.h"
33 #include "net/third_party/mozilla_security_manager/nsNSSCertTrust.h"
34
35 namespace msm = mozilla_security_manager;
31 36
32 namespace net { 37 namespace net {
33 38
34 namespace { 39 namespace {
35 40
36 class ScopedCERTCertificatePolicies { 41 class ScopedCERTCertificatePolicies {
37 public: 42 public:
38 explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies) 43 explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies)
39 : policies_(policies) {} 44 : policies_(policies) {}
40 45
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 CERTCertificate* root_cert, 665 CERTCertificate* root_cert,
661 std::vector<SHA1Fingerprint>* hashes) { 666 std::vector<SHA1Fingerprint>* hashes) {
662 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); 667 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
663 !CERT_LIST_END(node, cert_list); 668 !CERT_LIST_END(node, cert_list);
664 node = CERT_LIST_NEXT(node)) { 669 node = CERT_LIST_NEXT(node)) {
665 hashes->push_back(CertPublicKeyHash(node->cert)); 670 hashes->push_back(CertPublicKeyHash(node->cert));
666 } 671 }
667 hashes->push_back(CertPublicKeyHash(root_cert)); 672 hashes->push_back(CertPublicKeyHash(root_cert));
668 } 673 }
669 674
675 bool SetPKCS11Nicknames(CERTCertificate* cert_handle,
676 const std::string& label) {
677 DCHECK(cert_handle);
678
679 // If the slot isn't initialized, then do nothing.
680 if (!cert_handle->slot)
681 return true;
682
683 // As far as I can tell, there is no API for PKCS11 that allows one
684 // to get the valid public key (that has a valid PKCS11 slot and id)
685 // associated with a certificate. So, instead, I extract the public
686 // key using CERT_ExtractPublicKey (which returns a key that has no
687 // slot or pkcs11 id set), and then we iterate through all of the
688 // existing public keys (which do have this information), and look
689 // for one that has the same DER encoding as the public key
690 // extracted from this certificate. I then set the key's nickname
691 // 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
692 SECKEYPublicKey* public_key = CERT_ExtractPublicKey(cert_handle);
693 if (!public_key)
694 return false;
695
696 SECKEYPublicKeyList* pubkey_list =
697 PK11_ListPublicKeysInSlot(cert_handle->slot, NULL);
698
699 // If there are no public keys, that's OK.
700 if (pubkey_list) {
701 for (SECKEYPublicKeyListNode* node = PUBKEY_LIST_HEAD(pubkey_list);
702 !PUBKEY_LIST_END(node, pubkey_list);
703 node = PUBKEY_LIST_NEXT(node)) {
704 SECItem* der_encoded = PK11_DEREncodePublicKey(node->key);
705 if (SECITEM_CompareItem(der_encoded,
706 &cert_handle->derPublicKey) == SECEqual)
707 PK11_SetPublicKeyNickname(node->key, label.c_str());
708 SECITEM_FreeItem(der_encoded, PR_TRUE);
709 }
710 SECKEY_DestroyPublicKeyList(pubkey_list);
711 }
712 SECKEY_DestroyPublicKey(public_key);
713
714 // Now set the nickname on the private key (if there is one)
715 SECKEYPrivateKey* private_key =
716 PK11_FindPrivateKeyFromCert(cert_handle->slot, cert_handle, NULL);
717 if (private_key) {
718 PK11_SetPrivateKeyNickname(private_key, label.c_str());
719 SECKEY_DestroyPrivateKey(private_key);
720 }
721 return true;
722 }
723
670 } // namespace 724 } // namespace
671 725
672 void X509Certificate::Initialize() { 726 void X509Certificate::Initialize() {
673 ParsePrincipal(&cert_handle_->subject, &subject_); 727 ParsePrincipal(&cert_handle_->subject, &subject_);
674 ParsePrincipal(&cert_handle_->issuer, &issuer_); 728 ParsePrincipal(&cert_handle_->issuer, &issuer_);
675 729
676 ParseDate(&cert_handle_->validity.notBefore, &valid_start_); 730 ParseDate(&cert_handle_->validity.notBefore, &valid_start_);
677 ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_); 731 ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_);
678 732
679 fingerprint_ = CalculateFingerprint(cert_handle_); 733 fingerprint_ = CalculateFingerprint(cert_handle_);
(...skipping 20 matching lines...) Expand all
700 754
701 if (!cert) 755 if (!cert)
702 return NULL; 756 return NULL;
703 757
704 X509Certificate* x509_cert = X509Certificate::CreateFromHandle( 758 X509Certificate* x509_cert = X509Certificate::CreateFromHandle(
705 cert, X509Certificate::OSCertHandles()); 759 cert, X509Certificate::OSCertHandles());
706 CERT_DestroyCertificate(cert); 760 CERT_DestroyCertificate(cert);
707 return x509_cert; 761 return x509_cert;
708 } 762 }
709 763
764 bool X509Certificate::SetLabel(const std::string& label) {
765 if (!SetPKCS11Nicknames(cert_handle_, label))
766 return false;
767
768 // Now set the cert's nickname pointer.
769 char* nickname = reinterpret_cast<char*>(
770 PORT_ArenaAlloc(cert_handle_->arena, label.size() + 1));
771 if (!nickname)
772 return false;
773 PORT_Strcpy(nickname, label.c_str());
774 if (cert_handle_->nickname)
775 PORT_ArenaRelease(cert_handle_->arena, cert_handle_->nickname);
776 cert_handle_->nickname = nickname;
777 return true;
778 }
779
780 std::string X509Certificate::GetLabel() {
781 std::string result;
782 if (cert_handle_->nickname) {
783 // If the cert already has a nickname set, we use that.
784 result = std::string(cert_handle_->nickname);
785 } else {
786 switch(GetCertificateType()) {
787 case CA_CERT: {
788 char *nickname = CERT_MakeCANickname(cert_handle_);
789 result = nickname;
790 PORT_Free(nickname);
791 break;
792 }
793 case USER_CERT: {
794 // Create a nickname for this user certificate.
795 // We use the scheme used by Firefox:
796 // --> <subject's common name>'s <issuer's common name> ID.
797 // TODO(gspencer): internationalize this: it's wrong to
798 // hard code English.
799
800 std::string username, ca_name;
801 char* temp_username = CERT_GetCommonName(&cert_handle_->subject);
802 char* temp_ca_name = CERT_GetCommonName(&cert_handle_->issuer);
803 if (temp_username) {
804 username = temp_username;
805 PORT_Free(temp_username);
806 }
807 if (temp_ca_name) {
808 ca_name = temp_ca_name;
809 PORT_Free(temp_ca_name);
810 }
811 result = username + "'s " + ca_name + " ID";
812 break;
813 }
814 case SERVER_CERT: {
815 result = subject().GetDisplayName();
816 break;
817 }
818 case UNKNOWN_CERT:
819 default:
820 break;
821 }
822 }
823 return result;
824 }
825
826 CertType X509Certificate::GetCertificateType() const {
827 msm::nsNSSCertTrust trust(cert_handle_->trust);
828 if (trust.HasAnyUser())
829 return USER_CERT;
830 if (trust.HasAnyCA() || CERT_IsCACert(cert_handle_, NULL))
831 return CA_CERT;
832 if (trust.HasPeer(PR_TRUE, PR_FALSE, PR_FALSE))
833 return SERVER_CERT;
834 return UNKNOWN_CERT;
835 }
836
710 void X509Certificate::GetSubjectAltName( 837 void X509Certificate::GetSubjectAltName(
711 std::vector<std::string>* dns_names, 838 std::vector<std::string>* dns_names,
712 std::vector<std::string>* ip_addrs) const { 839 std::vector<std::string>* ip_addrs) const {
713 if (dns_names) 840 if (dns_names)
714 dns_names->clear(); 841 dns_names->clear();
715 if (ip_addrs) 842 if (ip_addrs)
716 ip_addrs->clear(); 843 ip_addrs->clear();
717 844
718 SECItem alt_name; 845 SECItem alt_name;
719 SECStatus rv = CERT_FindCertExtension(cert_handle_, 846 SECStatus rv = CERT_FindCertExtension(cert_handle_,
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
915 DCHECK(a && b); 1042 DCHECK(a && b);
916 if (a == b) 1043 if (a == b)
917 return true; 1044 return true;
918 return a->derCert.len == b->derCert.len && 1045 return a->derCert.len == b->derCert.len &&
919 memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0; 1046 memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0;
920 } 1047 }
921 1048
922 // static 1049 // static
923 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( 1050 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
924 const char* data, int length) { 1051 const char* data, int length) {
1052 return CreateOSCertHandleFromBytesWithNickname(data, length, NULL);
1053 }
1054
1055 // static
1056 X509Certificate::OSCertHandle
1057 X509Certificate::CreateOSCertHandleFromBytesWithNickname(
1058 const char* data, int length, const char* nickname) {
925 if (length < 0) 1059 if (length < 0)
926 return NULL; 1060 return NULL;
927 1061
928 crypto::EnsureNSSInit(); 1062 crypto::EnsureNSSInit();
929 1063
930 if (!NSS_IsInitialized()) 1064 if (!NSS_IsInitialized())
931 return NULL; 1065 return NULL;
932 1066
933 SECItem der_cert; 1067 SECItem der_cert;
934 der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data)); 1068 der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
935 der_cert.len = length; 1069 der_cert.len = length;
936 der_cert.type = siDERCertBuffer; 1070 der_cert.type = siDERCertBuffer;
937 1071
938 // Parse into a certificate structure. 1072 // Parse into a certificate structure.
939 return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL, 1073 X509Certificate::OSCertHandle result =
940 PR_FALSE, PR_TRUE); 1074 CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert,
1075 const_cast<char*>(nickname),
1076 PR_FALSE, PR_TRUE);
1077
1078 // CERT_NewTempCertificate doesn't always fill in the nickname,
1079 // so we have to.
1080 if (result->nickname)
1081 PORT_ArenaRelease(result->arena, result->nickname);
1082 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.
1083 char *arena_nickname = reinterpret_cast<char*>(
1084 PORT_ArenaAlloc(result->arena, len + 1));
1085 PORT_Strncpy(arena_nickname, nickname, len);
1086 result->nickname = arena_nickname;
1087
1088 return result;
941 } 1089 }
942 1090
943 // static 1091 // static
944 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( 1092 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
945 const char* data, int length, Format format) { 1093 const char* data, int length, Format format) {
946 OSCertHandles results; 1094 OSCertHandles results;
947 if (length < 0) 1095 if (length < 0)
948 return results; 1096 return results;
949 1097
950 crypto::EnsureNSSInit(); 1098 crypto::EnsureNSSInit();
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
1039 1187
1040 // static 1188 // static
1041 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, 1189 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
1042 Pickle* pickle) { 1190 Pickle* pickle) {
1043 return pickle->WriteData( 1191 return pickle->WriteData(
1044 reinterpret_cast<const char*>(cert_handle->derCert.data), 1192 reinterpret_cast<const char*>(cert_handle->derCert.data),
1045 cert_handle->derCert.len); 1193 cert_handle->derCert.len);
1046 } 1194 }
1047 1195
1048 } // namespace net 1196 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698