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

Side by Side Diff: net/base/x509_certificate_win.cc

Issue 261016: Detect NULL characters in certificate Subject common... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Add IA5String and VisibleString Created 11 years, 2 months 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698