| 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 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/pickle.h" | 8 #include "base/pickle.h" |
| 9 #include "base/string_tokenizer.h" | 9 #include "base/string_tokenizer.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "net/base/cert_status_flags.h" | 11 #include "net/base/cert_status_flags.h" |
| 12 #include "net/base/cert_verify_result.h" | 12 #include "net/base/cert_verify_result.h" |
| 13 #include "net/base/ev_root_ca_metadata.h" | 13 #include "net/base/ev_root_ca_metadata.h" |
| 14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 15 #include "net/base/scoped_cert_chain_context.h" | 15 #include "net/base/scoped_cert_chain_context.h" |
| 16 | 16 |
| 17 #pragma comment(lib, "crypt32.lib") | 17 #pragma comment(lib, "crypt32.lib") |
| 18 | 18 |
| 19 using base::Time; | 19 using base::Time; |
| 20 | 20 |
| 21 namespace net { | 21 namespace net { |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 // Problematic certificates. | |
| 26 const X509Certificate::Fingerprint cert_blacklist[] = { | |
| 27 // A certificate for www.paypal.com with a NULL byte in the common name. | |
| 28 // Validity period from 2009-02-24 to 2011-02-24. | |
| 29 // Subject CN=www.paypal.com\00ssl.secureconnection.cc | |
| 30 // From http://www.gossamer-threads.com/lists/fulldisc/full-disclosure/70363 | |
| 31 { 0x4c, 0x88, 0x9e, 0x28, 0xd7, 0x7a, 0x44, 0x1e, 0x13, 0xf2, | |
| 32 0x6a, 0xba, 0x1f, 0xe8, 0x1b, 0xd6, 0xab, 0x7b, 0xe8, 0xd7 } | |
| 33 }; | |
| 34 | |
| 35 //----------------------------------------------------------------------------- | 25 //----------------------------------------------------------------------------- |
| 36 | 26 |
| 37 // TODO(wtc): This is a copy of the MapSecurityError function in | 27 // TODO(wtc): This is a copy of the MapSecurityError function in |
| 38 // ssl_client_socket_win.cc. Another function that maps Windows error codes | 28 // ssl_client_socket_win.cc. Another function that maps Windows error codes |
| 39 // to our network error codes is WinInetUtil::OSErrorToNetError. We should | 29 // to our network error codes is WinInetUtil::OSErrorToNetError. We should |
| 40 // eliminate the code duplication. | 30 // eliminate the code duplication. |
| 41 int MapSecurityError(SECURITY_STATUS err) { | 31 int MapSecurityError(SECURITY_STATUS err) { |
| 42 // There are numerous security error codes, but these are the ones we thus | 32 // There are numerous security error codes, but these are the ones we thus |
| 43 // far find interesting. | 33 // far find interesting. |
| 44 switch (err) { | 34 switch (err) { |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 extension->Value.pbData, | 157 extension->Value.pbData, |
| 168 extension->Value.cbData, | 158 extension->Value.cbData, |
| 169 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, | 159 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, |
| 170 &decode_para, | 160 &decode_para, |
| 171 &alt_name_info, | 161 &alt_name_info, |
| 172 &alt_name_info_size); | 162 &alt_name_info_size); |
| 173 if (rv) | 163 if (rv) |
| 174 output->reset(alt_name_info); | 164 output->reset(alt_name_info); |
| 175 } | 165 } |
| 176 | 166 |
| 167 // Returns true if any common name in the certificate's Subject field contains |
| 168 // a NULL character. |
| 169 bool CertSubjectCommonNameHasNull(PCCERT_CONTEXT cert) { |
| 170 CRYPT_DECODE_PARA decode_para; |
| 171 decode_para.cbSize = sizeof(decode_para); |
| 172 decode_para.pfnAlloc = MyCryptAlloc; |
| 173 decode_para.pfnFree = MyCryptFree; |
| 174 CERT_NAME_INFO* name_info = NULL; |
| 175 DWORD name_info_size = 0; |
| 176 BOOL rv; |
| 177 rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, |
| 178 X509_NAME, |
| 179 cert->pCertInfo->Subject.pbData, |
| 180 cert->pCertInfo->Subject.cbData, |
| 181 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, |
| 182 &decode_para, |
| 183 &name_info, |
| 184 &name_info_size); |
| 185 if (rv) { |
| 186 scoped_ptr_malloc<CERT_NAME_INFO> scoped_name_info(name_info); |
| 187 |
| 188 // The Subject field may have multiple common names. According to the |
| 189 // "PKI Layer Cake" paper, CryptoAPI uses every common name in the |
| 190 // Subject field, so we inspect every common name. |
| 191 // |
| 192 // From RFC 5280: |
| 193 // X520CommonName ::= CHOICE { |
| 194 // teletexString TeletexString (SIZE (1..ub-common-name)), |
| 195 // printableString PrintableString (SIZE (1..ub-common-name)), |
| 196 // universalString UniversalString (SIZE (1..ub-common-name)), |
| 197 // utf8String UTF8String (SIZE (1..ub-common-name)), |
| 198 // bmpString BMPString (SIZE (1..ub-common-name)) } |
| 199 // |
| 200 // We also check IA5String and VisibleString. |
| 201 for (DWORD i = 0; i < name_info->cRDN; ++i) { |
| 202 PCERT_RDN rdn = &name_info->rgRDN[i]; |
| 203 for (DWORD j = 0; j < rdn->cRDNAttr; ++j) { |
| 204 PCERT_RDN_ATTR rdn_attr = &rdn->rgRDNAttr[j]; |
| 205 if (strcmp(rdn_attr->pszObjId, szOID_COMMON_NAME) == 0) { |
| 206 switch (rdn_attr->dwValueType) { |
| 207 // Array of 8-bit characters. |
| 208 case CERT_RDN_PRINTABLE_STRING: |
| 209 case CERT_RDN_TELETEX_STRING: |
| 210 case CERT_RDN_IA5_STRING: |
| 211 case CERT_RDN_VISIBLE_STRING: |
| 212 for (DWORD k = 0; k < rdn_attr->Value.cbData; ++k) { |
| 213 if (rdn_attr->Value.pbData[k] == '\0') |
| 214 return true; |
| 215 } |
| 216 break; |
| 217 // Array of 16-bit characters. |
| 218 case CERT_RDN_BMP_STRING: |
| 219 case CERT_RDN_UTF8_STRING: { |
| 220 DWORD num_wchars = rdn_attr->Value.cbData / 2; |
| 221 wchar_t* common_name = |
| 222 reinterpret_cast<wchar_t*>(rdn_attr->Value.pbData); |
| 223 for (DWORD k = 0; k < num_wchars; ++k) { |
| 224 if (common_name[k] == L'\0') |
| 225 return true; |
| 226 } |
| 227 break; |
| 228 } |
| 229 // Array of ints (32-bit). |
| 230 case CERT_RDN_UNIVERSAL_STRING: { |
| 231 DWORD num_ints = rdn_attr->Value.cbData / 4; |
| 232 int* common_name = |
| 233 reinterpret_cast<int*>(rdn_attr->Value.pbData); |
| 234 for (DWORD k = 0; k < num_ints; ++k) { |
| 235 if (common_name[k] == 0) |
| 236 return true; |
| 237 } |
| 238 break; |
| 239 } |
| 240 default: |
| 241 NOTREACHED(); |
| 242 break; |
| 243 } |
| 244 } |
| 245 } |
| 246 } |
| 247 } |
| 248 return false; |
| 249 } |
| 250 |
| 177 // Saves some information about the certificate chain chain_context in | 251 // Saves some information about the certificate chain chain_context in |
| 178 // *verify_result. The caller MUST initialize *verify_result before calling | 252 // *verify_result. The caller MUST initialize *verify_result before calling |
| 179 // this function. | 253 // this function. |
| 180 void GetCertChainInfo(PCCERT_CHAIN_CONTEXT chain_context, | 254 void GetCertChainInfo(PCCERT_CHAIN_CONTEXT chain_context, |
| 181 CertVerifyResult* verify_result) { | 255 CertVerifyResult* verify_result) { |
| 182 PCERT_SIMPLE_CHAIN first_chain = chain_context->rgpChain[0]; | 256 PCERT_SIMPLE_CHAIN first_chain = chain_context->rgpChain[0]; |
| 183 int num_elements = first_chain->cElement; | 257 int num_elements = first_chain->cElement; |
| 184 PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement; | 258 PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement; |
| 185 | 259 |
| 186 // Each chain starts with the end entity certificate (i = 0) and ends with | 260 // Each chain starts with the end entity certificate (i = 0) and ends with |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 482 chain_context->TrustStatus.dwErrorStatus); | 556 chain_context->TrustStatus.dwErrorStatus); |
| 483 | 557 |
| 484 // Treat certificates signed using broken signature algorithms as invalid. | 558 // Treat certificates signed using broken signature algorithms as invalid. |
| 485 if (verify_result->has_md4) | 559 if (verify_result->has_md4) |
| 486 verify_result->cert_status |= CERT_STATUS_INVALID; | 560 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 487 | 561 |
| 488 // Flag certificates signed using weak signature algorithms. | 562 // Flag certificates signed using weak signature algorithms. |
| 489 if (verify_result->has_md2) | 563 if (verify_result->has_md2) |
| 490 verify_result->cert_status |= CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; | 564 verify_result->cert_status |= CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; |
| 491 | 565 |
| 492 // Treat certificates on our blacklist as invalid. | 566 // Flag certificates that have a Subject common name with a NULL character. |
| 493 for (int i = 0; i < arraysize(cert_blacklist); ++i) { | 567 if (CertSubjectCommonNameHasNull(cert_handle_)) |
| 494 if (fingerprint_.Equals(cert_blacklist[i])) { | 568 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 495 verify_result->cert_status |= CERT_STATUS_INVALID; | |
| 496 break; | |
| 497 } | |
| 498 } | |
| 499 | 569 |
| 500 std::wstring wstr_hostname = ASCIIToWide(hostname); | 570 std::wstring wstr_hostname = ASCIIToWide(hostname); |
| 501 | 571 |
| 502 SSL_EXTRA_CERT_CHAIN_POLICY_PARA extra_policy_para; | 572 SSL_EXTRA_CERT_CHAIN_POLICY_PARA extra_policy_para; |
| 503 memset(&extra_policy_para, 0, sizeof(extra_policy_para)); | 573 memset(&extra_policy_para, 0, sizeof(extra_policy_para)); |
| 504 extra_policy_para.cbSize = sizeof(extra_policy_para); | 574 extra_policy_para.cbSize = sizeof(extra_policy_para); |
| 505 extra_policy_para.dwAuthType = AUTHTYPE_SERVER; | 575 extra_policy_para.dwAuthType = AUTHTYPE_SERVER; |
| 506 extra_policy_para.fdwChecks = 0; | 576 extra_policy_para.fdwChecks = 0; |
| 507 extra_policy_para.pwszServerName = | 577 extra_policy_para.pwszServerName = |
| 508 const_cast<wchar_t*>(wstr_hostname.c_str()); | 578 const_cast<wchar_t*>(wstr_hostname.c_str()); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 DWORD sha1_size = sizeof(sha1.data); | 739 DWORD sha1_size = sizeof(sha1.data); |
| 670 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, | 740 rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded, |
| 671 cert->cbCertEncoded, sha1.data, &sha1_size); | 741 cert->cbCertEncoded, sha1.data, &sha1_size); |
| 672 DCHECK(rv && sha1_size == sizeof(sha1.data)); | 742 DCHECK(rv && sha1_size == sizeof(sha1.data)); |
| 673 if (!rv) | 743 if (!rv) |
| 674 memset(sha1.data, 0, sizeof(sha1.data)); | 744 memset(sha1.data, 0, sizeof(sha1.data)); |
| 675 return sha1; | 745 return sha1; |
| 676 } | 746 } |
| 677 | 747 |
| 678 } // namespace net | 748 } // namespace net |
| OLD | NEW |