summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-19 17:29:06 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-19 17:29:06 +0000
commit23f98b5d5729c3256eb2a1466c1e9cd12a999cc1 (patch)
tree2aa4532ffed5d3423702099629a607a1d1b9d3f9 /net
parent67fa15db908950d6cb44f1e68667cbbbe31bd961 (diff)
downloadchromium_src-23f98b5d5729c3256eb2a1466c1e9cd12a999cc1.zip
chromium_src-23f98b5d5729c3256eb2a1466c1e9cd12a999cc1.tar.gz
chromium_src-23f98b5d5729c3256eb2a1466c1e9cd12a999cc1.tar.bz2
Do not use cert_pi_useAIACertFetch by default. Use it only
when we are likely to be missing intermediate CA certificates. Work around the SEC_ERROR_POLICY_VALIDATION_FAILED error from CERT_PKIXVerifyCert by retrying CERT_PKIXVerifyCert with the certificate policy in the certificate. Map SEC_ERROR_POLICY_VALIDATION_FAILED to ERR_CERT_INVALID if we can't work around the error. Start the migration away from test_certificate_data.h to the certificate files in the src/net/data/ssl/certificates directory. R=eroman BUG=31497,30891,37549 TEST=A new unit test. To verify the fix for issue 31497 manually, must install the "DoD Root CA 2" certificate first (see comment 9 of bug 31497). Review URL: http://codereview.chromium.org/545103 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42118 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/test_certificate_data.h123
-rw-r--r--net/base/x509_certificate_nss.cc176
-rw-r--r--net/base/x509_certificate_unittest.cc71
3 files changed, 207 insertions, 163 deletions
diff --git a/net/base/test_certificate_data.h b/net/base/test_certificate_data.h
index e475906..1ca6db8 100644
--- a/net/base/test_certificate_data.h
+++ b/net/base/test_certificate_data.h
@@ -443,127 +443,4 @@ unsigned char paypal_null_der[] = {
0x23, 0x82, 0x6f, 0xdb, 0xb8, 0x22, 0x1c, 0x43, 0x96, 0x07, 0xa8, 0xbb
};
-// A certificate for https://www.unosoft.hu/, whose AIA extension contains
-// an LDAP URL without a host name. Expires on 2011-09-08.
-unsigned char unosoft_hu_der[] = {
- 0x30, 0x82, 0x05, 0x7f, 0x30, 0x82, 0x04, 0x67, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x0a, 0x17, 0x73, 0x3e, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x3f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x30, 0x4a, 0x31, 0x15, 0x30, 0x13, 0x06, 0x0a,
- 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x05,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x31, 0x17, 0x30, 0x15, 0x06, 0x0a, 0x09,
- 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x07, 0x75,
- 0x6e, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
- 0x55, 0x04, 0x03, 0x13, 0x0f, 0x55, 0x4e, 0x4f, 0x2d, 0x53, 0x4f, 0x46,
- 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d,
- 0x30, 0x39, 0x31, 0x32, 0x30, 0x37, 0x31, 0x30, 0x33, 0x35, 0x35, 0x34,
- 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x39, 0x30, 0x38, 0x31, 0x38, 0x30,
- 0x36, 0x30, 0x37, 0x5a, 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55, 0x31, 0x11, 0x30, 0x0f, 0x06,
- 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65,
- 0x73, 0x74, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
- 0x1e, 0x55, 0x4e, 0x4f, 0x2d, 0x53, 0x4f, 0x46, 0x54, 0x20, 0x53, 0x7a,
- 0x61, 0x6d, 0x69, 0x74, 0x61, 0x73, 0x74, 0x65, 0x63, 0x68, 0x6e, 0x69,
- 0x6b, 0x61, 0x69, 0x20, 0x4b, 0x46, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x6e,
- 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x68, 0x75, 0x30, 0x81, 0x9f, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
- 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
- 0x00, 0xa4, 0x07, 0x76, 0xf1, 0xe0, 0xfa, 0x16, 0x58, 0xcc, 0x45, 0xee,
- 0xbb, 0x8f, 0xa1, 0x1b, 0x4b, 0x95, 0xe5, 0x6e, 0xc1, 0x93, 0xa3, 0xc1,
- 0x0a, 0x79, 0x33, 0x92, 0xfa, 0x6a, 0xb8, 0xf1, 0x14, 0x35, 0x45, 0x8f,
- 0xc5, 0x82, 0x0b, 0x71, 0xca, 0x2c, 0x48, 0x7e, 0x15, 0xa6, 0xa6, 0x66,
- 0x4f, 0x0b, 0x41, 0xe8, 0xdf, 0xeb, 0x96, 0x06, 0xb0, 0xed, 0x08, 0xbb,
- 0xe9, 0x14, 0x97, 0xf8, 0xdd, 0x66, 0x3f, 0xb7, 0x32, 0x7e, 0x8b, 0xab,
- 0x80, 0xd1, 0x2b, 0xd7, 0x8b, 0x0e, 0xfb, 0x88, 0x68, 0x73, 0x6b, 0xd7,
- 0x94, 0x22, 0x42, 0x94, 0x07, 0xd5, 0xe3, 0xc4, 0x98, 0x25, 0x01, 0x66,
- 0xe7, 0xc2, 0x5a, 0x1a, 0x3d, 0x0b, 0x01, 0x14, 0x49, 0x32, 0x47, 0x6c,
- 0xff, 0x19, 0x07, 0x6c, 0x1a, 0x47, 0x2f, 0x87, 0x4c, 0x3a, 0xc4, 0x61,
- 0xae, 0x77, 0x33, 0x4f, 0x27, 0xc1, 0xa5, 0xdd, 0x63, 0x02, 0x03, 0x01,
- 0x00, 0x01, 0xa3, 0x82, 0x02, 0xd1, 0x30, 0x82, 0x02, 0xcd, 0x30, 0x1d,
- 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xac, 0xee, 0x30,
- 0xf0, 0x0e, 0x73, 0x42, 0x73, 0x2f, 0x8f, 0xb5, 0x62, 0xcb, 0xb6, 0x3e,
- 0xdb, 0x62, 0x6c, 0xb2, 0x0a, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
- 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x29, 0x53, 0x4a, 0x9d, 0x9c, 0xd9,
- 0xf9, 0xda, 0x04, 0xfe, 0x46, 0x3a, 0x76, 0x49, 0x5c, 0xdd, 0x3b, 0x0e,
- 0x98, 0x76, 0x30, 0x82, 0x01, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04,
- 0x82, 0x01, 0x05, 0x30, 0x82, 0x01, 0x01, 0x30, 0x81, 0xfe, 0xa0, 0x81,
- 0xfb, 0xa0, 0x81, 0xf8, 0x86, 0x81, 0xb8, 0x6c, 0x64, 0x61, 0x70, 0x3a,
- 0x2f, 0x2f, 0x2f, 0x43, 0x4e, 0x3d, 0x55, 0x4e, 0x4f, 0x2d, 0x53, 0x4f,
- 0x46, 0x54, 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2c,
- 0x43, 0x4e, 0x3d, 0x55, 0x4e, 0x4f, 0x44, 0x43, 0x2c, 0x43, 0x4e, 0x3d,
- 0x43, 0x44, 0x50, 0x2c, 0x43, 0x4e, 0x3d, 0x50, 0x75, 0x62, 0x6c, 0x69,
- 0x63, 0x25, 0x32, 0x30, 0x4b, 0x65, 0x79, 0x25, 0x32, 0x30, 0x53, 0x65,
- 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x65,
- 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x6f,
- 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c,
- 0x44, 0x43, 0x3d, 0x75, 0x6e, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2c, 0x44,
- 0x43, 0x3d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x3f, 0x63, 0x65, 0x72, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x76, 0x6f, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x3f, 0x62, 0x61,
- 0x73, 0x65, 0x3f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61,
- 0x73, 0x73, 0x3d, 0x63, 0x52, 0x4c, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69,
- 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x86,
- 0x3b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x75, 0x6e, 0x6f, 0x64,
- 0x63, 0x2e, 0x75, 0x6e, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x2f, 0x43, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x72, 0x6f,
- 0x6c, 0x6c, 0x2f, 0x55, 0x4e, 0x4f, 0x2d, 0x53, 0x4f, 0x46, 0x54, 0x25,
- 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c,
- 0x30, 0x82, 0x01, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
- 0x01, 0x01, 0x04, 0x82, 0x01, 0x16, 0x30, 0x82, 0x01, 0x12, 0x30, 0x81,
- 0xb2, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86,
- 0x81, 0xa5, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x2f, 0x43, 0x4e,
- 0x3d, 0x55, 0x4e, 0x4f, 0x2d, 0x53, 0x4f, 0x46, 0x54, 0x25, 0x32, 0x30,
- 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x41, 0x49,
- 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x25,
- 0x32, 0x30, 0x4b, 0x65, 0x79, 0x25, 0x32, 0x30, 0x53, 0x65, 0x72, 0x76,
- 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x72, 0x76,
- 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x66,
- 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x44, 0x43,
- 0x3d, 0x75, 0x6e, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2c, 0x44, 0x43, 0x3d,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x3f, 0x63, 0x41, 0x43, 0x65, 0x72, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3f, 0x62, 0x61, 0x73, 0x65,
- 0x3f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73,
- 0x3d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30,
- 0x5b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86,
- 0x4f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x75, 0x6e, 0x6f, 0x64,
- 0x63, 0x2e, 0x75, 0x6e, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x2f, 0x43, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x72, 0x6f,
- 0x6c, 0x6c, 0x2f, 0x55, 0x4e, 0x4f, 0x44, 0x43, 0x2e, 0x75, 0x6e, 0x6f,
- 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x55,
- 0x4e, 0x4f, 0x2d, 0x53, 0x4f, 0x46, 0x54, 0x25, 0x32, 0x30, 0x52, 0x6f,
- 0x6f, 0x74, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x21, 0x06, 0x09,
- 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x04, 0x14, 0x1e,
- 0x12, 0x00, 0x57, 0x00, 0x65, 0x00, 0x62, 0x00, 0x53, 0x00, 0x65, 0x00,
- 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x30, 0x0c, 0x06, 0x03, 0x55,
- 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06,
- 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x13,
- 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b,
- 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
- 0x01, 0x01, 0x00, 0xaa, 0xc8, 0x95, 0xc4, 0x61, 0xcf, 0x3a, 0x6d, 0xf1,
- 0x66, 0xba, 0x2d, 0x24, 0x06, 0xe3, 0x1e, 0x33, 0x9a, 0x21, 0xda, 0x48,
- 0x99, 0xce, 0xfa, 0x36, 0x98, 0x78, 0x20, 0xc4, 0x81, 0xda, 0x5a, 0x9e,
- 0x45, 0xfd, 0xfa, 0x1e, 0xe6, 0x11, 0x72, 0xf2, 0xfd, 0x58, 0x79, 0x29,
- 0x52, 0x6a, 0xe6, 0xf3, 0x1b, 0xab, 0x28, 0xe6, 0x92, 0xd3, 0x65, 0x30,
- 0xf5, 0xd6, 0x51, 0x40, 0x01, 0xc0, 0x92, 0xbb, 0x4f, 0x8f, 0x74, 0xae,
- 0x78, 0x5d, 0x2c, 0x78, 0xce, 0x9c, 0xae, 0x90, 0x50, 0x1e, 0x67, 0x79,
- 0xc1, 0x84, 0xba, 0x0c, 0xff, 0x02, 0xe2, 0x31, 0xbb, 0x72, 0x75, 0x31,
- 0x16, 0x08, 0x10, 0x0e, 0xb2, 0x40, 0x6d, 0xa1, 0x52, 0xb8, 0x4b, 0x52,
- 0x47, 0xbe, 0xaa, 0x6f, 0x31, 0xd0, 0xb9, 0x52, 0xef, 0xb7, 0x3e, 0xf3,
- 0xae, 0x49, 0xf5, 0x1e, 0x33, 0x76, 0x43, 0xf3, 0x74, 0xeb, 0x7b, 0x22,
- 0xdf, 0x46, 0x15, 0x2b, 0xb5, 0xe5, 0x10, 0x24, 0x5d, 0x69, 0x30, 0x5a,
- 0xb0, 0xfe, 0xa2, 0x4d, 0xf5, 0xe6, 0x67, 0x87, 0x18, 0x81, 0x2d, 0x3d,
- 0xa2, 0xfb, 0xc3, 0x47, 0xc2, 0x87, 0x03, 0x5a, 0x2b, 0x3d, 0xdf, 0x7c,
- 0x52, 0xed, 0x24, 0xf3, 0x9e, 0x55, 0x4c, 0x76, 0x59, 0x0d, 0x29, 0x04,
- 0x70, 0xaa, 0x9c, 0x83, 0x8e, 0x6c, 0x3e, 0x46, 0xe3, 0x1b, 0x2e, 0x88,
- 0xd7, 0x68, 0x06, 0xbe, 0x92, 0x2b, 0x4a, 0x1d, 0x4a, 0x6a, 0xa6, 0x13,
- 0x75, 0xf1, 0x52, 0x5f, 0xfa, 0xf7, 0x14, 0x83, 0x62, 0x54, 0xb5, 0x69,
- 0x83, 0xd8, 0x9f, 0xce, 0xf0, 0xb9, 0xec, 0x05, 0x33, 0x85, 0xfc, 0xd1,
- 0xe0, 0x23, 0xd4, 0xab, 0xa2, 0xcd, 0xac, 0x90, 0xc5, 0xe4, 0x23, 0x1a,
- 0xc4, 0xd7, 0x38, 0xcf, 0x34, 0x43, 0xba, 0x58, 0x63, 0x92, 0xed, 0x11,
- 0x8e, 0x05, 0x08, 0xbe, 0xc9, 0x9a, 0x4b
-};
-
} // namespace
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc
index 705690a..6255f85 100644
--- a/net/base/x509_certificate_nss.cc
+++ b/net/base/x509_certificate_nss.cc
@@ -138,6 +138,7 @@ int MapSecurityError(int err) {
case SEC_ERROR_CERT_NOT_VALID:
// TODO(port): add an ERR_CERT_WRONG_USAGE error code.
case SEC_ERROR_CERT_USAGES_INVALID:
+ case SEC_ERROR_POLICY_VALIDATION_FAILED:
return ERR_CERT_INVALID;
default:
LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
@@ -169,6 +170,7 @@ int MapCertErrorToCertStatus(int err) {
case SEC_ERROR_CERT_NOT_VALID:
// TODO(port): add a CERT_STATUS_WRONG_USAGE error code.
case SEC_ERROR_CERT_USAGES_INVALID:
+ case SEC_ERROR_POLICY_VALIDATION_FAILED:
return CERT_STATUS_INVALID;
default:
return 0;
@@ -319,6 +321,12 @@ void GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle,
PORT_FreeArena(arena, PR_FALSE);
}
+// Forward declarations.
+SECStatus RetryPKIXVerifyCertWithWorkarounds(
+ X509Certificate::OSCertHandle cert_handle, int num_policy_oids,
+ std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout);
+SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle);
+
// Call CERT_PKIXVerifyCert for the cert_handle.
// Verification results are stored in an array of CERTValOutParam.
// If policy_oids is not NULL and num_policy_oids is positive, policies
@@ -392,60 +400,158 @@ SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle,
revocation_flags.chainTests.cert_rev_method_independent_flags =
revocation_method_independent_flags;
- CERTValInParam cvin[4];
- int cvin_index = 0;
+ std::vector<CERTValInParam> cvin;
+ cvin.reserve(5);
+ CERTValInParam in_param;
// No need to set cert_pi_trustAnchors here.
- cvin[cvin_index].type = cert_pi_revocationFlags;
- cvin[cvin_index].value.pointer.revocation = &revocation_flags;
- cvin_index++;
- std::vector<SECOidTag> policies;
+ in_param.type = cert_pi_revocationFlags;
+ in_param.value.pointer.revocation = &revocation_flags;
+ cvin.push_back(in_param);
if (policy_oids && num_policy_oids > 0) {
- cvin[cvin_index].type = cert_pi_policyOID;
- cvin[cvin_index].value.arraySize = num_policy_oids;
- cvin[cvin_index].value.array.oids = policy_oids;
- cvin_index++;
+ in_param.type = cert_pi_policyOID;
+ in_param.value.arraySize = num_policy_oids;
+ in_param.value.array.oids = policy_oids;
+ cvin.push_back(in_param);
}
- // Add cert_pi_useAIACertFetch last so we can easily remove it from the
- // cvin array in the workaround below.
- cvin[cvin_index].type = cert_pi_useAIACertFetch;
- cvin[cvin_index].value.scalar.b = PR_TRUE;
- cvin_index++;
- cvin[cvin_index].type = cert_pi_end;
+ in_param.type = cert_pi_end;
+ cvin.push_back(in_param);
SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
- cvin, cvout, NULL);
+ &cvin[0], cvout, NULL);
if (rv != SECSuccess) {
- // cert_pi_useAIACertFetch can't handle a CA issuers access location that
- // is an LDAP URL with an empty host name (NSS bug 528741). If cert fetch
- // fails because of a network error, it also causes CERT_PKIXVerifyCert
- // to report the network error rather than SEC_ERROR_UNKNOWN_ISSUER. To
- // work around these NSS bugs, we retry without cert_pi_useAIACertFetch.
- int nss_error = PORT_GetError();
- if (nss_error == SEC_ERROR_INVALID_ARGS || !IS_SEC_ERROR(nss_error)) {
- cvin_index--;
- DCHECK_EQ(cvin[cvin_index].type, cert_pi_useAIACertFetch);
- cvin[cvin_index].type = cert_pi_end;
+ rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids,
+ &cvin, cvout);
+ }
+ return rv;
+}
+
+// PKIXVerifyCert calls this function to work around some bugs in
+// CERT_PKIXVerifyCert. All the arguments of this function are either the
+// arguments or local variables of PKIXVerifyCert.
+SECStatus RetryPKIXVerifyCertWithWorkarounds(
+ X509Certificate::OSCertHandle cert_handle, int num_policy_oids,
+ std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout) {
+ // We call this function when the first CERT_PKIXVerifyCert call in
+ // PKIXVerifyCert failed, so we initialize |rv| to SECFailure.
+ SECStatus rv = SECFailure;
+ int nss_error = PORT_GetError();
+ CERTValInParam in_param;
+
+ // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate
+ // CA certificate, so we retry with cert_pi_useAIACertFetch.
+ // cert_pi_useAIACertFetch has several bugs in its error handling and
+ // error reporting (NSS bug 528743), so we don't use it by default.
+ // Note: When building a certificate chain, CERT_PKIXVerifyCert may
+ // incorrectly pick a CA certificate with the same subject name as the
+ // missing intermediate CA certificate, and fail with the
+ // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with
+ // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE.
+ if (nss_error == SEC_ERROR_UNKNOWN_ISSUER ||
+ nss_error == SEC_ERROR_BAD_SIGNATURE) {
+ DCHECK_EQ(cvin->back().type, cert_pi_end);
+ cvin->pop_back();
+ in_param.type = cert_pi_useAIACertFetch;
+ in_param.value.scalar.b = PR_TRUE;
+ cvin->push_back(in_param);
+ in_param.type = cert_pi_end;
+ cvin->push_back(in_param);
+ rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
+ &(*cvin)[0], cvout, NULL);
+ if (rv == SECSuccess)
+ return rv;
+ int new_nss_error = PORT_GetError();
+ if (new_nss_error == SEC_ERROR_INVALID_ARGS ||
+ new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE ||
+ !IS_SEC_ERROR(new_nss_error)) {
+ // Use the original error code because of cert_pi_useAIACertFetch's
+ // bad error reporting.
+ PORT_SetError(nss_error);
+ return rv;
+ }
+ nss_error = new_nss_error;
+ }
+
+ // If an intermediate CA certificate has requireExplicitPolicy in its
+ // policyConstraints extension, CERT_PKIXVerifyCert fails with
+ // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any
+ // certificate policy (NSS bug 552775). So we retry with the certificate
+ // policy found in the server certificate.
+ if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED &&
+ num_policy_oids == 0) {
+ SECOidTag policy = GetFirstCertPolicy(cert_handle);
+ if (policy != SEC_OID_UNKNOWN) {
+ DCHECK_EQ(cvin->back().type, cert_pi_end);
+ cvin->pop_back();
+ in_param.type = cert_pi_policyOID;
+ in_param.value.arraySize = 1;
+ in_param.value.array.oids = &policy;
+ cvin->push_back(in_param);
+ in_param.type = cert_pi_end;
+ cvin->push_back(in_param);
rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
- cvin, cvout, NULL);
+ &(*cvin)[0], cvout, NULL);
+ if (rv != SECSuccess) {
+ // Use the original error code.
+ PORT_SetError(nss_error);
+ }
}
}
+
return rv;
}
-bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
- SECOidTag ev_policy_tag) {
+// Decodes the certificatePolicies extension of the certificate. Returns
+// NULL if the certificate doesn't have the extension or the extension can't
+// be decoded. The returned value must be freed with a
+// CERT_DestroyCertificatePoliciesExtension call.
+CERTCertificatePolicies* DecodeCertPolicies(
+ X509Certificate::OSCertHandle cert_handle) {
SECItem policy_ext;
SECStatus rv = CERT_FindCertExtension(
cert_handle, SEC_OID_X509_CERTIFICATE_POLICIES, &policy_ext);
- if (rv != SECSuccess) {
- LOG(ERROR) << "Cert has no policies extension.";
- return false;
- }
+ if (rv != SECSuccess)
+ return NULL;
CERTCertificatePolicies* policies =
CERT_DecodeCertificatePoliciesExtension(&policy_ext);
SECITEM_FreeItem(&policy_ext, PR_FALSE);
+ return policies;
+}
+
+// Returns the OID tag for the first certificate policy in the certificate's
+// certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate
+// has no certificate policy.
+SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) {
+ CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
+ if (!policies)
+ return SEC_OID_UNKNOWN;
+ ScopedCERTCertificatePolicies scoped_policies(policies);
+ CERTPolicyInfo* policy_info = policies->policyInfos[0];
+ if (!policy_info)
+ return SEC_OID_UNKNOWN;
+ if (policy_info->oid != SEC_OID_UNKNOWN)
+ return policy_info->oid;
+
+ // The certificate policy is unknown to NSS. We need to create a dynamic
+ // OID tag for the policy.
+ SECOidData od;
+ od.oid.len = policy_info->policyID.len;
+ od.oid.data = policy_info->policyID.data;
+ od.offset = SEC_OID_UNKNOWN;
+ // NSS doesn't allow us to pass an empty description, so I use a hardcoded,
+ // default description here. The description doesn't need to be unique for
+ // each OID.
+ od.desc = "a certificate policy";
+ od.mechanism = CKM_INVALID_MECHANISM;
+ od.supportedExtension = INVALID_CERT_EXTENSION;
+ return SECOID_AddEntry(&od);
+}
+
+bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
+ SECOidTag ev_policy_tag) {
+ CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
if (!policies) {
- LOG(ERROR) << "Failed to decode certificate policy.";
+ LOG(ERROR) << "Cert has no policies extension or extension couldn't be "
+ "decoded.";
return false;
}
ScopedCERTCertificatePolicies scoped_policies(policies);
diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc
index 54de7a0..fb550ad 100644
--- a/net/base/x509_certificate_unittest.cc
+++ b/net/base/x509_certificate_unittest.cc
@@ -2,8 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
#include "base/pickle.h"
#include "net/base/cert_status_flags.h"
+#include "net/base/cert_test_util.h"
#include "net/base/cert_verify_result.h"
#include "net/base/net_errors.h"
#include "net/base/test_certificate_data.h"
@@ -23,6 +27,8 @@
using base::Time;
+namespace net {
+
namespace {
// Certificates for test data. They're obtained with:
@@ -70,9 +76,31 @@ unsigned char unosoft_hu_fingerprint[] = {
0x25, 0x66, 0xf2, 0xec, 0x8b, 0x0f, 0xbf, 0xd8
};
-} // namespace
+// Returns a FilePath object representing the src/net/data/ssl/certificates
+// directory in the source tree.
+FilePath GetTestCertsDirectory() {
+ FilePath certs_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &certs_dir);
+ certs_dir = certs_dir.AppendASCII("net");
+ certs_dir = certs_dir.AppendASCII("data");
+ certs_dir = certs_dir.AppendASCII("ssl");
+ certs_dir = certs_dir.AppendASCII("certificates");
+ return certs_dir;
+}
-namespace net {
+// Imports a certificate file in the src/net/data/ssl/certificates directory.
+// certs_dir represents the test certificates directory. cert_file is the
+// name of the certificate file.
+X509Certificate* ImportCertFromFile(const FilePath& certs_dir,
+ const std::string& cert_file) {
+ FilePath cert_path = certs_dir.AppendASCII(cert_file);
+ std::string cert_data;
+ if (!file_util::ReadFileToString(cert_path, &cert_data))
+ return NULL;
+ return X509Certificate::CreateFromBytes(cert_data.data(), cert_data.size());
+}
+
+} // namespace
TEST(X509CertificateTest, GoogleCertParsing) {
scoped_refptr<X509Certificate> google_cert = X509Certificate::CreateFromBytes(
@@ -272,12 +300,12 @@ TEST(X509CertificateTest, PaypalNullCertParsing) {
#endif
}
+// A certificate whose AIA extension contains an LDAP URL without a host name.
// This certificate will expire on 2011-09-08.
TEST(X509CertificateTest, UnoSoftCertParsing) {
+ FilePath certs_dir = GetTestCertsDirectory();
scoped_refptr<X509Certificate> unosoft_hu_cert =
- X509Certificate::CreateFromBytes(
- reinterpret_cast<const char*>(unosoft_hu_der),
- sizeof(unosoft_hu_der));
+ ImportCertFromFile(certs_dir, "unosoft_hu_cert.der");
ASSERT_NE(static_cast<X509Certificate*>(NULL), unosoft_hu_cert);
@@ -294,6 +322,39 @@ TEST(X509CertificateTest, UnoSoftCertParsing) {
EXPECT_NE(0, verify_result.cert_status & CERT_STATUS_AUTHORITY_INVALID);
}
+#if defined(USE_NSS)
+// A regression test for http://crbug.com/31497.
+// This certificate will expire on 2012-04-08.
+// TODO(wtc): we can't run this test on Mac because MacTrustedCertificates
+// can hold only one additional trusted root certificate for unit tests.
+// TODO(wtc): we can't run this test on Windows because LoadTemporaryRootCert
+// isn't implemented (http//crbug.com/8470).
+TEST(X509CertificateTest, IntermediateCARequireExplicitPolicy) {
+ FilePath certs_dir = GetTestCertsDirectory();
+
+ scoped_refptr<X509Certificate> server_cert =
+ ImportCertFromFile(certs_dir, "www_us_army_mil_cert.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert);
+
+ // The intermediate CA certificate's policyConstraints extension has a
+ // requireExplicitPolicy field with SkipCerts=0.
+ scoped_refptr<X509Certificate> intermediate_cert =
+ ImportCertFromFile(certs_dir, "dod_ca_17_cert.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
+
+ FilePath root_cert_path = certs_dir.AppendASCII("dod_root_ca_2_cert.der");
+ scoped_refptr<X509Certificate> root_cert =
+ LoadTemporaryRootCert(root_cert_path);
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ int error = server_cert->Verify("www.us.army.mil", flags, &verify_result);
+ EXPECT_EQ(OK, error);
+ EXPECT_EQ(0, verify_result.cert_status);
+}
+#endif
+
// Tests X509Certificate::Cache via X509Certificate::CreateFromHandle. We
// call X509Certificate::CreateFromHandle several times and observe whether
// it returns a cached or new X509Certificate object.