| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 | 7 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 |
| 8 // until NSS 3.12.2 comes out and we update to it. | 8 // until NSS 3.12.2 comes out and we update to it. |
| 9 #define Lock FOO_NSS_Lock | 9 #define Lock FOO_NSS_Lock |
| 10 #include <cert.h> | 10 #include <cert.h> |
| 11 #include <prtime.h> | 11 #include <prtime.h> |
| 12 #include <secder.h> | 12 #include <secder.h> |
| 13 #include <sechash.h> | 13 #include <sechash.h> |
| 14 #undef Lock | 14 #undef Lock |
| 15 | 15 |
| 16 #include "base/histogram.h" | |
| 17 #include "base/logging.h" | 16 #include "base/logging.h" |
| 18 #include "base/time.h" | 17 #include "base/time.h" |
| 19 #include "base/nss_init.h" | 18 #include "base/nss_init.h" |
| 20 | 19 |
| 21 namespace net { | 20 namespace net { |
| 22 | 21 |
| 23 // Calculates the SHA-1 fingerprint of the certificate. Returns an empty | |
| 24 // (all zero) fingerprint on failure. | |
| 25 X509Certificate::Fingerprint CalculateFingerprint( | |
| 26 X509Certificate::OSCertHandle cert) { | |
| 27 X509Certificate::Fingerprint sha1; | |
| 28 memset(sha1.data, 0, sizeof(sha1.data)); | |
| 29 | |
| 30 DCHECK(NULL != cert->derCert.data); | |
| 31 DCHECK(0 != cert->derCert.len); | |
| 32 | |
| 33 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, | |
| 34 cert->derCert.data, cert->derCert.len); | |
| 35 DCHECK(rv == SECSuccess); | |
| 36 | |
| 37 return sha1; | |
| 38 } | |
| 39 | |
| 40 namespace { | 22 namespace { |
| 41 | 23 |
| 42 // TODO(port): Implement this more simply, and put it in the right place | 24 // TODO(port): Implement this more simply, and put it in the right place |
| 43 base::Time PRTimeToBaseTime(PRTime prtime) { | 25 base::Time PRTimeToBaseTime(PRTime prtime) { |
| 44 PRExplodedTime prxtime; | 26 PRExplodedTime prxtime; |
| 45 PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); | 27 PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); |
| 46 | 28 |
| 47 base::Time::Exploded exploded; | 29 base::Time::Exploded exploded; |
| 48 exploded.year = prxtime.tm_year; | 30 exploded.year = prxtime.tm_year; |
| 49 exploded.month = prxtime.tm_month + 1; | 31 exploded.month = prxtime.tm_month + 1; |
| 50 exploded.day_of_week = prxtime.tm_wday; | 32 exploded.day_of_week = prxtime.tm_wday; |
| 51 exploded.day_of_month = prxtime.tm_mday; | 33 exploded.day_of_month = prxtime.tm_mday; |
| 52 exploded.hour = prxtime.tm_hour; | 34 exploded.hour = prxtime.tm_hour; |
| 53 exploded.minute = prxtime.tm_min; | 35 exploded.minute = prxtime.tm_min; |
| 54 exploded.second = prxtime.tm_sec; | 36 exploded.second = prxtime.tm_sec; |
| 55 exploded.millisecond = prxtime.tm_usec / 1000; | 37 exploded.millisecond = prxtime.tm_usec / 1000; |
| 56 | 38 |
| 57 return base::Time::FromUTCExploded(exploded); | 39 return base::Time::FromUTCExploded(exploded); |
| 58 } | 40 } |
| 59 | 41 |
| 60 void ParsePrincipal(SECItem *der_name, | 42 void ParsePrincipal(SECItem* der_name, |
| 61 X509Certificate::Principal* principal) { | 43 X509Certificate::Principal* principal) { |
| 62 | 44 |
| 63 CERTName name; | 45 CERTName name; |
| 64 PRArenaPool *arena = NULL; | 46 PRArenaPool* arena = NULL; |
| 65 | 47 |
| 66 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | 48 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
| 67 DCHECK(arena != NULL); | 49 DCHECK(arena != NULL); |
| 68 if (arena == NULL) | 50 if (arena == NULL) |
| 69 return; | 51 return; |
| 70 | 52 |
| 71 // TODO(dkegel): is CERT_NameTemplate what we always want here? | 53 // TODO(dkegel): is CERT_NameTemplate what we always want here? |
| 72 SECStatus rv; | 54 SECStatus rv; |
| 73 rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, der_name); | 55 rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, der_name); |
| 74 DCHECK(rv == SECSuccess); | 56 DCHECK(rv == SECSuccess); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 103 CERTRDN** rdns = name.rdns; | 85 CERTRDN** rdns = name.rdns; |
| 104 for (size_t rdn = 0; rdns[rdn]; ++rdn) { | 86 for (size_t rdn = 0; rdns[rdn]; ++rdn) { |
| 105 CERTAVA** avas = rdns[rdn]->avas; | 87 CERTAVA** avas = rdns[rdn]->avas; |
| 106 for (size_t pair = 0; avas[pair] != 0; ++pair) { | 88 for (size_t pair = 0; avas[pair] != 0; ++pair) { |
| 107 SECOidTag tag = CERT_GetAVATag(avas[pair]); | 89 SECOidTag tag = CERT_GetAVATag(avas[pair]); |
| 108 for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { | 90 for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { |
| 109 if (kOIDs[oid] == tag) { | 91 if (kOIDs[oid] == tag) { |
| 110 SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); | 92 SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); |
| 111 if (!decode_item) | 93 if (!decode_item) |
| 112 break; | 94 break; |
| 113 std::string value(reinterpret_cast<char *>(decode_item->data), | 95 std::string value(reinterpret_cast<char*>(decode_item->data), |
| 114 decode_item->len); | 96 decode_item->len); |
| 115 values[oid]->push_back(value); | 97 values[oid]->push_back(value); |
| 116 SECITEM_FreeItem(decode_item, PR_TRUE); | 98 SECITEM_FreeItem(decode_item, PR_TRUE); |
| 117 break; | 99 break; |
| 118 } | 100 } |
| 119 } | 101 } |
| 120 } | 102 } |
| 121 } | 103 } |
| 122 | 104 |
| 123 // We don't expect to have more than one CN, L, S, and C. | 105 // We don't expect to have more than one CN, L, S, and C. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 alt_name_list = CERT_DecodeAltNameExtension(arena, &alt_name); | 140 alt_name_list = CERT_DecodeAltNameExtension(arena, &alt_name); |
| 159 | 141 |
| 160 CERTGeneralName* name = alt_name_list; | 142 CERTGeneralName* name = alt_name_list; |
| 161 while (name) { | 143 while (name) { |
| 162 // For future extension: We're assuming that these values are of types | 144 // For future extension: We're assuming that these values are of types |
| 163 // RFC822Name, DNSName or URI. See the mac code for notes. | 145 // RFC822Name, DNSName or URI. See the mac code for notes. |
| 164 DCHECK(name->type == certRFC822Name || | 146 DCHECK(name->type == certRFC822Name || |
| 165 name->type == certDNSName || | 147 name->type == certDNSName || |
| 166 name->type == certURI); | 148 name->type == certURI); |
| 167 if (name->type == name_type) { | 149 if (name->type == name_type) { |
| 168 unsigned char *p = name->name.other.data; | 150 unsigned char* p = name->name.other.data; |
| 169 int len = name->name.other.len; | 151 int len = name->name.other.len; |
| 170 std::string value = std::string(reinterpret_cast<char *>(p), len); | 152 std::string value = std::string(reinterpret_cast<char*>(p), len); |
| 171 result->push_back(value); | 153 result->push_back(value); |
| 172 } | 154 } |
| 173 name = CERT_GetNextGeneralName(name); | 155 name = CERT_GetNextGeneralName(name); |
| 174 if (name == alt_name_list) | 156 if (name == alt_name_list) |
| 175 break; | 157 break; |
| 176 } | 158 } |
| 177 PORT_FreeArena(arena, PR_FALSE); | 159 PORT_FreeArena(arena, PR_FALSE); |
| 178 } | 160 } |
| 179 | 161 |
| 180 } // namespace | 162 } // namespace |
| 181 | 163 |
| 182 void X509Certificate::Initialize() { | 164 void X509Certificate::Initialize() { |
| 183 ParsePrincipal(&cert_handle_->derSubject, &subject_); | 165 ParsePrincipal(&cert_handle_->derSubject, &subject_); |
| 184 ParsePrincipal(&cert_handle_->derIssuer, &issuer_); | 166 ParsePrincipal(&cert_handle_->derIssuer, &issuer_); |
| 185 | 167 |
| 186 ParseDate(&cert_handle_->validity.notBefore, &valid_start_); | 168 ParseDate(&cert_handle_->validity.notBefore, &valid_start_); |
| 187 ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_); | 169 ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_); |
| 188 | 170 |
| 189 fingerprint_ = CalculateFingerprint(cert_handle_); | 171 fingerprint_ = CalculateFingerprint(cert_handle_); |
| 190 | 172 |
| 191 // Store the certificate in the cache in case we need it later. | 173 // Store the certificate in the cache in case we need it later. |
| 192 X509Certificate::Cache::GetInstance()->Insert(this); | 174 X509Certificate::Cache::GetInstance()->Insert(this); |
| 193 } | 175 } |
| 194 | 176 |
| 195 // static | 177 // static |
| 196 X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) { | |
| 197 DCHECK(cert_handle); | |
| 198 | |
| 199 // Check if we already have this certificate in memory. | |
| 200 X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); | |
| 201 X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle)); | |
| 202 if (cert) { | |
| 203 // We've found a certificate with the same fingerprint in our cache. We own | |
| 204 // the |cert_handle|, which makes it our job to free it. | |
| 205 CERT_DestroyCertificate(cert_handle); | |
| 206 DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); | |
| 207 return cert; | |
| 208 } | |
| 209 // Otherwise, allocate a new object. | |
| 210 return new X509Certificate(cert_handle); | |
| 211 } | |
| 212 | |
| 213 // static | |
| 214 X509Certificate* X509Certificate::CreateFromBytes(const char* data, | |
| 215 int length) { | |
| 216 base::EnsureNSSInit(); | |
| 217 | |
| 218 SECItem der_cert; | |
| 219 der_cert.data = reinterpret_cast<unsigned char *>(const_cast<char *>(data)); | |
| 220 der_cert.len = length; | |
| 221 OSCertHandle cert_handle = | |
| 222 CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, | |
| 223 NULL, PR_FALSE, PR_TRUE); | |
| 224 if (!cert_handle) | |
| 225 return NULL; | |
| 226 | |
| 227 return CreateFromHandle(cert_handle); | |
| 228 } | |
| 229 | |
| 230 // static | |
| 231 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, | 178 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, |
| 232 void** pickle_iter) { | 179 void** pickle_iter) { |
| 233 NOTIMPLEMENTED(); | 180 NOTIMPLEMENTED(); |
| 234 return NULL; | 181 return NULL; |
| 235 } | 182 } |
| 236 | 183 |
| 237 X509Certificate::X509Certificate(OSCertHandle cert_handle) | |
| 238 : cert_handle_(cert_handle) { | |
| 239 Initialize(); | |
| 240 } | |
| 241 | |
| 242 void X509Certificate::Persist(Pickle* pickle) { | 184 void X509Certificate::Persist(Pickle* pickle) { |
| 243 NOTIMPLEMENTED(); | 185 NOTIMPLEMENTED(); |
| 244 } | 186 } |
| 245 | 187 |
| 246 X509Certificate::~X509Certificate() { | |
| 247 // We might not be in the cache, but it is safe to remove ourselves anyway. | |
| 248 X509Certificate::Cache::GetInstance()->Remove(this); | |
| 249 if (cert_handle_) | |
| 250 CERT_DestroyCertificate(cert_handle_); | |
| 251 } | |
| 252 | |
| 253 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { | 188 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { |
| 254 dns_names->clear(); | 189 dns_names->clear(); |
| 255 | 190 |
| 256 // Compare with CERT_VerifyCertName(). | 191 // Compare with CERT_VerifyCertName(). |
| 257 GetCertSubjectAltNamesOfType(cert_handle_, certDNSName, dns_names); | 192 GetCertSubjectAltNamesOfType(cert_handle_, certDNSName, dns_names); |
| 258 | 193 |
| 259 // TODO(port): suppress nss's support of the obsolete extension | 194 // TODO(port): suppress nss's support of the obsolete extension |
| 260 // SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME | 195 // SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME |
| 261 // by providing our own authCertificate callback. | 196 // by providing our own authCertificate callback. |
| 262 | 197 |
| 263 if (dns_names->empty()) | 198 if (dns_names->empty()) |
| 264 dns_names->push_back(subject_.common_name); | 199 dns_names->push_back(subject_.common_name); |
| 265 } | 200 } |
| 201 |
| 202 // static |
| 203 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( |
| 204 const char* data, int length) { |
| 205 base::EnsureNSSInit(); |
| 206 |
| 207 SECItem der_cert; |
| 208 der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data)); |
| 209 der_cert.len = length; |
| 210 return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, |
| 211 NULL, PR_FALSE, PR_TRUE); |
| 212 } |
| 213 |
| 214 // static |
| 215 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { |
| 216 CERT_DestroyCertificate(cert_handle); |
| 217 } |
| 218 |
| 219 // static |
| 220 X509Certificate::Fingerprint X509Certificate::CalculateFingerprint( |
| 221 OSCertHandle cert) { |
| 222 Fingerprint sha1; |
| 223 memset(sha1.data, 0, sizeof(sha1.data)); |
| 224 |
| 225 DCHECK(NULL != cert->derCert.data); |
| 226 DCHECK(0 != cert->derCert.len); |
| 227 |
| 228 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, |
| 229 cert->derCert.data, cert->derCert.len); |
| 230 DCHECK(rv == SECSuccess); |
| 231 |
| 232 return sha1; |
| 233 } |
| 266 | 234 |
| 267 } // namespace net | 235 } // namespace net |
| 268 | 236 |
| OLD | NEW |