Chromium Code Reviews| 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 |