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_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 Loading... | |
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, | |
wtc
2011/11/29 23:13:57
Please document this function.
Greg Spencer (Chromium)
2011/12/02 18:50:07
This function has been merged back into SetLabel.
| |
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. | |
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 Loading... | |
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()) { | |
wtc
2011/11/29 23:13:57
Nit: add a space after 'switch'.
IMPORTANT: in th
Greg Spencer (Chromium)
2011/12/02 18:50:07
True.
I've split this into two separate functions
| |
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(); | |
wtc
2011/11/29 23:13:57
Nit: we can just use the subject_ member when insi
Greg Spencer (Chromium)
2011/12/02 18:50:07
Good point, but in the new incarnation I had to ca
| |
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 Loading... | |
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 (if there is one). | |
1080 if (!nickname) | |
1081 return result; | |
1082 | |
1083 if (result->nickname) | |
1084 PORT_ArenaRelease(result->arena, result->nickname); | |
wtc
2011/11/29 23:13:57
BUG: the fact that result->nickname is allocated f
Greg Spencer (Chromium)
2011/12/02 18:50:07
OK, I've changed the way I do things here. I no l
| |
1085 int len = strlen(nickname); | |
1086 char *arena_nickname = reinterpret_cast<char*>( | |
1087 PORT_ArenaAlloc(result->arena, len + 1)); | |
1088 PORT_Strncpy(arena_nickname, nickname, len); | |
1089 result->nickname = arena_nickname; | |
wtc
2011/11/29 23:13:57
You can use the PORT_ArenaStrdup function.
Greg Spencer (Chromium)
2011/12/02 18:50:07
This code went away.
| |
1090 | |
1091 return result; | |
941 } | 1092 } |
942 | 1093 |
943 // static | 1094 // static |
944 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( | 1095 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( |
945 const char* data, int length, Format format) { | 1096 const char* data, int length, Format format) { |
946 OSCertHandles results; | 1097 OSCertHandles results; |
947 if (length < 0) | 1098 if (length < 0) |
948 return results; | 1099 return results; |
949 | 1100 |
950 crypto::EnsureNSSInit(); | 1101 crypto::EnsureNSSInit(); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1039 | 1190 |
1040 // static | 1191 // static |
1041 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, | 1192 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, |
1042 Pickle* pickle) { | 1193 Pickle* pickle) { |
1043 return pickle->WriteData( | 1194 return pickle->WriteData( |
1044 reinterpret_cast<const char*>(cert_handle->derCert.data), | 1195 reinterpret_cast<const char*>(cert_handle->derCert.data), |
1045 cert_handle->derCert.len); | 1196 cert_handle->derCert.len); |
1046 } | 1197 } |
1047 | 1198 |
1048 } // namespace net | 1199 } // namespace net |
OLD | NEW |