summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/tests')
-rw-r--r--security/manager/ssl/tests/.eslintrc.js8
-rw-r--r--security/manager/ssl/tests/gtest/CertDBTest.cpp60
-rw-r--r--security/manager/ssl/tests/gtest/DataStorageTest.cpp225
-rw-r--r--security/manager/ssl/tests/gtest/DeserializeCertTest.cpp96
-rw-r--r--security/manager/ssl/tests/gtest/MD4Test.cpp76
-rw-r--r--security/manager/ssl/tests/gtest/OCSPCacheTest.cpp337
-rw-r--r--security/manager/ssl/tests/gtest/README.txt2
-rw-r--r--security/manager/ssl/tests/gtest/STSParserTest.cpp144
-rw-r--r--security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp568
-rw-r--r--security/manager/ssl/tests/gtest/moz.build29
-rw-r--r--security/manager/ssl/tests/mochitest/browser/.eslintrc.js5
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser.ini18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js102
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_certViewer.js224
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_certificateManagerLeak.js32
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_clientAuth_connection.js135
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_clientAuth_ui.js137
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js215
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js150
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_editCACertTrust.js119
-rw-r--r--security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js142
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ca.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/mochitest/browser/code-ee.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/code-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/email-ee.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/email-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/expired-ca.pem18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/expired-ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-cn.pem18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-cn.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem16
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-o.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-o.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-ou.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/has-ou.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/head.js59
-rw-r--r--security/manager/ssl/tests/mochitest/browser/invalid.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/invalid.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/md5-ee.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/md5-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/moz.build35
-rw-r--r--security/manager/ssl/tests/mochitest/browser/revoked.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/revoked.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ssl-ee.pem18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/ssl-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem17
-rw-r--r--security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem.certspec2
-rw-r--r--security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem18
-rw-r--r--security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/.eslintrc.js5
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/alloworigin.sjs6
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/backward.html18
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/bug329869.js7
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/bug383369step2.html29
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/bug383369step3.html30
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/download.auto1
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/download.auto^headers^2
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/emptyimage.sjs5
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/hugebmp.sjs13
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/iframe.html13
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/iframe2.html14
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/iframeMetaRedirect.html8
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/iframesecredirect.sjs5
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/iframeunsecredirect.sjs5
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/imgsecredirect.sjs5
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/imgunsecredirect.sjs5
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/mixedContentTest.js204
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/mochitest.ini62
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpgbin0 -> 52159 bytes
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/moz.build8
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/nocontent.sjs4
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/redirecttoemptyimage.sjs5
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/somestyle.css4
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_bug329869.html37
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_bug383369.html102
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_bug455367.html35
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_bug472986.html47
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_bug477118.html35
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_bug521461.html39
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_cssBefore1.html43
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_cssContent1.html42
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_cssContent2.html47
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_documentWrite1.html38
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_documentWrite2.html40
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_dynDelayedUnsecurePicture.html48
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_dynDelayedUnsecureXHR.html49
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureBackground.html45
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureIframeRedirect.html45
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecurePicture.html46
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecurePicturePreload.html37
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureRedirect.html40
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_innerHtmlDelayedUnsecurePicture.html42
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_innerHtmlUnsecurePicture.html40
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_javascriptPicture.html35
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_secureAll.html43
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_securePicture.html37
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureBackground.html36
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureCSS.html39
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframe.html37
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframe2.html37
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframeMetaRedirect.html38
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframeRedirect.html38
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePicture.html35
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePictureDup.html21
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePictureInIframe.html37
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureRedirect.html37
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/unsecureIframe.html9
-rw-r--r--security/manager/ssl/tests/mochitest/mixedcontent/unsecurePictureDup.html35
-rw-r--r--security/manager/ssl/tests/mochitest/moz.build11
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/.eslintrc.js9
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/chrome.ini6
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/mochitest.ini13
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/moz.build10
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/nosts_bootstrap.html26
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/nosts_bootstrap.html^headers^1
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/page_blank.html5
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/plain_bootstrap.html26
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/plain_bootstrap.html^headers^2
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/subdom_bootstrap.html26
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/subdom_bootstrap.html^headers^2
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html120
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html275
-rw-r--r--security/manager/ssl/tests/mochitest/stricttransportsecurity/verify.sjs47
-rw-r--r--security/manager/ssl/tests/moz.build17
-rw-r--r--security/manager/ssl/tests/unit/.eslintrc.js5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/badSubjectAltNames.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/badSubjectAltNames.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/beforeEpoch.pem19
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/beforeEpoch.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/beforeEpochINT.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/beforeEpochINT.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/beforeEpochIssuer.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/beforeEpochIssuer.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/ca-used-as-end-entity.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/ca-used-as-end-entity.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/default-ee.key28
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/default-ee.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/default-ee.pem21
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/default-ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/eeIssuedByNonCA.pem19
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/eeIssuedByNonCA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/eeIssuedByV1Cert.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/eeIssuedByV1Cert.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/emptyIssuerName.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/emptyIssuerName.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/emptyNameCA.pem17
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/emptyNameCA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/ev-test-intermediate.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/ev-test-intermediate.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/ev-test.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/ev-test.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/evroot.key28
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/evroot.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/evroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/evroot.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/expired-ee.pem19
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/expired-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/expiredINT.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/expiredINT.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/expiredissuer.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/expiredissuer.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.key16
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.pem17
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/inadequatekeyusage-ee.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/inadequatekeyusage-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/ipAddressAsDNSNameInSAN.pem17
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/ipAddressAsDNSNameInSAN.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/md5signature-expired.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/md5signature-expired.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/md5signature.pem19
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/md5signature.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch-expired.pem19
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch-expired.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch-notYetValid.pem19
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch-notYetValid.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted-expired.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted-expired.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatch.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatchCN.pem17
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/mismatchCN.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/moz.build68
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/noValidNames.pem19
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/noValidNames.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/notYetValid.pem19
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/notYetValid.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/notYetValidINT.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/notYetValidINT.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/notYetValidIssuer.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/notYetValidIssuer.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/nsCertTypeCritical.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/nsCertTypeCritical.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/nsCertTypeCriticalWithExtKeyUsage.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/nsCertTypeCriticalWithExtKeyUsage.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/nsCertTypeNotCritical.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/nsCertTypeNotCritical.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/other-issuer-ee.pem21
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/other-issuer-ee.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/other-test-ca.key28
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/other-test-ca.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/other-test-ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/other-test-ca.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/self-signed-EE-with-cA-true.pem21
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/self-signed-EE-with-cA-true.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/selfsigned-inadequateEKU.pem21
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/selfsigned-inadequateEKU.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/selfsigned.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/selfsigned.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/test-ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/test-ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/test-int.pem18
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/test-int.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/unknownissuer.pem22
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/unknownissuer.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/untrusted-expired.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/untrusted-expired.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/untrustedissuer.pem20
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/untrustedissuer.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/v1Cert.pem17
-rw-r--r--security/manager/ssl/tests/unit/bad_certs/v1Cert.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/head_psm.js863
-rw-r--r--security/manager/ssl/tests/unit/moz.build37
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/ca-used-as-end-entity.pem20
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/ca-used-as-end-entity.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/default-ee.key28
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/default-ee.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/default-ee.pem21
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/default-ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/delegatedSHA1Signer.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/delegatedSHA1Signer.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/delegatedSigner.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/delegatedSigner.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerFromIntermediate.pem19
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerFromIntermediate.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerKeyUsageCrlSigning.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerKeyUsageCrlSigning.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerNoExtKeyUsage.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerNoExtKeyUsage.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerWrongExtKeyUsage.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerWrongExtKeyUsage.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/moz.build42
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-bad-ee.pem19
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-bad-ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-good-ee.pem19
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-good-ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee-with-must-staple-int.pem19
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee-with-must-staple-int.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/must-staple-missing-ee.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/must-staple-missing-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/ocspEEWithIntermediate.pem20
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/ocspEEWithIntermediate.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/ocspOtherEndEntity.pem19
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/ocspOtherEndEntity.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.key28
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.key16
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.pem15
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/test-ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/test-ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/test-int.pem18
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/test-int.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/test-multi-tls-feature-int.pem19
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/test-multi-tls-feature-int.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/test-must-staple-int.pem19
-rw-r--r--security/manager/ssl/tests/unit/ocsp_certs/test-must-staple-int.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/pkcs11testmodule/moz.build18
-rw-r--r--security/manager/ssl/tests/unit/pkcs11testmodule/pkcs11testmodule.cpp633
-rw-r--r--security/manager/ssl/tests/unit/pkcs11testmodule/pkcs11testmodule.symbols1
-rwxr-xr-xsecurity/manager/ssl/tests/unit/pycert.py697
-rwxr-xr-xsecurity/manager/ssl/tests/unit/pykey.py706
-rw-r--r--security/manager/ssl/tests/unit/sss_readstate_child_worker.js25
-rw-r--r--security/manager/ssl/tests/unit/test_add_preexisting_cert.js45
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/moz.build19
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/no-san-old.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/no-san-old.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/no-san-older.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/no-san-older.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/no-san-recent.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/no-san-recent.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-old.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-old.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-older.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-older.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-recent.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-recent.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js188
-rw-r--r--security/manager/ssl/tests/unit/test_certDB_import.js118
-rw-r--r--security/manager/ssl/tests/unit/test_certDB_import/cert_from_windows.pfxbin0 -> 2041 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_certDB_import/moz.build14
-rw-r--r--security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js92
-rw-r--r--security/manager/ssl/tests/unit/test_cert_blocklist.js362
-rw-r--r--security/manager/ssl/tests/unit/test_cert_chains.js134
-rw-r--r--security/manager/ssl/tests/unit/test_cert_dbKey.js146
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku.js131
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ca.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-CA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-CA.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-SA-CA.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-SA-CA.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-SA-OCSP.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-SA-OCSP.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-SA-nsSGC.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-SA-nsSGC.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-SA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-SA.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-CA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-CA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-CA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-CA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-OCSP.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-OCSP.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-nsSGC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-nsSGC.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-old.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-old.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-older.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-older.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-recent.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-recent.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-nsSGC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/ee-nsSGC.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-CA.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-CA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-SA-CA.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-SA-CA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-SA-OCSP.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-SA-OCSP.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-SA-nsSGC.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-SA-nsSGC.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-SA.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-SA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-old.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-old.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-older.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-older.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-recent.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-recent.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_eku/moz.build35
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null.js38
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_embedded_null/moz.build17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_isBuiltInRoot.js71
-rw-r--r--security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload.js123
-rw-r--r--security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/cert8.dbbin0 -> 65536 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/cert9.dbbin0 -> 28672 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/key3.dbbin0 -> 16384 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/key4.dbbin0 -> 36864 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage.js57
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_keyUsage/moz.build27
-rw-r--r--security/manager/ssl/tests/unit/test_cert_override_bits_mismatches.js89
-rw-r--r--security/manager/ssl/tests/unit/test_cert_overrides.js340
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1.js142
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/ca.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-post.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-post.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-pre.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-pre.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/ee-pre_int-pre.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/ee-pre_int-pre.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/int-post.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/int-post.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/int-pre.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/int-pre.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_cert_sha1/moz.build18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures.js121
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ca-secp384r1.pem11
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ca-secp384r1.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa-direct.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa-direct.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1-direct.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1-direct.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/int-rsa.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/int-rsa.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/int-secp384r1.pem11
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/int-secp384r1.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_cert_signatures/moz.build20
-rw-r--r--security/manager/ssl/tests/unit/test_cert_trust.js216
-rw-r--r--security/manager/ssl/tests/unit/test_cert_trust/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_trust/ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_trust/ee.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_trust/ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_trust/int.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_trust/int.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_trust/moz.build15
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version.js190
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-cA_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-not-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-not-cA_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v1-noBC_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v1-noBC_ca.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-cA_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-not-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-not-cA_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v2-noBC_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v2-noBC_ca.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-cA_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-not-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-not-cA_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v3-noBC_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v3-noBC_ca.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-cA_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-not-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-not-cA_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v4-noBC_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee-v4-noBC_ca.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-cA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-not-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-not-cA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-noBC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-noBC.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-cA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-not-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-not-cA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-noBC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-noBC.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-cA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-not-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-not-cA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-noBC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-noBC.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-cA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-not-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-not-cA.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-noBC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-noBC.pem.certspec2
-rwxr-xr-xsecurity/manager/ssl/tests/unit/test_cert_version/generate.py82
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-cA_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-cA_ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-not-cA_ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-not-cA_ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v1-noBC_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v1-noBC_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-cA_ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-cA_ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-not-cA_ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-not-cA_ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v2-noBC_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v2-noBC_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-cA_ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-cA_ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-not-cA_ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-not-cA_ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v3-noBC_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v3-noBC_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-cA_ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-cA_ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-not-cA_ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-not-cA_ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v4-noBC_ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/int-v4-noBC_ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/moz.build61
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-cA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-not-cA.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-not-cA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v1-noBC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v1-noBC.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-cA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-not-cA.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-not-cA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v2-noBC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v2-noBC.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-cA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-not-cA.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-not-cA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v3-noBC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v3-noBC.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-cA.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-cA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-not-cA.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-not-cA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v4-noBC.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_cert_version/ss-v4-noBC.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js62
-rw-r--r--security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack2b.pem14
-rw-r--r--security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack7.pem16
-rw-r--r--security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-pk10oflo.pem14
-rw-r--r--security/manager/ssl/tests/unit/test_constructX509FromBase64.js69
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing.js266
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_int.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_int.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_RSA_ee.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_RSA_ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_ee.pem15
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_no_SAN_ee.pem14
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_no_SAN_ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_wrong_key_ee.pem14
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_wrong_key_ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_remote_newtab_ee.pem15
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_remote_newtab_ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_root.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/content_signing_root.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/moz.build19
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/pysign.py29
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/test.txt1
-rw-r--r--security/manager/ssl/tests/unit/test_content_signing/test.txt.signature1
-rw-r--r--security/manager/ssl/tests/unit/test_datasignatureverifier.js193
-rw-r--r--security/manager/ssl/tests/unit/test_der.js219
-rw-r--r--security/manager/ssl/tests/unit/test_enterprise_roots.js58
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs.js356
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-ee.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-int.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-ee.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-int.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem23
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-ee.pem22
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-int.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-ee.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-int.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/evroot.key28
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/evroot.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/evroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/evroot.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/moz.build48
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-ee.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-int.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-ee.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-int.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-int.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-ee.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-int.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-int.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-ee.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-int.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem23
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-ee.pem22
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-int.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-ee.pem22
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-int.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-ee.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-ee.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.key28
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_forget_about_site_security_headers.js100
-rw-r--r--security/manager/ssl/tests/unit/test_getchain.js82
-rw-r--r--security/manager/ssl/tests/unit/test_getchain/ca-1.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_getchain/ca-1.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_getchain/ca-2.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_getchain/ca-2.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_getchain/ee.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_getchain/ee.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_getchain/moz.build15
-rw-r--r--security/manager/ssl/tests/unit/test_hash_algorithms.js87
-rw-r--r--security/manager/ssl/tests/unit/test_hash_algorithms_wrap.js5
-rw-r--r--security/manager/ssl/tests/unit/test_hmac.js88
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints.js111
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-cA-FALSE-asserts-keyCertSign.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-cA-FALSE-asserts-keyCertSign.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-cA-FALSE-asserts-keyCertSign.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-cA-FALSE-asserts-keyCertSign.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/moz.build35
-rw-r--r--security/manager/ssl/tests/unit/test_js_cert_override_service.js56
-rw-r--r--security/manager/ssl/tests/unit/test_keysize.js127
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem12
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem12
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem15
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem13
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem11
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem11
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem12
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_rsa_1024.pem13
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_rsa_1024.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_secp256r1_256.pem12
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_secp256r1_256.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1016.pem13
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1016.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1024.pem13
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1024.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp224r1_224-root_secp256r1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp224r1_224-root_secp256r1_256.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_rsa_2048.pem14
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_rsa_2048.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp224r1_224.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp224r1_224.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256k1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256k1_256.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256r1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256r1_256.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp384r1_384-root_secp256r1_256.pem11
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/int_secp384r1_384-root_secp256r1_256.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/moz.build41
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_rsa_1016.pem12
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_rsa_1016.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_rsa_1024.pem12
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_rsa_1024.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_rsa_2048.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_rsa_2048.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_secp224r1_224.pem9
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_secp224r1_224.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_secp256k1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_secp256k1_256.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_secp256r1_256.pem10
-rw-r--r--security/manager/ssl/tests/unit/test_keysize/root_secp256r1_256.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev.js146
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040-evroot.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040-evroot.pem.certspec8
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040.key28
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-ev_root_rsa_2040.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-ev_root_rsa_2040.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-evroot.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-evroot.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048.key28
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.key28
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/evroot.key28
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/evroot.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/evroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/evroot.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_keysize_ev/moz.build31
-rw-r--r--security/manager/ssl/tests/unit/test_local_cert.js83
-rw-r--r--security/manager/ssl/tests/unit/test_logoutAndTeardown.js55
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints.js63
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissallowed.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissallowed.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissblocked.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissblocked.pem.certspec2
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ca-example-com-permitted.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ca-example-com-permitted.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/dciss.pem22
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/dciss.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ee-example-com-and-org.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ee-example-com-and-org.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ee-example-com.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ee-example-com.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ee-example-org.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ee-example-org.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ee-example-test.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/ee-example-test.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/int-example-org-permitted.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/int-example-org-permitted.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_name_constraints/moz.build21
-rw-r--r--security/manager/ssl/tests/unit/test_nsCertType.js28
-rw-r--r--security/manager/ssl/tests/unit/test_nsIX509CertValidity.js49
-rw-r--r--security/manager/ssl/tests/unit/test_nsIX509Cert_utf8.js70
-rw-r--r--security/manager/ssl/tests/unit/test_nss_shutdown.js44
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_caching.js299
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_enabled_pref.js141
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method.js59
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/a.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/a.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.key28
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_fetch_method/moz.build22
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_must_staple.js116
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_no_hsts_upgrade.js54
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_required.js55
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_stapling.js209
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js184
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_stapling_with_intermediate.js45
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_timeout.js88
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url.js137
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/bad-scheme.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/bad-scheme.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/ca.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/empty-scheme-url.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/empty-scheme-url.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/ftp-url.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/ftp-url.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/hTTp-url.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/hTTp-url.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/https-url.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/https-url.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/int.key28
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/int.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/int.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/int.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/moz.build33
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/negative-port.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/negative-port.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/no-host-url.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/no-host-url.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/no-path-url.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/no-path-url.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-host-port.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-host-port.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-url.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-url.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/unknown-scheme.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/unknown-scheme.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/user-pass.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_ocsp_url/user-pass.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_onecrl/moz.build14
-rw-r--r--security/manager/ssl/tests/unit/test_onecrl/same-issuer-ee.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_onecrl/same-issuer-ee.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_onecrl/sample_revocations.txt39
-rw-r--r--security/manager/ssl/tests/unit/test_onecrl/test-int-ee.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_onecrl/test-int-ee.pem.certspec3
-rw-r--r--security/manager/ssl/tests/unit/test_password_prompt.js78
-rw-r--r--security/manager/ssl/tests/unit/test_pinning.js263
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic.js246
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-badca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-badca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-badca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-badca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-pinningroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-pinningroot.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-badca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-badca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-pinningroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-pinningroot.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-badca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-badca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-pinningroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-pinningroot.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/badca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/badca.pem.certspec6
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/moz.build26
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-badca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-badca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-pinningroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-pinningroot.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-badca.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-badca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-pinningroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-pinningroot.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_pinning_header_parsing.js141
-rw-r--r--security/manager/ssl/tests/unit/test_pkcs11_insert_remove.js41
-rw-r--r--security/manager/ssl/tests/unit/test_pkcs11_module.js121
-rw-r--r--security/manager/ssl/tests/unit/test_pkcs11_no_events_after_removal.js29
-rw-r--r--security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js49
-rw-r--r--security/manager/ssl/tests/unit/test_pkcs11_slot.js38
-rw-r--r--security/manager/ssl/tests/unit/test_pkcs11_token.js119
-rw-r--r--security/manager/ssl/tests/unit/test_pkcs11_tokenDB.js45
-rw-r--r--security/manager/ssl/tests/unit/test_sdr.js87
-rw-r--r--security/manager/ssl/tests/unit/test_session_resumption.js159
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps-marketplace.js42
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps.js233
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/README.md18
-rwxr-xr-xsecurity/manager/ssl/tests/unit/test_signed_apps/gentestfiles/create_test_files.sh213
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/nss_ctypes.py129
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/sign_b2g_app.py174
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/icon-128.pngbin0 -> 1633 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/index.html6
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/manifest.webapp8
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/icon-128.pngbin0 -> 1633 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/index.html6
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/manifest.webapp10
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin_toolkit_webapps/index.html10
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin_toolkit_webapps/manifest.webapp9
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/privileged-app-test-1.0.zipbin0 -> 23169 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/test-privileged-app-test-1.0.zipbin0 -> 22750 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/trusted_ca1.derbin0 -> 898 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/unknown_issuer_app_1.zipbin0 -> 4220 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/unsigned_app_1.zipbin0 -> 2282 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_apps/valid_app_1.zipbin0 -> 4222 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_dir.js201
-rw-r--r--security/manager/ssl/tests/unit/test_signed_dir/lightbeam_for_firefox-1.3.1-fx.xpibin0 -> 672533 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/README.md17
-rwxr-xr-xsecurity/manager/ssl/tests/unit/test_signed_manifest/create_test_files.sh181
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/manifest.webapp10
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/nss_ctypes.py136
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/sign_b2g_manifest.py76
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/testInvalidSignedManifest/manifest.sigbin0 -> 1501 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/testValidSignedManifest/manifest.sigbin0 -> 1494 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_signed_manifest/trusted_ca1.derbin0 -> 928 bytes
-rw-r--r--security/manager/ssl/tests/unit/test_sss_eviction.js85
-rw-r--r--security/manager/ssl/tests/unit/test_sss_readstate.js82
-rw-r--r--security/manager/ssl/tests/unit/test_sss_readstate_child.js41
-rw-r--r--security/manager/ssl/tests/unit/test_sss_readstate_empty.js40
-rw-r--r--security/manager/ssl/tests/unit/test_sss_readstate_garbage.js56
-rw-r--r--security/manager/ssl/tests/unit/test_sss_readstate_huge.js60
-rw-r--r--security/manager/ssl/tests/unit/test_sss_savestate.js128
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign.js43
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-after-cutoff.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-after-cutoff.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-before-cutoff.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-before-cutoff.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/StartComCA.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/StartComCA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-after-cutoff.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-after-cutoff.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-before-cutoff.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-before-cutoff.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/WoSignCA.pem19
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/WoSignCA.pem.certspec4
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/ca.pem17
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/ca.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_startcom_wosign/moz.build19
-rw-r--r--security/manager/ssl/tests/unit/test_sts_fqdn.js50
-rw-r--r--security/manager/ssl/tests/unit/test_sts_holepunch.js34
-rw-r--r--security/manager/ssl/tests/unit/test_sts_ipv4_ipv6.js42
-rw-r--r--security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js217
-rw-r--r--security/manager/ssl/tests/unit/test_sts_preloadlist_selfdestruct.js23
-rw-r--r--security/manager/ssl/tests/unit/test_toolkit_securityreporter.js133
-rw-r--r--security/manager/ssl/tests/unit/test_validity.js92
-rw-r--r--security/manager/ssl/tests/unit/test_validity/ev_ee_27_months-ev_int_60_months-evroot.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_validity/ev_ee_27_months-ev_int_60_months-evroot.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_validity/ev_ee_28_months-ev_int_60_months-evroot.pem21
-rw-r--r--security/manager/ssl/tests/unit/test_validity/ev_ee_28_months-ev_int_60_months-evroot.pem.certspec5
-rw-r--r--security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.key28
-rw-r--r--security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.pem20
-rw-r--r--security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.pem.certspec8
-rw-r--r--security/manager/ssl/tests/unit/test_validity/evroot.key28
-rw-r--r--security/manager/ssl/tests/unit/test_validity/evroot.key.keyspec1
-rw-r--r--security/manager/ssl/tests/unit/test_validity/evroot.pem18
-rw-r--r--security/manager/ssl/tests/unit/test_validity/evroot.pem.certspec7
-rw-r--r--security/manager/ssl/tests/unit/test_validity/moz.build24
-rw-r--r--security/manager/ssl/tests/unit/test_weak_crypto.js273
-rw-r--r--security/manager/ssl/tests/unit/test_x509.js83
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp141
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp170
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp129
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/cmd/moz.build25
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/default-ee.der3
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.cpp215
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.h61
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp600
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.h89
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/lib/moz.build17
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/moz.build8
-rw-r--r--security/manager/ssl/tests/unit/xpcshell-smartcards.ini14
-rw-r--r--security/manager/ssl/tests/unit/xpcshell.ini149
1011 files changed, 29814 insertions, 0 deletions
diff --git a/security/manager/ssl/tests/.eslintrc.js b/security/manager/ssl/tests/.eslintrc.js
new file mode 100644
index 000000000..a2a4eb389
--- /dev/null
+++ b/security/manager/ssl/tests/.eslintrc.js
@@ -0,0 +1,8 @@
+"use strict";
+
+module.exports = { // eslint-disable-line no-undef
+ "rules": {
+ // Disallow non-top level |var| declarations.
+ "mozilla/var-only-at-top-level": "error"
+ }
+};
diff --git a/security/manager/ssl/tests/gtest/CertDBTest.cpp b/security/manager/ssl/tests/gtest/CertDBTest.cpp
new file mode 100644
index 000000000..e6b773cd6
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/CertDBTest.cpp
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "nsCOMPtr.h"
+#include "nsIPrefService.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIX509Cert.h"
+#include "nsIX509CertDB.h"
+#include "nsIX509CertList.h"
+#include "nsServiceManagerUtils.h"
+
+TEST(psm_CertDB, Test)
+{
+ {
+ nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+ ASSERT_TRUE(prefs) << "couldn't get nsIPrefBranch";
+
+ // When PSM initializes, it attempts to get some localized strings.
+ // As a result, Android flips out if this isn't set.
+ nsresult rv = prefs->SetBoolPref("intl.locale.matchOS", true);
+ ASSERT_TRUE(NS_SUCCEEDED(rv)) << "couldn't set pref 'intl.locale.matchOS'";
+
+ nsCOMPtr<nsIX509CertDB> certdb(do_GetService(NS_X509CERTDB_CONTRACTID));
+ ASSERT_TRUE(certdb) << "couldn't get certdb";
+
+ nsCOMPtr<nsIX509CertList> certList;
+ rv = certdb->GetCerts(getter_AddRefs(certList));
+ ASSERT_TRUE(NS_SUCCEEDED(rv)) << "couldn't get list of certificates";
+
+ nsCOMPtr<nsISimpleEnumerator> enumerator;
+ rv = certList->GetEnumerator(getter_AddRefs(enumerator));
+ ASSERT_TRUE(NS_SUCCEEDED(rv)) << "couldn't enumerate certificate list";
+
+ bool foundBuiltIn = false;
+ bool hasMore = false;
+ while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsISupports> supports;
+ ASSERT_TRUE(NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(supports))))
+ << "couldn't get next certificate";
+
+ nsCOMPtr<nsIX509Cert> cert(do_QueryInterface(supports));
+ ASSERT_TRUE(cert) << "couldn't QI to nsIX509Cert";
+
+ ASSERT_TRUE(NS_SUCCEEDED(cert->GetIsBuiltInRoot(&foundBuiltIn))) <<
+ "GetIsBuiltInRoot failed";
+
+ if (foundBuiltIn) {
+ break;
+ }
+ }
+
+ ASSERT_TRUE(foundBuiltIn) << "didn't load any built-in certificates";
+
+ printf("successfully loaded at least one built-in certificate\n");
+
+ } // this scopes the nsCOMPtrs
+}
diff --git a/security/manager/ssl/tests/gtest/DataStorageTest.cpp b/security/manager/ssl/tests/gtest/DataStorageTest.cpp
new file mode 100644
index 000000000..eaab50878
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/DataStorageTest.cpp
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/DataStorage.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsNetUtil.h"
+#include "nsPrintfCString.h"
+#include "nsStreamUtils.h"
+#include "prtime.h"
+
+using namespace mozilla;
+
+class psm_DataStorageTest : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ const ::testing::TestInfo* const testInfo =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ NS_ConvertUTF8toUTF16 testName(testInfo->name());
+ storage = DataStorage::Get(testName);
+ storage->Init(dataWillPersist);
+ }
+
+ RefPtr<DataStorage> storage;
+ bool dataWillPersist;
+};
+
+NS_NAMED_LITERAL_CSTRING(testKey, "test");
+NS_NAMED_LITERAL_CSTRING(testValue, "value");
+NS_NAMED_LITERAL_CSTRING(privateTestValue, "private");
+
+TEST_F(psm_DataStorageTest, GetPutRemove)
+{
+ EXPECT_TRUE(dataWillPersist);
+
+ // Test Put/Get on Persistent data
+ EXPECT_EQ(NS_OK, storage->Put(testKey, testValue, DataStorage_Persistent));
+ // Don't re-use testKey / testValue here, to make sure that this works as
+ // expected with objects that have the same semantic value but are not
+ // literally the same object.
+ nsCString result = storage->Get(NS_LITERAL_CSTRING("test"),
+ DataStorage_Persistent);
+ EXPECT_STREQ("value", result.get());
+
+ // Get on Temporary/Private data with the same key should give nothing
+ result = storage->Get(testKey, DataStorage_Temporary);
+ EXPECT_TRUE(result.IsEmpty());
+ result = storage->Get(testKey, DataStorage_Private);
+ EXPECT_TRUE(result.IsEmpty());
+
+ // Put with Temporary/Private data shouldn't affect Persistent data
+ NS_NAMED_LITERAL_CSTRING(temporaryTestValue, "temporary");
+ EXPECT_EQ(NS_OK, storage->Put(testKey, temporaryTestValue,
+ DataStorage_Temporary));
+ EXPECT_EQ(NS_OK, storage->Put(testKey, privateTestValue,
+ DataStorage_Private));
+ result = storage->Get(testKey, DataStorage_Temporary);
+ EXPECT_STREQ("temporary", result.get());
+ result = storage->Get(testKey, DataStorage_Private);
+ EXPECT_STREQ("private", result.get());
+ result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_STREQ("value", result.get());
+
+ // Put of a previously-present key overwrites it (if of the same type)
+ NS_NAMED_LITERAL_CSTRING(newValue, "new");
+ EXPECT_EQ(NS_OK, storage->Put(testKey, newValue, DataStorage_Persistent));
+ result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_STREQ("new", result.get());
+
+ // Removal should work
+ storage->Remove(testKey, DataStorage_Temporary);
+ result = storage->Get(testKey, DataStorage_Temporary);
+ EXPECT_TRUE(result.IsEmpty());
+ // But removing one type shouldn't affect the others
+ result = storage->Get(testKey, DataStorage_Private);
+ EXPECT_STREQ("private", result.get());
+ result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_STREQ("new", result.get());
+ // Test removing the other types as well
+ storage->Remove(testKey, DataStorage_Private);
+ result = storage->Get(testKey, DataStorage_Private);
+ EXPECT_TRUE(result.IsEmpty());
+ storage->Remove(testKey, DataStorage_Persistent);
+ result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_TRUE(result.IsEmpty());
+}
+
+TEST_F(psm_DataStorageTest, InputValidation)
+{
+ EXPECT_TRUE(dataWillPersist);
+
+ // Keys may not have tabs or newlines
+ EXPECT_EQ(NS_ERROR_INVALID_ARG,
+ storage->Put(NS_LITERAL_CSTRING("key\thas tab"), testValue,
+ DataStorage_Persistent));
+ nsCString result = storage->Get(NS_LITERAL_CSTRING("key\thas tab"),
+ DataStorage_Persistent);
+ EXPECT_TRUE(result.IsEmpty());
+ EXPECT_EQ(NS_ERROR_INVALID_ARG,
+ storage->Put(NS_LITERAL_CSTRING("key has\nnewline"), testValue,
+ DataStorage_Persistent));
+ result = storage->Get(NS_LITERAL_CSTRING("keyhas\nnewline"),
+ DataStorage_Persistent);
+ EXPECT_TRUE(result.IsEmpty());
+ // Values may not have newlines
+ EXPECT_EQ(NS_ERROR_INVALID_ARG,
+ storage->Put(testKey, NS_LITERAL_CSTRING("value\nhas newline"),
+ DataStorage_Persistent));
+ result = storage->Get(testKey, DataStorage_Persistent);
+ // Values may have tabs
+ EXPECT_TRUE(result.IsEmpty());
+ EXPECT_EQ(NS_OK, storage->Put(testKey,
+ NS_LITERAL_CSTRING("val\thas tab; this is ok"),
+ DataStorage_Persistent));
+ result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_STREQ("val\thas tab; this is ok", result.get());
+
+ nsCString longKey("a");
+ for (int i = 0; i < 8; i++) {
+ longKey.Append(longKey);
+ }
+ // A key of length 256 will work
+ EXPECT_EQ(NS_OK, storage->Put(longKey, testValue, DataStorage_Persistent));
+ result = storage->Get(longKey, DataStorage_Persistent);
+ EXPECT_STREQ("value", result.get());
+ longKey.Append("a");
+ // A key longer than that will not work
+ EXPECT_EQ(NS_ERROR_INVALID_ARG,
+ storage->Put(longKey, testValue, DataStorage_Persistent));
+ result = storage->Get(longKey, DataStorage_Persistent);
+ EXPECT_TRUE(result.IsEmpty());
+
+ nsCString longValue("a");
+ for (int i = 0; i < 10; i++) {
+ longValue.Append(longValue);
+ }
+ // A value of length 1024 will work
+ EXPECT_EQ(NS_OK, storage->Put(testKey, longValue, DataStorage_Persistent));
+ result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_STREQ(longValue.get(), result.get());
+ longValue.Append("a");
+ // A value longer than that will not work
+ storage->Remove(testKey, DataStorage_Persistent);
+ EXPECT_EQ(NS_ERROR_INVALID_ARG,
+ storage->Put(testKey, longValue, DataStorage_Persistent));
+ result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_TRUE(result.IsEmpty());
+}
+
+TEST_F(psm_DataStorageTest, Eviction)
+{
+ EXPECT_TRUE(dataWillPersist);
+
+ // Eviction is on a per-table basis. Tables shouldn't affect each other.
+ EXPECT_EQ(NS_OK, storage->Put(testKey, testValue, DataStorage_Persistent));
+ for (int i = 0; i < 1025; i++) {
+ EXPECT_EQ(NS_OK, storage->Put(nsPrintfCString("%d", i),
+ nsPrintfCString("%d", i),
+ DataStorage_Temporary));
+ nsCString result = storage->Get(nsPrintfCString("%d", i),
+ DataStorage_Temporary);
+ EXPECT_STREQ(nsPrintfCString("%d", i).get(), result.get());
+ }
+ // We don't know which entry got evicted, but we can count them.
+ int entries = 0;
+ for (int i = 0; i < 1025; i++) {
+ nsCString result = storage->Get(nsPrintfCString("%d", i),
+ DataStorage_Temporary);
+ if (!result.IsEmpty()) {
+ entries++;
+ }
+ }
+ EXPECT_EQ(entries, 1024);
+ nsCString result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_STREQ("value", result.get());
+}
+
+TEST_F(psm_DataStorageTest, ClearPrivateData)
+{
+ EXPECT_TRUE(dataWillPersist);
+
+ EXPECT_EQ(NS_OK, storage->Put(testKey, privateTestValue,
+ DataStorage_Private));
+ nsCString result = storage->Get(testKey, DataStorage_Private);
+ EXPECT_STREQ("private", result.get());
+ storage->Observe(nullptr, "last-pb-context-exited", nullptr);
+ result = storage->Get(testKey, DataStorage_Private);
+ EXPECT_TRUE(result.IsEmpty());
+}
+
+TEST_F(psm_DataStorageTest, Shutdown)
+{
+ EXPECT_TRUE(dataWillPersist);
+
+ EXPECT_EQ(NS_OK, storage->Put(testKey, testValue, DataStorage_Persistent));
+ nsCString result = storage->Get(testKey, DataStorage_Persistent);
+ EXPECT_STREQ("value", result.get());
+ // Get "now" (in days) close to when the data was last touched, so we won't
+ // get intermittent failures with the day not matching.
+ int64_t microsecondsPerDay = 24 * 60 * 60 * int64_t(PR_USEC_PER_SEC);
+ int32_t nowInDays = int32_t(PR_Now() / microsecondsPerDay);
+ storage->Observe(nullptr, "profile-before-change", nullptr);
+ nsCOMPtr<nsIFile> backingFile;
+ EXPECT_EQ(NS_OK, NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+ getter_AddRefs(backingFile)));
+ const ::testing::TestInfo* const testInfo =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ NS_ConvertUTF8toUTF16 testName(testInfo->name());
+ EXPECT_EQ(NS_OK, backingFile->Append(testName));
+ nsCOMPtr<nsIInputStream> fileInputStream;
+ EXPECT_EQ(NS_OK, NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream),
+ backingFile));
+ nsCString data;
+ EXPECT_EQ(NS_OK, NS_ConsumeStream(fileInputStream, UINT32_MAX, data));
+ // The data will be of the form 'test\t0\t<days since the epoch>\tvalue'
+ EXPECT_STREQ(nsPrintfCString("test\t0\t%d\tvalue\n", nowInDays).get(),
+ data.get());
+}
diff --git a/security/manager/ssl/tests/gtest/DeserializeCertTest.cpp b/security/manager/ssl/tests/gtest/DeserializeCertTest.cpp
new file mode 100644
index 000000000..868ecdba6
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/DeserializeCertTest.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsSerializationHelper.h"
+
+// These tests verify that we can still deserialize old binary strings
+// generated for security info. This is necessary because service workers
+// stores these strings on disk.
+//
+// If you make a change and start breaking these tests, you will need to
+// add a compat fix for loading the old versions. For things that affect
+// the UUID, but do not break the rest of the format you can simply add
+// another hack condition in nsBinaryInputStream::ReadObject(). If you
+// change the overall format of the serialization then we will need more
+// complex handling in the security info concrete classes.
+//
+// We would like to move away from this binary compatibility requirement
+// in service workers. See bug 1248628.
+
+TEST(psm_DeserializeCert, gecko33)
+{
+ // Gecko 33+ vintage Security info serialized with UUIDs:
+ // - nsISupports 00000000-0000-0000-c000-000000000046
+ // - nsISSLStatus fa9ba95b-ca3b-498a-b889-7c79cf28fee8
+ // - nsIX509Cert f8ed8364-ced9-4c6e-86ba-48af53c393e6
+ nsCString base64Serialization(
+ "FnhllAKWRHGAlo+ESXykKAAAAAAAAAAAwAAAAAAAAEaphjojH6pBabDSgSnsfLHeAAQAAgAAAAAAAAAAAAAAAAAAAAA"
+ "B4vFIJp5wRkeyPxAQ9RJGKPqbqVvKO0mKuIl8ec8o/uhmCjImkVxP+7sgiYWmMt8F+O2DZM7ZTG6GukivU8OT5gAAAAIAAAWpMII"
+ "FpTCCBI2gAwIBAgIQD4svsaKEC+QtqtsU2TF8ITANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUN"
+ "lcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFN"
+ "lcnZlciBDQTAeFw0xNTAyMjMwMDAwMDBaFw0xNjAzMDIxMjAwMDBaMGoxCzAJBgNVBAYTAlVTMRYwFAYDVQQHEw1TYW4gRnJhbmN"
+ "pc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRUwEwYDVQQKEwxGYXN0bHksIEluYy4xFzAVBgNVBAMTDnd3dy5naXRodWIuY29tMII"
+ "BIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+9WUCgrgUNwP/JC3cUefLAXeDpq8Ko/U8p8IRvny0Ri0I6Uq0t+RP/nF0LJ"
+ "Avda8QHYujdgeDTePepBX7+OiwBFhA0YO+rM3C2Z8IRaN/i9eLln+Yyc68+1z+E10s1EXdZrtDGvN6MHqygGsdfkXKfBLUJ1BZEh"
+ "s9sBnfcjq3kh5gZdBArdG9l5NpdmQhtceaFGsPiWuJxGxRzS4i95veUHWkhMpEYDEEBdcDGxqArvQCvzSlngdttQCfx8OUkBTb3B"
+ "A2okpTwwJfqPsxVetA6qR7UNc+fVb6KHwvm0bzi2rQ3xw3D/syRHwdMkpoVDQPCk43H9WufgfBKRen87dFwIDAQABo4ICPzCCAjs"
+ "wHwYDVR0jBBgwFoAUUWj/kK8CB3U8zNllZGKiErhZcjswHQYDVR0OBBYEFGS/RLNGCZvPWh1xSaIEcouINIQjMHsGA1UdEQR0MHK"
+ "CDnd3dy5naXRodWIuY29tggpnaXRodWIuY29tggwqLmdpdGh1Yi5jb22CCyouZ2l0aHViLmlvgglnaXRodWIuaW+CFyouZ2l0aHV"
+ "idXNlcmNvbnRlbnQuY29tghVnaXRodWJ1c2VyY29udGVudC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwM"
+ "BBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzMuY3J"
+ "sMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzMuY3JsMEIGA1UdIAQ7MDkwNwYJYIZIAYb"
+ "9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQc"
+ "wAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUN"
+ "lcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAc4dbVmuKvyI7"
+ "KZ4Txk+ZqcAYToJGKUIVaPL94e5SZGweUisjaCbplAOihnf6Mxt8n6vnuH2IsCaz2NRHqhdcosjT3CwAiJpJNkXPKWVL/txgdSTV"
+ "2cqB1GG4esFOalvI52dzn+J4fTIYZvNF+AtGyHSLm2XRXYZCw455laUKf6Sk9RDShDgUvzhOKL4GXfTwKXv12MyMknJybH8UCpjC"
+ "HZmFBVHMcUN/87HsQo20PdOekeEvkjrrMIxW+gxw22Yb67yF/qKgwrWr+43bLN709iyw+LWiU7sQcHL2xk9SYiWQDj2tYz2soObV"
+ "QYTJm0VUZMEVFhtALq46cx92Zu4vFwC8AAwAAAAABAQAA");
+
+ nsCOMPtr<nsISupports> cert;
+ nsresult rv = NS_DeserializeObject(base64Serialization, getter_AddRefs(cert));
+ ASSERT_EQ(NS_OK, rv);
+ ASSERT_TRUE(cert);
+}
+
+TEST(psm_DeserializeCert, gecko46)
+{
+ // Gecko 46+ vintage Security info serialized with UUIDs:
+ // - nsISupports 00000000-0000-0000-c000-000000000046
+ // - nsISSLStatus fa9ba95b-ca3b-498a-b889-7c79cf28fee8
+ // - nsIX509Cert bdc3979a-5422-4cd5-8589-696b6e96ea83
+ nsCString base64Serialization(
+ "FnhllAKWRHGAlo+ESXykKAAAAAAAAAAAwAAAAAAAAEaphjojH6pBabDSgSnsfLHeAAQAAgAAAAAAAAAAAAAAAAAAAAA"
+ "B4vFIJp5wRkeyPxAQ9RJGKPqbqVvKO0mKuIl8ec8o/uhmCjImkVxP+7sgiYWmMt8FvcOXmlQiTNWFiWlrbpbqgwAAAAIAAAWzMII"
+ "FrzCCBJegAwIBAgIQB3pdwzYjAfmJ/lT3+G8+ZDANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUN"
+ "lcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFN"
+ "lcnZlciBDQTAeFw0xNjAxMjAwMDAwMDBaFw0xNzA0MDYxMjAwMDBaMGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybml"
+ "hMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxGYXN0bHksIEluYy4xFzAVBgNVBAMTDnd3dy5naXRodWIuY29tMII"
+ "BIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+9WUCgrgUNwP/JC3cUefLAXeDpq8Ko/U8p8IRvny0Ri0I6Uq0t+RP/nF0LJ"
+ "Avda8QHYujdgeDTePepBX7+OiwBFhA0YO+rM3C2Z8IRaN/i9eLln+Yyc68+1z+E10s1EXdZrtDGvN6MHqygGsdfkXKfBLUJ1BZEh"
+ "s9sBnfcjq3kh5gZdBArdG9l5NpdmQhtceaFGsPiWuJxGxRzS4i95veUHWkhMpEYDEEBdcDGxqArvQCvzSlngdttQCfx8OUkBTb3B"
+ "A2okpTwwJfqPsxVetA6qR7UNc+fVb6KHwvm0bzi2rQ3xw3D/syRHwdMkpoVDQPCk43H9WufgfBKRen87dFwIDAQABo4ICSTCCAkU"
+ "wHwYDVR0jBBgwFoAUUWj/kK8CB3U8zNllZGKiErhZcjswHQYDVR0OBBYEFGS/RLNGCZvPWh1xSaIEcouINIQjMHsGA1UdEQR0MHK"
+ "CDnd3dy5naXRodWIuY29tggwqLmdpdGh1Yi5jb22CCmdpdGh1Yi5jb22CCyouZ2l0aHViLmlvgglnaXRodWIuaW+CFyouZ2l0aHV"
+ "idXNlcmNvbnRlbnQuY29tghVnaXRodWJ1c2VyY29udGVudC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwM"
+ "BBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzUuY3J"
+ "sMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzUuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb"
+ "9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3MHU"
+ "wJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQ"
+ "uY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQE"
+ "ATxbRdPg+o49+96/P+rbdp4ie+CGtfCgUubT/Z9C54k+BfQO0nbxVgCSM5WZQuLgo2Q+0lcxisod8zxZeU0j5wviQINwOln/iN89"
+ "Bx3VmDRynTe4CqhsAwOoO1ERmCAmsAJBwY/rNr4mK22p8erBrqMW0nYXYU5NFynI+pNTjojhKD4II8PNV8G2yMWwYOb/u4+WPzUA"
+ "HC9DpZdrWTEH/W69Cr/KxRqGsWPwpgMv2Wqav8jaT35JxqTXjOlhQqzo6fNn3eYOeCf4PkCxZKwckWjy10qDaRbjhwAMHAGj2TPr"
+ "idlvOj/7QyyX5m8up/1US8z1fRW4yoCSOt6V2bwuH6cAvAAMAAAAAAQEAAA==");
+
+ nsCOMPtr<nsISupports> cert;
+ nsresult rv = NS_DeserializeObject(base64Serialization, getter_AddRefs(cert));
+ ASSERT_EQ(NS_OK, rv);
+ ASSERT_TRUE(cert);
+}
diff --git a/security/manager/ssl/tests/gtest/MD4Test.cpp b/security/manager/ssl/tests/gtest/MD4Test.cpp
new file mode 100644
index 000000000..1b635a757
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/MD4Test.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This file tests the md4.c implementation.
+
+#include "gtest/gtest.h"
+#include "md4.h"
+#include "mozilla/Casting.h"
+#include "mozilla/PodOperations.h"
+
+struct RFC1320TestParams
+{
+ const char* data;
+ const uint8_t expectedHash[16];
+};
+
+static const RFC1320TestParams RFC1320_TEST_PARAMS[] =
+{
+ {
+ "",
+ { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
+ 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 }
+ },
+ {
+ "a",
+ { 0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46,
+ 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 }
+ },
+ {
+ "abc",
+ { 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52,
+ 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d }
+ },
+ {
+ "message digest",
+ { 0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8,
+ 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b }
+ },
+ {
+ "abcdefghijklmnopqrstuvwxyz",
+ { 0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd,
+ 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 },
+ },
+ {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ { 0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35,
+ 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 },
+ },
+ {
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ { 0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19,
+ 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 },
+ }
+};
+
+class psm_MD4
+ : public ::testing::Test
+ , public ::testing::WithParamInterface<RFC1320TestParams>
+{
+};
+
+TEST_P(psm_MD4, RFC1320TestValues)
+{
+ const RFC1320TestParams& params(GetParam());
+ uint8_t actualHash[16];
+ md4sum(mozilla::BitwiseCast<const uint8_t*, const char*>(params.data),
+ strlen(params.data), actualHash);
+ EXPECT_TRUE(mozilla::PodEqual(actualHash, params.expectedHash))
+ << "MD4 hashes aren't equal for input: '" << params.data << "'";
+}
+
+INSTANTIATE_TEST_CASE_P(psm_MD4, psm_MD4,
+ testing::ValuesIn(RFC1320_TEST_PARAMS));
diff --git a/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp
new file mode 100644
index 000000000..2b7dc946c
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CertVerifier.h"
+#include "OCSPCache.h"
+#include "gtest/gtest.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/Casting.h"
+#include "mozilla/Sprintf.h"
+#include "nss.h"
+#include "pkix/pkixtypes.h"
+#include "pkixtestutil.h"
+#include "prerr.h"
+#include "secerr.h"
+
+using namespace mozilla::pkix;
+using namespace mozilla::pkix::test;
+
+using mozilla::NeckoOriginAttributes;
+
+template <size_t N>
+inline Input
+LiteralInput(const char(&valueString)[N])
+{
+ // Ideally we would use mozilla::BitwiseCast() here rather than
+ // reinterpret_cast for better type checking, but the |N - 1| part trips
+ // static asserts.
+ return Input(reinterpret_cast<const uint8_t(&)[N - 1]>(valueString));
+}
+
+const int MaxCacheEntries = 1024;
+
+class psm_OCSPCacheTest : public ::testing::Test
+{
+protected:
+ psm_OCSPCacheTest() : now(Now()) { }
+
+ static void SetUpTestCase()
+ {
+ NSS_NoDB_Init(nullptr);
+ }
+
+ const Time now;
+ mozilla::psm::OCSPCache cache;
+};
+
+static void
+PutAndGet(mozilla::psm::OCSPCache& cache, const CertID& certID, Result result,
+ Time time,
+ const NeckoOriginAttributes& originAttributes = NeckoOriginAttributes())
+{
+ // The first time is thisUpdate. The second is validUntil.
+ // The caller is expecting the validUntil returned with Get
+ // to be equal to the passed-in time. Since these values will
+ // be different in practice, make thisUpdate less than validUntil.
+ Time thisUpdate(time);
+ ASSERT_EQ(Success, thisUpdate.SubtractSeconds(10));
+ Result rv = cache.Put(certID, originAttributes, result, thisUpdate, time);
+ ASSERT_TRUE(rv == Success);
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ ASSERT_TRUE(cache.Get(certID, originAttributes, resultOut, timeOut));
+ ASSERT_EQ(result, resultOut);
+ ASSERT_EQ(time, timeOut);
+}
+
+Input fakeIssuer1(LiteralInput("CN=issuer1"));
+Input fakeKey000(LiteralInput("key000"));
+Input fakeKey001(LiteralInput("key001"));
+Input fakeSerial0000(LiteralInput("0000"));
+
+TEST_F(psm_OCSPCacheTest, TestPutAndGet)
+{
+ Input fakeSerial000(LiteralInput("000"));
+ Input fakeSerial001(LiteralInput("001"));
+
+ SCOPED_TRACE("");
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial001),
+ Success, now);
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial000),
+ NeckoOriginAttributes(), resultOut, timeOut));
+}
+
+TEST_F(psm_OCSPCacheTest, TestVariousGets)
+{
+ SCOPED_TRACE("");
+ for (int i = 0; i < MaxCacheEntries; i++) {
+ uint8_t serialBuf[8];
+ snprintf(mozilla::BitwiseCast<char*, uint8_t*>(serialBuf), sizeof(serialBuf),
+ "%04d", i);
+ Input fakeSerial;
+ ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
+ Time timeIn(now);
+ ASSERT_EQ(Success, timeIn.AddSeconds(i));
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
+ Success, timeIn);
+ }
+
+ Time timeIn(now);
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+
+ // This will be at the end of the list in the cache
+ CertID cert0000(fakeIssuer1, fakeKey000, fakeSerial0000);
+ ASSERT_TRUE(cache.Get(cert0000, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(timeIn, timeOut);
+ // Once we access it, it goes to the front
+ ASSERT_TRUE(cache.Get(cert0000, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(timeIn, timeOut);
+
+ // This will be in the middle
+ Time timeInPlus512(now);
+ ASSERT_EQ(Success, timeInPlus512.AddSeconds(512));
+
+ static const Input fakeSerial0512(LiteralInput("0512"));
+ CertID cert0512(fakeIssuer1, fakeKey000, fakeSerial0512);
+ ASSERT_TRUE(cache.Get(cert0512, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(timeInPlus512, timeOut);
+ ASSERT_TRUE(cache.Get(cert0512, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(timeInPlus512, timeOut);
+
+ // We've never seen this certificate
+ static const Input fakeSerial1111(LiteralInput("1111"));
+ ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey000, fakeSerial1111),
+ NeckoOriginAttributes(), resultOut, timeOut));
+}
+
+TEST_F(psm_OCSPCacheTest, TestEviction)
+{
+ SCOPED_TRACE("");
+ // By putting more distinct entries in the cache than it can hold,
+ // we cause the least recently used entry to be evicted.
+ for (int i = 0; i < MaxCacheEntries + 1; i++) {
+ uint8_t serialBuf[8];
+ snprintf(mozilla::BitwiseCast<char*, uint8_t*>(serialBuf), sizeof(serialBuf),
+ "%04d", i);
+ Input fakeSerial;
+ ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
+ Time timeIn(now);
+ ASSERT_EQ(Success, timeIn.AddSeconds(i));
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
+ Success, timeIn);
+ }
+
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial0000),
+ NeckoOriginAttributes(), resultOut, timeOut));
+}
+
+TEST_F(psm_OCSPCacheTest, TestNoEvictionForRevokedResponses)
+{
+ SCOPED_TRACE("");
+ CertID notEvicted(fakeIssuer1, fakeKey000, fakeSerial0000);
+ Time timeIn(now);
+ PutAndGet(cache, notEvicted, Result::ERROR_REVOKED_CERTIFICATE, timeIn);
+ // By putting more distinct entries in the cache than it can hold,
+ // we cause the least recently used entry that isn't revoked to be evicted.
+ for (int i = 1; i < MaxCacheEntries + 1; i++) {
+ uint8_t serialBuf[8];
+ snprintf(mozilla::BitwiseCast<char*, uint8_t*>(serialBuf), sizeof(serialBuf),
+ "%04d", i);
+ Input fakeSerial;
+ ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
+ Time timeIn(now);
+ ASSERT_EQ(Success, timeIn.AddSeconds(i));
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
+ Success, timeIn);
+ }
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ ASSERT_TRUE(cache.Get(notEvicted, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, resultOut);
+ ASSERT_EQ(timeIn, timeOut);
+
+ Input fakeSerial0001(LiteralInput("0001"));
+ CertID evicted(fakeIssuer1, fakeKey000, fakeSerial0001);
+ ASSERT_FALSE(cache.Get(evicted, NeckoOriginAttributes(), resultOut, timeOut));
+}
+
+TEST_F(psm_OCSPCacheTest, TestEverythingIsRevoked)
+{
+ SCOPED_TRACE("");
+ Time timeIn(now);
+ // Fill up the cache with revoked responses.
+ for (int i = 0; i < MaxCacheEntries; i++) {
+ uint8_t serialBuf[8];
+ snprintf(mozilla::BitwiseCast<char*, uint8_t*>(serialBuf), sizeof(serialBuf),
+ "%04d", i);
+ Input fakeSerial;
+ ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
+ Time timeIn(now);
+ ASSERT_EQ(Success, timeIn.AddSeconds(i));
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
+ Result::ERROR_REVOKED_CERTIFICATE, timeIn);
+ }
+ static const Input fakeSerial1025(LiteralInput("1025"));
+ CertID good(fakeIssuer1, fakeKey000, fakeSerial1025);
+ // This will "succeed", allowing verification to continue. However,
+ // nothing was actually put in the cache.
+ Time timeInPlus1025(timeIn);
+ ASSERT_EQ(Success, timeInPlus1025.AddSeconds(1025));
+ Time timeInPlus1025Minus50(timeInPlus1025);
+ ASSERT_EQ(Success, timeInPlus1025Minus50.SubtractSeconds(50));
+ Result result = cache.Put(good, NeckoOriginAttributes(), Success, timeInPlus1025Minus50,
+ timeInPlus1025);
+ ASSERT_EQ(Success, result);
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ ASSERT_FALSE(cache.Get(good, NeckoOriginAttributes(), resultOut, timeOut));
+
+ static const Input fakeSerial1026(LiteralInput("1026"));
+ CertID revoked(fakeIssuer1, fakeKey000, fakeSerial1026);
+ // This will fail, causing verification to fail.
+ Time timeInPlus1026(timeIn);
+ ASSERT_EQ(Success, timeInPlus1026.AddSeconds(1026));
+ Time timeInPlus1026Minus50(timeInPlus1026);
+ ASSERT_EQ(Success, timeInPlus1026Minus50.SubtractSeconds(50));
+ result = cache.Put(revoked, NeckoOriginAttributes(), Result::ERROR_REVOKED_CERTIFICATE,
+ timeInPlus1026Minus50, timeInPlus1026);
+ ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, result);
+}
+
+TEST_F(psm_OCSPCacheTest, VariousIssuers)
+{
+ SCOPED_TRACE("");
+ Time timeIn(now);
+ static const Input fakeIssuer2(LiteralInput("CN=issuer2"));
+ static const Input fakeSerial001(LiteralInput("001"));
+ CertID subject(fakeIssuer1, fakeKey000, fakeSerial001);
+ PutAndGet(cache, subject, Success, now);
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ ASSERT_TRUE(cache.Get(subject, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(timeIn, timeOut);
+ // Test that we don't match a different issuer DN
+ ASSERT_FALSE(cache.Get(CertID(fakeIssuer2, fakeKey000, fakeSerial001),
+ NeckoOriginAttributes(), resultOut, timeOut));
+ // Test that we don't match a different issuer key
+ ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial001),
+ NeckoOriginAttributes(), resultOut, timeOut));
+}
+
+TEST_F(psm_OCSPCacheTest, Times)
+{
+ SCOPED_TRACE("");
+ CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
+ PutAndGet(cache, certID, Result::ERROR_OCSP_UNKNOWN_CERT,
+ TimeFromElapsedSecondsAD(100));
+ PutAndGet(cache, certID, Success, TimeFromElapsedSecondsAD(200));
+ // This should not override the more recent entry.
+ ASSERT_EQ(Success,
+ cache.Put(certID, NeckoOriginAttributes(), Result::ERROR_OCSP_UNKNOWN_CERT,
+ TimeFromElapsedSecondsAD(100),
+ TimeFromElapsedSecondsAD(100)));
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ ASSERT_TRUE(cache.Get(certID, NeckoOriginAttributes(), resultOut, timeOut));
+ // Here we see the more recent time.
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(TimeFromElapsedSecondsAD(200), timeOut);
+
+ // Result::ERROR_REVOKED_CERTIFICATE overrides everything
+ PutAndGet(cache, certID, Result::ERROR_REVOKED_CERTIFICATE,
+ TimeFromElapsedSecondsAD(50));
+}
+
+TEST_F(psm_OCSPCacheTest, NetworkFailure)
+{
+ SCOPED_TRACE("");
+ CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
+ PutAndGet(cache, certID, Result::ERROR_CONNECT_REFUSED,
+ TimeFromElapsedSecondsAD(100));
+ PutAndGet(cache, certID, Success, TimeFromElapsedSecondsAD(200));
+ // This should not override the already present entry.
+ ASSERT_EQ(Success,
+ cache.Put(certID, NeckoOriginAttributes(), Result::ERROR_CONNECT_REFUSED,
+ TimeFromElapsedSecondsAD(300),
+ TimeFromElapsedSecondsAD(350)));
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ ASSERT_TRUE(cache.Get(certID, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(TimeFromElapsedSecondsAD(200), timeOut);
+
+ PutAndGet(cache, certID, Result::ERROR_OCSP_UNKNOWN_CERT,
+ TimeFromElapsedSecondsAD(400));
+ // This should not override the already present entry.
+ ASSERT_EQ(Success,
+ cache.Put(certID, NeckoOriginAttributes(), Result::ERROR_CONNECT_REFUSED,
+ TimeFromElapsedSecondsAD(500),
+ TimeFromElapsedSecondsAD(550)));
+ ASSERT_TRUE(cache.Get(certID, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Result::ERROR_OCSP_UNKNOWN_CERT, resultOut);
+ ASSERT_EQ(TimeFromElapsedSecondsAD(400), timeOut);
+
+ PutAndGet(cache, certID, Result::ERROR_REVOKED_CERTIFICATE,
+ TimeFromElapsedSecondsAD(600));
+ // This should not override the already present entry.
+ ASSERT_EQ(Success,
+ cache.Put(certID, NeckoOriginAttributes(), Result::ERROR_CONNECT_REFUSED,
+ TimeFromElapsedSecondsAD(700),
+ TimeFromElapsedSecondsAD(750)));
+ ASSERT_TRUE(cache.Get(certID, NeckoOriginAttributes(), resultOut, timeOut));
+ ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, resultOut);
+ ASSERT_EQ(TimeFromElapsedSecondsAD(600), timeOut);
+}
+
+TEST_F(psm_OCSPCacheTest, TestOriginAttributes)
+{
+ CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
+
+ SCOPED_TRACE("");
+ NeckoOriginAttributes attrs;
+ attrs.mFirstPartyDomain.AssignLiteral("foo.com");
+ PutAndGet(cache, certID, Success, now, attrs);
+
+ Result resultOut;
+ Time timeOut(Time::uninitialized);
+ attrs.mFirstPartyDomain.AssignLiteral("bar.com");
+ ASSERT_FALSE(cache.Get(certID, attrs, resultOut, timeOut));
+
+ // OCSP cache should not be isolated by containers.
+ attrs.mUserContextId = 1;
+ attrs.mFirstPartyDomain.AssignLiteral("foo.com");
+ ASSERT_TRUE(cache.Get(certID, attrs, resultOut, timeOut));
+}
diff --git a/security/manager/ssl/tests/gtest/README.txt b/security/manager/ssl/tests/gtest/README.txt
new file mode 100644
index 000000000..0e5132269
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/README.txt
@@ -0,0 +1,2 @@
+Please name all test cases in this directory with the prefix "psm". This makes
+it easier to run all PSM related GTests at once.
diff --git a/security/manager/ssl/tests/gtest/STSParserTest.cpp b/security/manager/ssl/tests/gtest/STSParserTest.cpp
new file mode 100644
index 000000000..bedf57fea
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/STSParserTest.cpp
@@ -0,0 +1,144 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+
+#include "gtest/gtest.h"
+#include "nsNetUtil.h"
+#include "nsISiteSecurityService.h"
+#include "nsIURI.h"
+
+void
+TestSuccess(const char* hdr, bool extraTokens,
+ uint64_t expectedMaxAge, bool expectedIncludeSubdomains,
+ nsISiteSecurityService* sss)
+{
+ nsCOMPtr<nsIURI> dummyUri;
+ nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
+ ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to create URI";
+
+ uint64_t maxAge = 0;
+ bool includeSubdomains = false;
+ rv = sss->UnsafeProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri,
+ hdr, 0, &maxAge, &includeSubdomains, nullptr);
+ ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to process valid header: " << hdr;
+
+ ASSERT_EQ(maxAge, expectedMaxAge) << "Did not correctly parse maxAge";
+ EXPECT_EQ(includeSubdomains, expectedIncludeSubdomains) <<
+ "Did not correctly parse presence/absence of includeSubdomains";
+
+ if (extraTokens) {
+ EXPECT_EQ(rv, NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA) <<
+ "Extra tokens were expected when parsing, but were not encountered.";
+ } else {
+ EXPECT_EQ(rv, NS_OK) << "Unexpected tokens found during parsing.";
+ }
+
+ printf("%s\n", hdr);
+}
+
+void TestFailure(const char* hdr,
+ nsISiteSecurityService* sss)
+{
+ nsCOMPtr<nsIURI> dummyUri;
+ nsresult rv = NS_NewURI(getter_AddRefs(dummyUri), "https://foo.com/bar.html");
+ ASSERT_TRUE(NS_SUCCEEDED(rv)) << "Failed to create URI";
+
+ rv = sss->UnsafeProcessHeader(nsISiteSecurityService::HEADER_HSTS, dummyUri,
+ hdr, 0, nullptr, nullptr, nullptr);
+ ASSERT_TRUE(NS_FAILED(rv)) << "Parsed invalid header: " << hdr;
+
+ printf("%s\n", hdr);
+}
+
+TEST(psm_STSParser, Test)
+{
+ nsresult rv;
+
+ // grab handle to the service
+ nsCOMPtr<nsISiteSecurityService> sss;
+ sss = do_GetService("@mozilla.org/ssservice;1", &rv);
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ // *** parsing tests
+ printf("*** Attempting to parse valid STS headers ...\n");
+
+ // SHOULD SUCCEED:
+ TestSuccess("max-age=100", false, 100, false, sss);
+ TestSuccess("max-age =100", false, 100, false, sss);
+ TestSuccess(" max-age=100", false, 100, false, sss);
+ TestSuccess("max-age = 100 ", false, 100, false, sss);
+ TestSuccess("max-age = \"100\" ", false, 100, false, sss);
+ TestSuccess("max-age=\"100\"", false, 100, false, sss);
+ TestSuccess(" max-age =\"100\" ", false, 100, false, sss);
+ TestSuccess("\tmax-age\t=\t\"100\"\t", false, 100, false, sss);
+ TestSuccess("max-age = 100 ", false, 100, false, sss);
+
+ TestSuccess("maX-aGe=100", false, 100, false, sss);
+ TestSuccess("MAX-age =100", false, 100, false, sss);
+ TestSuccess("max-AGE=100", false, 100, false, sss);
+ TestSuccess("Max-Age = 100 ", false, 100, false, sss);
+ TestSuccess("MAX-AGE = 100 ", false, 100, false, sss);
+
+ TestSuccess("max-age=100;includeSubdomains", false, 100, true, sss);
+ TestSuccess("max-age=100\t; includeSubdomains", false, 100, true, sss);
+ TestSuccess(" max-age=100; includeSubdomains", false, 100, true, sss);
+ TestSuccess("max-age = 100 ; includeSubdomains", false, 100, true, sss);
+ TestSuccess("max-age = 100 ; includeSubdomains",
+ false, 100, true, sss);
+
+ TestSuccess("maX-aGe=100; includeSUBDOMAINS", false, 100, true, sss);
+ TestSuccess("MAX-age =100; includeSubDomains", false, 100, true, sss);
+ TestSuccess("max-AGE=100; iNcLuDeSuBdoMaInS", false, 100, true, sss);
+ TestSuccess("Max-Age = 100; includesubdomains ", false, 100, true, sss);
+ TestSuccess("INCLUDESUBDOMAINS;MaX-AgE = 100 ", false, 100, true, sss);
+ // Turns out, the actual directive is entirely optional (hence the
+ // trailing semicolon)
+ TestSuccess("max-age=100;includeSubdomains;", true, 100, true, sss);
+
+ // these are weird tests, but are testing that some extended syntax is
+ // still allowed (but it is ignored)
+ TestSuccess("max-age=100 ; includesubdomainsSomeStuff",
+ true, 100, false, sss);
+ TestSuccess("\r\n\t\t \tcompletelyUnrelated = foobar; max-age= 34520103"
+ "\t \t; alsoUnrelated;asIsThis;\tincludeSubdomains\t\t \t",
+ true, 34520103, true, sss);
+ TestSuccess("max-age=100; unrelated=\"quoted \\\"thingy\\\"\"",
+ true, 100, false, sss);
+
+ // SHOULD FAIL:
+ printf("* Attempting to parse invalid STS headers (should not parse)...\n");
+ // invalid max-ages
+ TestFailure("max-age", sss);
+ TestFailure("max-age ", sss);
+ TestFailure("max-age=p", sss);
+ TestFailure("max-age=*1p2", sss);
+ TestFailure("max-age=.20032", sss);
+ TestFailure("max-age=!20032", sss);
+ TestFailure("max-age==20032", sss);
+
+ // invalid headers
+ TestFailure("foobar", sss);
+ TestFailure("maxage=100", sss);
+ TestFailure("maxa-ge=100", sss);
+ TestFailure("max-ag=100", sss);
+ TestFailure("includesubdomains", sss);
+ TestFailure(";", sss);
+ TestFailure("max-age=\"100", sss);
+ // The max-age directive here doesn't conform to the spec, so it MUST
+ // be ignored. Consequently, the REQUIRED max-age directive is not
+ // present in this header, and so it is invalid.
+ TestFailure("max-age=100, max-age=200; includeSubdomains", sss);
+ TestFailure("max-age=100 includesubdomains", sss);
+ TestFailure("max-age=100 bar foo", sss);
+ TestFailure("max-age=100randomstuffhere", sss);
+ // All directives MUST appear only once in an STS header field.
+ TestFailure("max-age=100; max-age=200", sss);
+ TestFailure("includeSubdomains; max-age=200; includeSubdomains", sss);
+ TestFailure("max-age=200; includeSubdomains; includeSubdomains", sss);
+ // The includeSubdomains directive is valueless.
+ TestFailure("max-age=100; includeSubdomains=unexpected", sss);
+ // LWS must have at least one space or horizontal tab
+ TestFailure("\r\nmax-age=200", sss);
+}
diff --git a/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp b/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
new file mode 100644
index 000000000..65f5257fb
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
@@ -0,0 +1,568 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsNSSIOLayer.h"
+#include "sslproto.h"
+#include "sslerr.h"
+
+#include "gtest/gtest.h"
+
+NS_NAMED_LITERAL_CSTRING(HOST, "example.org");
+const int16_t PORT = 443;
+
+class psm_TLSIntoleranceTest : public ::testing::Test
+{
+protected:
+ nsSSLIOLayerHelpers helpers;
+};
+
+TEST_F(psm_TLSIntoleranceTest, FullFallbackProcess)
+{
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, helpers.mVersionFallbackLimit);
+
+ // No adjustment made when there is no entry for the site.
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
+
+ ASSERT_TRUE(
+ helpers.rememberStrongCiphersFailed(
+ HOST, PORT, SSL_ERROR_NO_CYPHER_OVERLAP));
+ ASSERT_EQ(SSL_ERROR_NO_CYPHER_OVERLAP,
+ helpers.getIntoleranceReason(HOST, PORT));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+
+ ASSERT_FALSE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ range.min, range.max, 0));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+
+ ASSERT_FALSE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ range.min, range.max, 0));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.max);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+
+ ASSERT_FALSE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ range.min, range.max, 0));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ // When rememberIntolerantAtVersion returns false, it also resets the
+ // intolerance information for the server.
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
+ }
+}
+
+TEST_F(psm_TLSIntoleranceTest, DisableFallbackWithHighLimit)
+{
+ // this value disables version fallback entirely: with this value, all efforts
+ // to mark an origin as version intolerant fail
+ helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_2;
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ 0));
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ 0));
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ 0));
+}
+
+TEST_F(psm_TLSIntoleranceTest, FallbackLimitBelowMin)
+{
+ // check that we still respect the minimum version,
+ // when it is higher than the fallback limit
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ 0));
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+ ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
+ }
+
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ 0));
+}
+
+TEST_F(psm_TLSIntoleranceTest, TolerantOverridesIntolerant1)
+{
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ 0));
+ helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+ ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
+}
+
+TEST_F(psm_TLSIntoleranceTest, TolerantOverridesIntolerant2)
+{
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ 0));
+ helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_2);
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
+}
+
+TEST_F(psm_TLSIntoleranceTest, IntolerantDoesNotOverrideTolerant)
+{
+ // No adjustment made when there is no entry for the site.
+ helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
+ // false because we reached the floor set by rememberTolerantAtVersion.
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ 0));
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
+}
+
+TEST_F(psm_TLSIntoleranceTest, PortIsRelevant)
+{
+ helpers.rememberTolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_2);
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, 1,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ 0));
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, 2,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ 0));
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, 1, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, 2, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+ }
+}
+
+TEST_F(psm_TLSIntoleranceTest, IntoleranceReasonInitial)
+{
+ ASSERT_EQ(0, helpers.getIntoleranceReason(HOST, 1));
+
+ helpers.rememberTolerantAtVersion(HOST, 2, SSL_LIBRARY_VERSION_TLS_1_2);
+ ASSERT_EQ(0, helpers.getIntoleranceReason(HOST, 2));
+}
+
+TEST_F(psm_TLSIntoleranceTest, IntoleranceReasonStored)
+{
+ helpers.rememberIntolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_ERROR_BAD_SERVER);
+ ASSERT_EQ(SSL_ERROR_BAD_SERVER, helpers.getIntoleranceReason(HOST, 1));
+
+ helpers.rememberIntolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ SSL_ERROR_BAD_MAC_READ);
+ ASSERT_EQ(SSL_ERROR_BAD_MAC_READ, helpers.getIntoleranceReason(HOST, 1));
+}
+
+TEST_F(psm_TLSIntoleranceTest, IntoleranceReasonCleared)
+{
+ ASSERT_EQ(0, helpers.getIntoleranceReason(HOST, 1));
+
+ helpers.rememberIntolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
+ ASSERT_EQ(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT,
+ helpers.getIntoleranceReason(HOST, 1));
+
+ helpers.rememberTolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_2);
+ ASSERT_EQ(0, helpers.getIntoleranceReason(HOST, 1));
+}
+
+TEST_F(psm_TLSIntoleranceTest, StrongCiphersFailed)
+{
+ helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_1;
+
+ ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ range.min, range.max, 0));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ range.min, range.max, 0));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ // When rememberIntolerantAtVersion returns false, it also resets the
+ // intolerance information for the server.
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
+ }
+}
+
+TEST_F(psm_TLSIntoleranceTest, StrongCiphersFailedAt1_1)
+{
+ helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_0;
+
+ // No adjustment made when there is no entry for the site.
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ range.min, range.max, 0));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ range.min, range.max, 0));
+ }
+
+ {
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.max);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+ }
+}
+
+TEST_F(psm_TLSIntoleranceTest, StrongCiphersFailedWithHighLimit)
+{
+ // this value disables version fallback entirely: with this value, all efforts
+ // to mark an origin as version intolerant fail
+ helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_2;
+ // ...but weak ciphers fallback will not be disabled
+ ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ 0));
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_1,
+ 0));
+ ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ 0));
+}
+
+TEST_F(psm_TLSIntoleranceTest, TolerantDoesNotOverrideWeakCiphersFallback)
+{
+ ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+ // No adjustment made when intolerant is zero.
+ helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+}
+
+TEST_F(psm_TLSIntoleranceTest, WeakCiphersFallbackDoesNotOverrideTolerant)
+{
+ // No adjustment made when there is no entry for the site.
+ helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
+ // false because strongCipherWorked is set by rememberTolerantAtVersion.
+ ASSERT_FALSE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
+}
+
+TEST_F(psm_TLSIntoleranceTest, TLSForgetIntolerance)
+{
+ {
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ 0));
+
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+ ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
+ }
+
+ {
+ helpers.forgetIntolerance(HOST, PORT);
+
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
+ }
+}
+
+TEST_F(psm_TLSIntoleranceTest, TLSForgetStrongCipherFailed)
+{
+ {
+ ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
+
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(StrongCiphersFailed, strongCipherStatus);
+ }
+
+ {
+ helpers.forgetIntolerance(HOST, PORT);
+
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
+ }
+}
+
+TEST_F(psm_TLSIntoleranceTest, TLSDontForgetTolerance)
+{
+ {
+ helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
+
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
+ }
+
+ {
+ ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+ SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2,
+ 0));
+
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+ ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
+ }
+
+ {
+ helpers.forgetIntolerance(HOST, PORT);
+
+ SSLVersionRange range = { SSL_LIBRARY_VERSION_TLS_1_0,
+ SSL_LIBRARY_VERSION_TLS_1_2 };
+ StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
+ helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.min);
+ ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+ ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
+ }
+}
+
+TEST_F(psm_TLSIntoleranceTest, TLSPerSiteFallbackLimit)
+{
+ NS_NAMED_LITERAL_CSTRING(example_com, "example.com");
+ NS_NAMED_LITERAL_CSTRING(example_net, "example.net");
+ NS_NAMED_LITERAL_CSTRING(example_org, "example.org");
+
+ helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_0;
+
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+ helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_2;
+
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+ helpers.setInsecureFallbackSites(example_com);
+
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+ helpers.setInsecureFallbackSites(NS_LITERAL_CSTRING("example.com,example.net"));
+
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+ helpers.setInsecureFallbackSites(example_net);
+
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+ helpers.setInsecureFallbackSites(EmptyCString());
+
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+ ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+}
diff --git a/security/manager/ssl/tests/gtest/moz.build b/security/manager/ssl/tests/gtest/moz.build
new file mode 100644
index 000000000..735ab2971
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+ 'CertDBTest.cpp',
+ 'DataStorageTest.cpp',
+ 'DeserializeCertTest.cpp',
+ 'MD4Test.cpp',
+ 'OCSPCacheTest.cpp',
+ 'STSParserTest.cpp',
+ 'TLSIntoleranceTest.cpp',
+]
+
+LOCAL_INCLUDES += [
+ '/security/certverifier',
+ '/security/manager/ssl',
+ '/security/pkix/include',
+ '/security/pkix/test/lib',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul-gtest'
+
+if CONFIG['GNU_CXX']:
+ CXXFLAGS += ['-Wno-error=shadow']
diff --git a/security/manager/ssl/tests/mochitest/browser/.eslintrc.js b/security/manager/ssl/tests/mochitest/browser/.eslintrc.js
new file mode 100644
index 000000000..c15988365
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/.eslintrc.js
@@ -0,0 +1,5 @@
+"use strict";
+
+module.exports = { // eslint-disable-line no-undef
+ "extends": "../../../../../../testing/mochitest/browser.eslintrc.js"
+};
diff --git a/security/manager/ssl/tests/mochitest/browser/browser.ini b/security/manager/ssl/tests/mochitest/browser/browser.ini
new file mode 100644
index 000000000..3c91ceb80
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser.ini
@@ -0,0 +1,18 @@
+[DEFAULT]
+tags = psm
+support-files =
+ head.js
+ *.pem
+
+[browser_bug627234_perwindowpb.js]
+[browser_certificateManagerLeak.js]
+[browser_certViewer.js]
+[browser_clientAuth_connection.js]
+[browser_clientAuth_ui.js]
+[browser_deleteCert_ui.js]
+[browser_downloadCert_ui.js]
+[browser_editCACertTrust.js]
+# An earlier attempt at landing this test resulted in frequent intermittent
+# failures, almost entirely on Linux. See Bug 1309519.
+skip-if = os == "linux"
+[browser_exportP12_passwordUI.js]
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js b/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
new file mode 100644
index 000000000..081521ca9
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
@@ -0,0 +1,102 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+var FakeSSLStatus = function() {
+};
+
+FakeSSLStatus.prototype = {
+ serverCert: null,
+ cipherName: null,
+ keyLength: 2048,
+ isDomainMismatch: false,
+ isNotValidAtThisTime: false,
+ isUntrusted: false,
+ isExtendedValidation: false,
+ getInterface: function(aIID) {
+ return this.QueryInterface(aIID);
+ },
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Ci.nsISSLStatus) ||
+ aIID.equals(Ci.nsISupports)) {
+ return this;
+ }
+ throw new Error(Cr.NS_ERROR_NO_INTERFACE);
+ },
+};
+
+function whenNewWindowLoaded(aOptions, aCallback) {
+ let win = OpenBrowserWindow(aOptions);
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad, false);
+ aCallback(win);
+ }, false);
+}
+
+// This is a template to help porting global private browsing tests
+// to per-window private browsing tests
+function test() {
+ // initialization
+ waitForExplicitFinish();
+ let windowsToClose = [];
+ let testURI = "about:blank";
+ let uri;
+ let gSSService = Cc["@mozilla.org/ssservice;1"].
+ getService(Ci.nsISiteSecurityService);
+
+ function privacyFlags(aIsPrivateMode) {
+ return aIsPrivateMode ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
+ }
+
+ function doTest(aIsPrivateMode, aWindow, aCallback) {
+ aWindow.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+ aWindow.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+ let sslStatus = new FakeSSLStatus();
+ uri = aWindow.Services.io.newURI("https://localhost/img.png", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1000", sslStatus, privacyFlags(aIsPrivateMode));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS, "localhost", privacyFlags(aIsPrivateMode)), "checking sts host");
+
+ aCallback();
+ }, true);
+
+ aWindow.gBrowser.selectedBrowser.loadURI(testURI);
+ }
+
+ function testOnWindow(aOptions, aCallback) {
+ whenNewWindowLoaded(aOptions, function(aWin) {
+ windowsToClose.push(aWin);
+ // execute should only be called when need, like when you are opening
+ // web pages on the test. If calling executeSoon() is not necesary, then
+ // call whenNewWindowLoaded() instead of testOnWindow() on your test.
+ executeSoon(function() { aCallback(aWin); });
+ });
+ }
+
+ // this function is called after calling finish() on the test.
+ registerCleanupFunction(function() {
+ windowsToClose.forEach(function(aWin) {
+ aWin.close();
+ });
+ uri = Services.io.newURI("http://localhost", null, null);
+ gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
+ });
+
+ // test first when on private mode
+ testOnWindow({private: true}, function(aWin) {
+ doTest(true, aWin, function() {
+ //test when not on private mode
+ testOnWindow({}, function(aWin) {
+ doTest(false, aWin, function() {
+ //test again when on private mode
+ testOnWindow({private: true}, function(aWin) {
+ doTest(true, aWin, function () {
+ finish();
+ });
+ });
+ });
+ });
+ });
+ });
+}
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_certViewer.js b/security/manager/ssl/tests/mochitest/browser/browser_certViewer.js
new file mode 100644
index 000000000..d75f9f207
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_certViewer.js
@@ -0,0 +1,224 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Repeatedly opens the certificate viewer dialog with various certificates and
+// determines that the viewer correctly identifies either what usages those
+// certificates are valid for or what errors prevented the certificates from
+// being verified.
+
+var { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
+
+add_task(function* testCAandTitle() {
+ let cert = yield readCertificate("ca.pem", "CTu,CTu,CTu");
+ let win = yield displayCertificate(cert);
+ checkUsages(win, ["SSL Certificate Authority"]);
+
+ // There's no real need to test the title for every cert, so we just test it
+ // once here.
+ Assert.equal(win.document.title, "Certificate Viewer: \u201Cca\u201D",
+ "Actual and expected title should match");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testSSLEndEntity() {
+ let cert = yield readCertificate("ssl-ee.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkUsages(win, ["SSL Server Certificate", "SSL Client Certificate"]);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testEmailEndEntity() {
+ let cert = yield readCertificate("email-ee.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkUsages(win, ["Email Recipient Certificate", "Email Signer Certificate"]);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testCodeSignEndEntity() {
+ let cert = yield readCertificate("code-ee.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkUsages(win, ["Object Signer"]);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testExpired() {
+ let cert = yield readCertificate("expired-ca.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win, "Could not verify this certificate because it has expired.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testIssuerExpired() {
+ let cert = yield readCertificate("ee-from-expired-ca.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because the CA certificate " +
+ "is invalid.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testUnknownIssuer() {
+ let cert = yield readCertificate("unknown-issuer.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because the issuer is " +
+ "unknown.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testInsecureAlgo() {
+ let cert = yield readCertificate("md5-ee.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because it was signed using " +
+ "a signature algorithm that was disabled because that algorithm " +
+ "is not secure.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testUntrusted() {
+ let cert = yield readCertificate("untrusted-ca.pem", "p,p,p");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because it is not trusted.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testUntrustedIssuer() {
+ let cert = yield readCertificate("ee-from-untrusted-ca.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win,
+ "Could not verify this certificate because the issuer is not " +
+ "trusted.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testRevoked() {
+ // Note that there's currently no way to un-do this. This should only be a
+ // problem if another test re-uses a certificate with this same key (perhaps
+ // likely) and subject (less likely).
+ let certBlocklist = Cc["@mozilla.org/security/certblocklist;1"]
+ .getService(Ci.nsICertBlocklist);
+ certBlocklist.revokeCertBySubjectAndPubKey(
+ "MBIxEDAOBgNVBAMMB3Jldm9rZWQ=", // CN=revoked
+ "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8="); // hash of the shared key
+ let cert = yield readCertificate("revoked.pem", ",,");
+ let win = yield displayCertificate(cert);
+ // As of bug 1312827, OneCRL only applies to TLS web server certificates, so
+ // this certificate will actually verify successfully for every end-entity
+ // usage except TLS web server.
+ checkUsages(win, ["Email Recipient Certificate", "Email Signer Certificate",
+ "Object Signer", "SSL Client Certificate"]);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+add_task(function* testInvalid() {
+ // This certificate has a keyUsage extension asserting cRLSign and
+ // keyCertSign, but it doesn't have a basicConstraints extension. This
+ // shouldn't be valid for any usage. Sadly, we give a pretty lame error
+ // message in this case.
+ let cert = yield readCertificate("invalid.pem", ",,");
+ let win = yield displayCertificate(cert);
+ checkError(win, "Could not verify this certificate for unknown reasons.");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+/**
+ * Given a certificate, returns a promise that will resolve when the certificate
+ * viewer has opened is displaying that certificate, and has finished
+ * determining its valid usages.
+ *
+ * @param {nsIX509Cert} certificate
+ * The certificate to view and determine usages for.
+ * @return {Promise}
+ * A promise that will resolve with a handle on the opened certificate
+ * viewer window when the usages have been determined.
+ */
+function displayCertificate(certificate) {
+ let win = window.openDialog("chrome://pippki/content/certViewer.xul", "",
+ "", certificate);
+ return TestUtils.topicObserved("ViewCertDetails:CertUsagesDone",
+ (subject, data) => subject == win)
+ .then(([subject, data]) => subject, error => { throw error; });
+}
+
+/**
+ * Given a certificate viewer window, finds the usages the certificate is valid
+ * for.
+ *
+ * @param {window} win
+ * The certificate viewer window.
+ * @return {String[]}
+ * An array of strings describing the usages the certificate is valid
+ * for.
+ */
+function getUsages(win) {
+ let determinedUsages = [];
+ let verifyInfoBox = win.document.getElementById("verify_info_box");
+ Array.from(verifyInfoBox.children).forEach(child => {
+ if (child.getAttribute("hidden") != "true" &&
+ child.getAttribute("id") != "verified") {
+ determinedUsages.push(child.getAttribute("value"));
+ }
+ });
+ return determinedUsages.sort();
+}
+
+/**
+ * Given a certificate viewer window, returns the error string describing a
+ * failure encountered when determining the certificate's usages. It will be
+ * "This certificate has been verified for the following uses:" when the
+ * certificate has successfully verified for at least one usage.
+ *
+ * @param {window} win
+ * The certificate viewer window.
+ * @return {String}
+ * A string describing the error encountered, or the success message if
+ * the certificate is valid for at least one usage.
+ */
+function getError(win) {
+ return win.document.getElementById("verified").textContent;
+}
+
+/**
+ * Given a certificate viewer window and an array of expected usage
+ * descriptions, verifies that the window is actually showing that the
+ * certificate has validated for those usages.
+ *
+ * @param {window} win
+ * The certificate viewer window.
+ * @param {String[]} usages
+ * An array of expected usage descriptions.
+ */
+function checkUsages(win, usages) {
+ Assert.equal(getError(win),
+ "This certificate has been verified for the following uses:",
+ "should have successful verification message");
+ let determinedUsages = getUsages(win);
+ usages.sort();
+ Assert.equal(determinedUsages.length, usages.length,
+ "number of usages as determined by cert viewer should be equal");
+ while (usages.length > 0) {
+ Assert.equal(determinedUsages.pop(), usages.pop(),
+ "usages as determined by cert viewer should be equal");
+ }
+}
+
+/**
+ * Given a certificate viewer window and an expected error, verifies that the
+ * window is actually showing that error.
+ *
+ * @param {window} win
+ * The certificate viewer window.
+ * @param {String} error
+ * The expected error message.
+ */
+function checkError(win, error) {
+ let determinedUsages = getUsages(win);
+ Assert.equal(determinedUsages.length, 0,
+ "should not have any successful usages in error case");
+ Assert.equal(getError(win), error,
+ "determined error should be the same as expected error");
+}
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_certificateManagerLeak.js b/security/manager/ssl/tests/mochitest/browser/browser_certificateManagerLeak.js
new file mode 100644
index 000000000..d1db319d0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_certificateManagerLeak.js
@@ -0,0 +1,32 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+var gBugWindow;
+
+function onLoad() {
+ gBugWindow.removeEventListener("load", onLoad);
+ gBugWindow.addEventListener("unload", onUnload);
+ gBugWindow.close();
+}
+
+function onUnload() {
+ gBugWindow.removeEventListener("unload", onUnload);
+ window.focus();
+ finish();
+}
+
+// This test opens and then closes the certificate manager to test that it
+// does not leak. The test harness keeps track of and reports leaks, so
+// there are no actual checks here.
+function test() {
+ waitForExplicitFinish();
+
+ // This test relies on the test timing out in order to indicate failure so
+ // let's add a dummy pass.
+ ok(true, "Each test requires at least one pass, fail or todo so here is a pass.");
+
+ gBugWindow = window.openDialog("chrome://pippki/content/certManager.xul");
+ gBugWindow.addEventListener("load", onLoad);
+}
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_connection.js b/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_connection.js
new file mode 100644
index 000000000..6362fd34d
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_connection.js
@@ -0,0 +1,135 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests various scenarios connecting to a server that requires client cert
+// authentication. Also tests that nsIClientAuthDialogs.chooseCertificate
+// is called at the appropriate times and with the correct arguments.
+
+const { MockRegistrar } =
+ Cu.import("resource://testing-common/MockRegistrar.jsm", {});
+
+const DialogState = {
+ // Assert that chooseCertificate() is never called.
+ ASSERT_NOT_CALLED: "ASSERT_NOT_CALLED",
+ // Return that the user selected the first given cert.
+ RETURN_CERT_SELECTED: "RETURN_CERT_SELECTED",
+ // Return that the user canceled.
+ RETURN_CERT_NOT_SELECTED: "RETURN_CERT_NOT_SELECTED",
+};
+
+let sdr = Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing);
+
+// Mock implementation of nsIClientAuthDialogs.
+const gClientAuthDialogs = {
+ _state: DialogState.ASSERT_NOT_CALLED,
+
+ set state(newState) {
+ info(`old state: ${this._state}`);
+ this._state = newState;
+ info(`new state: ${this._state}`);
+ },
+
+ get state() {
+ return this._state;
+ },
+
+ chooseCertificate(ctx, hostname, port, organization, issuerOrg, certList,
+ selectedIndex) {
+ Assert.notEqual(this.state, DialogState.ASSERT_NOT_CALLED,
+ "chooseCertificate() should be called only when expected");
+
+ let caud = ctx.QueryInterface(Ci.nsIClientAuthUserDecision);
+ Assert.notEqual(caud, null,
+ "nsIClientAuthUserDecision should be queryable from the " +
+ "given context");
+ caud.rememberClientAuthCertificate = false;
+
+ Assert.equal(hostname, "requireclientcert.example.com",
+ "Hostname should be 'requireclientcert.example.com'");
+ Assert.equal(port, 443, "Port should be 443");
+ Assert.equal(organization, "",
+ "Server cert Organization should be empty/not present");
+ Assert.equal(issuerOrg, "Mozilla Testing",
+ "Server cert issuer Organization should be 'Mozilla Testing'");
+
+ // For mochitests, only the cert at build/pgo/certs/mochitest.client should
+ // be selectable, so we do some brief checks to confirm this.
+ Assert.notEqual(certList, null, "Cert list should not be null");
+ Assert.equal(certList.length, 1, "Only 1 certificate should be available");
+ let cert = certList.queryElementAt(0, Ci.nsIX509Cert);
+ Assert.notEqual(cert, null, "Cert list should contain an nsIX509Cert");
+ Assert.equal(cert.commonName, "Mochitest client",
+ "Cert CN should be 'Mochitest client'");
+
+ if (this.state == DialogState.RETURN_CERT_SELECTED) {
+ selectedIndex.value = 0;
+ return true;
+ }
+ return false;
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIClientAuthDialogs])
+};
+
+add_task(function* setup() {
+ let clientAuthDialogsCID =
+ MockRegistrar.register("@mozilla.org/nsClientAuthDialogs;1",
+ gClientAuthDialogs);
+ registerCleanupFunction(() => {
+ MockRegistrar.unregister(clientAuthDialogsCID);
+ });
+});
+
+/**
+ * Test helper for the tests below.
+ *
+ * @param {String} prefValue
+ * Value to set the "security.default_personal_cert" pref to.
+ * @param {String} expectedURL
+ * If the connection is expected to load successfully, the URL that
+ * should load. If the connection is expected to fail and result in an
+ * error page, |undefined|.
+ */
+function* testHelper(prefValue, expectedURL) {
+ yield SpecialPowers.pushPrefEnv({"set": [
+ ["security.default_personal_cert", prefValue],
+ ]});
+
+ yield BrowserTestUtils.loadURI(gBrowser.selectedBrowser,
+ "https://requireclientcert.example.com:443");
+
+ // |loadedURL| will be a string URL if browserLoaded() wins the race, or
+ // |undefined| if waitForErrorPage() wins the race.
+ let loadedURL = yield Promise.race([
+ BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser),
+ BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser),
+ ]);
+ Assert.equal(expectedURL, loadedURL, "Expected and actual URLs should match");
+
+ // Ensure previously successful connections don't influence future tests.
+ sdr.logoutAndTeardown();
+}
+
+// Test that if a certificate is chosen automatically the connection succeeds,
+// and that nsIClientAuthDialogs.chooseCertificate() is never called.
+add_task(function* testCertChosenAutomatically() {
+ gClientAuthDialogs.state = DialogState.ASSERT_NOT_CALLED;
+ yield* testHelper("Select Automatically",
+ "https://requireclientcert.example.com/");
+});
+
+// Test that if the user doesn't choose a certificate, the connection fails and
+// an error page is displayed.
+add_task(function* testCertNotChosenByUser() {
+ gClientAuthDialogs.state = DialogState.RETURN_CERT_NOT_SELECTED;
+ yield* testHelper("Ask Every Time", undefined);
+});
+
+// Test that if the user chooses a certificate the connection suceeeds.
+add_task(function* testCertChosenByUser() {
+ gClientAuthDialogs.state = DialogState.RETURN_CERT_SELECTED;
+ yield* testHelper("Ask Every Time",
+ "https://requireclientcert.example.com/");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_ui.js b/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_ui.js
new file mode 100644
index 000000000..bf4f179c0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_clientAuth_ui.js
@@ -0,0 +1,137 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that the client authentication certificate chooser correctly displays
+// provided information and correctly returns user input.
+
+const TEST_HOSTNAME = "Test Hostname";
+const TEST_ORG = "Test Org";
+const TEST_ISSUER_ORG = "Test Issuer Org";
+const TEST_PORT = 123;
+
+var certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+/**
+ * Test certificate (i.e. build/pgo/certs/mochitest.client).
+ * @type nsIX509Cert
+ */
+var cert;
+
+/**
+ * Opens the client auth cert chooser dialog.
+ *
+ * @param {nsIX509Cert} cert The cert to pass to the dialog for display.
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading, with
+ * an array consisting of:
+ * 1. The window of the opened dialog.
+ * 2. The return value nsIWritablePropertyBag2 passed to the dialog.
+ */
+function openClientAuthDialog(cert) {
+ let certList = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
+ certList.appendElement(cert, false);
+
+ let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
+ .createInstance(Ci.nsIWritablePropertyBag2);
+ let win = window.openDialog("chrome://pippki/content/clientauthask.xul", "",
+ "", TEST_HOSTNAME, TEST_ORG, TEST_ISSUER_ORG,
+ TEST_PORT, certList, returnVals);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve([win, returnVals]);
+ });
+ });
+}
+
+/**
+ * Checks that the contents of the given cert chooser dialog match the details
+ * of build/pgo/certs/mochitest.client.
+ *
+ * @param {window} win The cert chooser window.
+ * @param {String} notBefore
+ * The notBeforeLocalTime attribute of mochitest.client.
+ * @param {String} notAfter
+ * The notAfterLocalTime attribute of mochitest.client.
+ */
+function checkDialogContents(win, notBefore, notAfter) {
+ Assert.equal(win.document.getElementById("hostname").textContent,
+ `${TEST_HOSTNAME}:${TEST_PORT}`,
+ "Actual and expected hostname and port should be equal");
+ // “ and ” don't seem to work when embedded in the following literals, which
+ // is why escape codes are used instead.
+ Assert.equal(win.document.getElementById("organization").textContent,
+ `Organization: \u201C${TEST_ORG}\u201D`,
+ "Actual and expected organization should be equal");
+ Assert.equal(win.document.getElementById("issuer").textContent,
+ `Issued Under: \u201C${TEST_ISSUER_ORG}\u201D`,
+ "Actual and expected issuer organization should be equal");
+
+ Assert.equal(win.document.getElementById("nicknames").label,
+ "test client certificate [03]",
+ "Actual and expected selected cert nickname and serial should " +
+ "be equal");
+
+ let [subject, serialNum, validity, issuer, tokenName] =
+ win.document.getElementById("details").value.split("\n");
+ Assert.equal(subject, "Issued to: CN=Mochitest client",
+ "Actual and expected subject should be equal");
+ Assert.equal(serialNum, "Serial number: 03",
+ "Actual and expected serial number should be equal");
+ Assert.equal(validity, `Valid from ${notBefore} to ${notAfter}`,
+ "Actual and expected validity should be equal");
+ Assert.equal(issuer,
+ "Issued by: CN=Temporary Certificate Authority,O=Mozilla " +
+ "Testing,OU=Profile Guided Optimization",
+ "Actual and expected issuer should be equal");
+ Assert.equal(tokenName, "Stored on: Software Security Device",
+ "Actual and expected token name should be equal");
+}
+
+add_task(function* setup() {
+ cert = certDB.findCertByNickname("test client certificate");
+ Assert.notEqual(cert, null, "Should be able to find the test client cert");
+});
+
+// Test that the contents of the dialog correspond to the details of the
+// provided cert.
+add_task(function* testContents() {
+ let [win, retVals] = yield openClientAuthDialog(cert);
+ checkDialogContents(win, cert.validity.notBeforeLocalTime,
+ cert.validity.notAfterLocalTime);
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+// Test that the right values are returned when the dialog is accepted.
+add_task(function* testAcceptDialogReturnValues() {
+ let [win, retVals] = yield openClientAuthDialog(cert);
+ win.document.getElementById("rememberBox").checked = true;
+ info("Accepting dialog");
+ win.document.getElementById("certAuthAsk").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(retVals.get("certChosen"),
+ "Return value should signal user chose a certificate");
+ Assert.equal(retVals.get("selectedIndex"), 0,
+ "0 should be returned as the selected index");
+ Assert.ok(retVals.get("rememberSelection"),
+ "Return value should signal 'Remember this decision' checkbox was" +
+ "checked");
+});
+
+// Test that the right values are returned when the dialog is canceled.
+add_task(function* testCancelDialogReturnValues() {
+ let [win, retVals] = yield openClientAuthDialog(cert);
+ win.document.getElementById("rememberBox").checked = false;
+ info("Canceling dialog");
+ win.document.getElementById("certAuthAsk").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!retVals.get("certChosen"),
+ "Return value should signal user did not choose a certificate");
+ Assert.ok(!retVals.get("rememberSelection"),
+ "Return value should signal 'Remember this decision' checkbox was" +
+ "unchecked");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js b/security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js
new file mode 100644
index 000000000..b0ac8f95c
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js
@@ -0,0 +1,215 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests various aspects of the cert delete confirmation dialog.
+// Among other things, tests that for each type of cert that can be deleted:
+// 1. The various lines of explanation text are correctly set.
+// 2. The implementation correctly falls back through multiple cert attributes
+// to determine what to display to represent a cert.
+
+/**
+ * An array of tree items corresponding to TEST_CASES.
+ * @type nsICertTreeItem[]
+ */
+var gCertArray = [];
+
+const FAKE_HOST_PORT = "Fake host and port";
+
+/**
+ * @typedef {TestCase}
+ * @type Object
+ * @property {String} certFilename
+ * Filename of the cert, or null if we don't want to import a cert for
+ * this test case (i.e. we expect the hostPort attribute of
+ * nsICertTreeItem to be used).
+ * @property {String} expectedDisplayString
+ * The string we expect the UI to display to represent the given cert.
+ */
+
+/**
+ * A list of test cases representing certs that get "deleted".
+ * @type TestCase[]
+ */
+const TEST_CASES = [
+ { certFilename: null,
+ expectedDisplayString: FAKE_HOST_PORT },
+ { certFilename: "has-cn.pem",
+ expectedDisplayString: "Foo" },
+ { certFilename: "has-ou.pem",
+ expectedDisplayString: "Bar" },
+ { certFilename: "has-o.pem",
+ expectedDisplayString: "Baz" },
+ { certFilename: "has-non-empty-subject.pem",
+ expectedDisplayString: "C=US" },
+ { certFilename: "has-empty-subject.pem",
+ expectedDisplayString: "Certificate with serial number: 0A" },
+];
+
+/**
+ * Opens the cert delete confirmation dialog.
+ *
+ * @param {String} tabID
+ * The ID of the cert category tab the certs to delete belong to.
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading, with
+ * an array consisting of:
+ * 1. The window of the opened dialog.
+ * 2. The return value object passed to the dialog.
+ */
+function openDeleteCertConfirmDialog(tabID) {
+ let retVals = {
+ deleteConfirmed: false,
+ };
+ let win = window.openDialog("chrome://pippki/content/deletecert.xul", "", "",
+ tabID, gCertArray, retVals);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve([win, retVals]);
+ });
+ });
+}
+
+add_task(function* setup() {
+ for (let testCase of TEST_CASES) {
+ let cert = null;
+ if (testCase.certFilename) {
+ cert = yield readCertificate(testCase.certFilename, ",,");
+ }
+ let certTreeItem = {
+ hostPort: FAKE_HOST_PORT,
+ cert: cert,
+ QueryInterface(iid) {
+ if (iid.equals(Ci.nsICertTreeItem)) {
+ return this;
+ }
+
+ throw new Error(Cr.NS_ERROR_NO_INTERFACE);
+ }
+ };
+ gCertArray.push(certTreeItem);
+ }
+});
+
+/**
+ * Test helper for the below test cases.
+ *
+ * @param {String} tabID
+ * ID of the cert category tab the certs to delete belong to.
+ * @param {String} expectedTitle
+ * Title the dialog is expected to have.
+ * @param {String} expectedConfirmMsg
+ * Confirmation message the dialog is expected to show.
+ * @param {String} expectedImpact
+ * Impact the dialog is expected to show.
+ */
+function* testHelper(tabID, expectedTitle, expectedConfirmMsg, expectedImpact) {
+ let [win, retVals] = yield openDeleteCertConfirmDialog(tabID);
+ let certList = win.document.getElementById("certlist");
+
+ Assert.equal(win.document.title, expectedTitle,
+ `Actual and expected titles should match for ${tabID}`);
+ Assert.equal(win.document.getElementById("confirm").textContent,
+ expectedConfirmMsg,
+ `Actual and expected confirm message should match for ${tabID}`);
+ Assert.equal(win.document.getElementById("impact").textContent,
+ expectedImpact,
+ `Actual and expected impact should match for ${tabID}`);
+
+ Assert.equal(certList.itemCount, TEST_CASES.length,
+ `No. of certs displayed should match for ${tabID}`);
+ for (let i = 0; i < certList.itemCount; i++) {
+ Assert.equal(certList.getItemAtIndex(i).label,
+ TEST_CASES[i].expectedDisplayString,
+ "Actual and expected display string should match for " +
+ `index ${i} for ${tabID}`);
+ }
+
+ yield BrowserTestUtils.closeWindow(win);
+}
+
+// Test deleting certs from the "Your Certificates" tab.
+add_task(function* testDeletePersonalCerts() {
+ const expectedTitle = "Delete your Certificates";
+ const expectedConfirmMsg =
+ "Are you sure you want to delete these certificates?";
+ const expectedImpact =
+ "If you delete one of your own certificates, you can no longer use it to " +
+ "identify yourself.";
+ yield* testHelper("mine_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test deleting certs from the "People" tab.
+add_task(function* testDeleteOtherPeopleCerts() {
+ const expectedTitle = "Delete E-Mail Certificates";
+ // ’ doesn't seem to work when embedded in the following literals, which is
+ // why escape codes are used instead.
+ const expectedConfirmMsg =
+ "Are you sure you want to delete these people\u2019s e-mail certificates?";
+ const expectedImpact =
+ "If you delete a person\u2019s e-mail certificate, you will no longer be " +
+ "able to send encrypted e-mail to that person.";
+ yield* testHelper("others_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test deleting certs from the "Servers" tab.
+add_task(function* testDeleteServerCerts() {
+ const expectedTitle = "Delete Server Certificate Exceptions";
+ const expectedConfirmMsg =
+ "Are you sure you want to delete these server exceptions?";
+ const expectedImpact =
+ "If you delete a server exception, you restore the usual security checks " +
+ "for that server and require it uses a valid certificate.";
+ yield* testHelper("websites_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test deleting certs from the "Authorities" tab.
+add_task(function* testDeleteCACerts() {
+ const expectedTitle = "Delete or Distrust CA Certificates";
+ const expectedConfirmMsg =
+ "You have requested to delete these CA certificates. For built-in " +
+ "certificates all trust will be removed, which has the same effect. Are " +
+ "you sure you want to delete or distrust?";
+ const expectedImpact =
+ "If you delete or distrust a certificate authority (CA) certificate, " +
+ "this application will no longer trust any certificates issued by that CA.";
+ yield* testHelper("ca_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test deleting certs from the "Other" tab.
+add_task(function* testDeleteOtherCerts() {
+ const expectedTitle = "Delete Certificates";
+ const expectedConfirmMsg =
+ "Are you sure you want to delete these certificates?";
+ const expectedImpact = "";
+ yield* testHelper("orphan_tab", expectedTitle, expectedConfirmMsg,
+ expectedImpact);
+});
+
+// Test that the right values are returned when the dialog is accepted.
+add_task(function* testAcceptDialogReturnValues() {
+ let [win, retVals] = yield openDeleteCertConfirmDialog("ca_tab" /*arbitrary*/);
+ info("Accepting dialog");
+ win.document.getElementById("deleteCertificate").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(retVals.deleteConfirmed,
+ "Return value should signal user accepted");
+});
+
+// Test that the right values are returned when the dialog is canceled.
+add_task(function* testCancelDialogReturnValues() {
+ let [win, retVals] = yield openDeleteCertConfirmDialog("ca_tab" /*arbitrary*/);
+ info("Canceling dialog");
+ win.document.getElementById("deleteCertificate").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!retVals.deleteConfirmed,
+ "Return value should signal user did not accept");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js b/security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js
new file mode 100644
index 000000000..cbd59f883
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js
@@ -0,0 +1,150 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that the cert download/import UI correctly identifies the cert being
+// downloaded, and allows the trust of the cert to be specified.
+
+const { MockRegistrar } =
+ Cu.import("resource://testing-common/MockRegistrar.jsm", {});
+
+/**
+ * @typedef {TestCase}
+ * @type Object
+ * @property {String} certFilename
+ * Filename of the cert for this test case.
+ * @property {String} expectedDisplayString
+ * The string we expect the UI to display to represent the given cert.
+ * @property {nsIX509Cert} cert
+ * Handle to the cert once read in setup().
+ */
+
+/**
+ * A list of test cases representing certs that get "downloaded".
+ * @type TestCase[]
+ */
+const TEST_CASES = [
+ { certFilename: "has-cn.pem",
+ expectedDisplayString: "Foo",
+ cert: null },
+ { certFilename: "has-empty-subject.pem",
+ expectedDisplayString: "Certificate Authority (unnamed)",
+ cert: null },
+];
+
+/**
+ * Opens the cert download dialog.
+ *
+ * @param {nsIX509Cert} cert
+ * The cert to pass to the dialog for display.
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading, with
+ * an array consisting of:
+ * 1. The window of the opened dialog.
+ * 2. The return value nsIWritablePropertyBag2 passed to the dialog.
+ */
+function openCertDownloadDialog(cert) {
+ let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
+ .createInstance(Ci.nsIWritablePropertyBag2);
+ let win = window.openDialog("chrome://pippki/content/downloadcert.xul", "",
+ "", cert, returnVals);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve([win, returnVals]);
+ });
+ });
+}
+
+// Mock implementation of nsICertificateDialogs.
+const gCertificateDialogs = {
+ expectedCert: null,
+ viewCertCallCount: 0,
+ confirmDownloadCACert(ctx, cert, trust) {
+ Assert.ok(false, "confirmDownloadCACert() should not have been called");
+ },
+ setPKCS12FilePassword(ctx, password) {
+ Assert.ok(false, "setPKCS12FilePassword() should not have been called");
+ },
+ getPKCS12FilePassword(ctx, password) {
+ Assert.ok(false, "getPKCS12FilePassword() should not have been called");
+ },
+ viewCert(ctx, cert) {
+ this.viewCertCallCount++;
+ Assert.notEqual(cert, null, "Cert to view should not be null");
+ Assert.equal(cert, this.expectedCert,
+ "Actual and expected cert should match");
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs])
+};
+
+add_task(function* setup() {
+ for (let testCase of TEST_CASES) {
+ testCase.cert = yield readCertificate(testCase.certFilename, ",,");
+ Assert.notEqual(testCase.cert, null,
+ `'${testCase.certFilename}' should have been read`);
+ }
+
+ let certificateDialogsCID =
+ MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1",
+ gCertificateDialogs);
+ registerCleanupFunction(() => {
+ MockRegistrar.unregister(certificateDialogsCID);
+ });
+});
+
+// Test that the trust header message corresponds to the provided cert, and that
+// the View Cert button launches the cert viewer for the provided cert.
+add_task(function* testTrustHeaderAndViewCertButton() {
+ for (let testCase of TEST_CASES) {
+ let [win, retVals] = yield openCertDownloadDialog(testCase.cert);
+ let expectedTrustHeaderString =
+ `Do you want to trust \u201C${testCase.expectedDisplayString}\u201D ` +
+ "for the following purposes?";
+ Assert.equal(win.document.getElementById("trustHeader").textContent,
+ expectedTrustHeaderString,
+ "Actual and expected trust header text should match for " +
+ `${testCase.certFilename}`);
+
+ gCertificateDialogs.viewCertCallCount = 0;
+ gCertificateDialogs.expectedCert = testCase.cert;
+ info("Pressing View Cert button");
+ win.document.getElementById("viewC-button").doCommand();
+ Assert.equal(gCertificateDialogs.viewCertCallCount, 1,
+ "viewCert() should've been called once");
+
+ yield BrowserTestUtils.closeWindow(win);
+ }
+});
+
+// Test that the right values are returned when the dialog is accepted.
+add_task(function* testAcceptDialogReturnValues() {
+ let [win, retVals] = yield openCertDownloadDialog(TEST_CASES[0].cert);
+ win.document.getElementById("trustSSL").checked = true;
+ win.document.getElementById("trustEmail").checked = false;
+ win.document.getElementById("trustObjSign").checked = true;
+ info("Accepting dialog");
+ win.document.getElementById("download_cert").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(retVals.get("importConfirmed"),
+ "Return value should signal user chose to import the cert");
+ Assert.ok(retVals.get("trustForSSL"),
+ "Return value should signal SSL trust checkbox was checked");
+ Assert.ok(!retVals.get("trustForEmail"),
+ "Return value should signal E-mail trust checkbox was unchecked");
+ Assert.ok(retVals.get("trustForObjSign"),
+ "Return value should signal Obj Sign trust checkbox was checked");
+});
+
+// Test that the right values are returned when the dialog is canceled.
+add_task(function* testCancelDialogReturnValues() {
+ let [win, retVals] = yield openCertDownloadDialog(TEST_CASES[0].cert);
+ info("Canceling dialog");
+ win.document.getElementById("download_cert").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!retVals.get("importConfirmed"),
+ "Return value should signal user chose not to import the cert");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_editCACertTrust.js b/security/manager/ssl/tests/mochitest/browser/browser_editCACertTrust.js
new file mode 100644
index 000000000..bc87732a5
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_editCACertTrust.js
@@ -0,0 +1,119 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that the UI for editing the trust of a CA certificate correctly
+// reflects trust in the cert DB, and correctly updates trust in the cert DB
+// when requested.
+
+var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+/**
+ * The cert we're editing the trust of.
+ * @type nsIX509Cert
+ */
+var gCert;
+
+/**
+ * Opens the cert trust editing dialog.
+ *
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading with
+ * the window of the opened dialog.
+ */
+function openEditCertTrustDialog() {
+ let win = window.openDialog("chrome://pippki/content/editcacert.xul", "", "",
+ gCert);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve(win);
+ });
+ });
+}
+
+add_task(function* setup() {
+ // Initially trust ca.pem for SSL, but not e-mail or object signing.
+ gCert = yield readCertificate("ca.pem", "CT,,");
+ Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL),
+ "Sanity check: ca.pem should be trusted for SSL");
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_EMAIL),
+ "Sanity check: ca.pem should not be trusted for e-mail");
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_OBJSIGN),
+ "Sanity check: ca.pem should not be trusted for object signing");
+});
+
+// Tests the following:
+// 1. The checkboxes correctly reflect the trust set in setup().
+// 2. Accepting the dialog after flipping some of the checkboxes results in the
+// correct trust being set in the cert DB.
+add_task(function* testAcceptDialog() {
+ let win = yield openEditCertTrustDialog();
+
+ let sslCheckbox = win.document.getElementById("trustSSL");
+ let emailCheckbox = win.document.getElementById("trustEmail");
+ let objSignCheckbox = win.document.getElementById("trustObjSign");
+ Assert.ok(sslCheckbox.checked,
+ "Cert should be trusted for SSL in UI");
+ Assert.ok(!emailCheckbox.checked,
+ "Cert should not be trusted for e-mail in UI");
+ Assert.ok(!objSignCheckbox.checked,
+ "Cert should not be trusted for object signing in UI");
+
+ sslCheckbox.checked = false;
+ emailCheckbox.checked = true;
+
+ info("Accepting dialog");
+ win.document.getElementById("editCaCert").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL),
+ "Cert should no longer be trusted for SSL");
+ Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_EMAIL),
+ "Cert should now be trusted for e-mail");
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_OBJSIGN),
+ "Cert should still not be trusted for object signing");
+});
+
+// Tests the following:
+// 1. The checkboxes correctly reflect the trust set in testAcceptDialog().
+// 2. Canceling the dialog even after flipping the checkboxes doesn't result in
+// a change of trust in the cert DB.
+add_task(function* testCancelDialog() {
+ let win = yield openEditCertTrustDialog();
+
+ let sslCheckbox = win.document.getElementById("trustSSL");
+ let emailCheckbox = win.document.getElementById("trustEmail");
+ let objSignCheckbox = win.document.getElementById("trustObjSign");
+ Assert.ok(!sslCheckbox.checked,
+ "Cert should not be trusted for SSL in UI");
+ Assert.ok(emailCheckbox.checked,
+ "Cert should be trusted for e-mail in UI");
+ Assert.ok(!objSignCheckbox.checked,
+ "Cert should not be trusted for object signing in UI");
+
+ sslCheckbox.checked = true;
+ emailCheckbox.checked = false;
+ objSignCheckbox.checked = true;
+
+ info("Canceling dialog");
+ win.document.getElementById("editCaCert").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL),
+ "Cert should still not be trusted for SSL");
+ Assert.ok(gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_EMAIL),
+ "Cert should still be trusted for e-mail");
+ Assert.ok(!gCertDB.isCertTrusted(gCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_OBJSIGN),
+ "Cert should still not be trusted for object signing");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js b/security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js
new file mode 100644
index 000000000..fc7591ece
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js
@@ -0,0 +1,142 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that the UI for setting the password on a to be exported PKCS #12 file:
+// 1. Correctly requires the password to be typed in twice as confirmation.
+// 2. Calculates and displays the strength of said password.
+
+/**
+ * @typedef {TestCase}
+ * @type Object
+ * @property {String} name
+ * The name of the test case for display purposes.
+ * @property {String} password1
+ * The password to enter into the first password textbox.
+ * @property {String} password2
+ * The password to enter into the second password textbox.
+ * @property {String} strength
+ * The expected strength of the password in the range [0, 100].
+ */
+
+/**
+ * A list of test cases representing various inputs to the password textboxes.
+ * @type TestCase[]
+ */
+const TEST_CASES = [
+ { name: "empty",
+ password1: "",
+ password2: "",
+ strength: "0" },
+ { name: "match-weak",
+ password1: "foo",
+ password2: "foo",
+ strength: "10" },
+ { name: "match-medium",
+ password1: "foo123",
+ password2: "foo123",
+ strength: "60" },
+ { name: "match-strong",
+ password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
+ password2: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
+ strength: "100" },
+ { name: "mismatch-weak",
+ password1: "foo",
+ password2: "bar",
+ strength: "10" },
+ { name: "mismatch-medium",
+ password1: "foo123",
+ password2: "bar",
+ strength: "60" },
+ { name: "mismatch-strong",
+ password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三",
+ password2: "bar",
+ strength: "100" },
+];
+
+/**
+ * Opens the dialog shown to set the password on a PKCS #12 file being exported.
+ *
+ * @returns {Promise}
+ * A promise that resolves when the dialog has finished loading, with
+ * an array consisting of:
+ * 1. The window of the opened dialog.
+ * 2. The return value nsIWritablePropertyBag2 passed to the dialog.
+ */
+function openSetP12PasswordDialog() {
+ let returnVals = Cc["@mozilla.org/hash-property-bag;1"]
+ .createInstance(Ci.nsIWritablePropertyBag2);
+ let win = window.openDialog("chrome://pippki/content/setp12password.xul", "",
+ "", returnVals);
+ return new Promise((resolve, reject) => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ resolve([win, returnVals]);
+ });
+ });
+}
+
+// Tests that the first password textbox is the element that is initially
+// focused.
+add_task(function* testFocus() {
+ let [win, retVals] = yield openSetP12PasswordDialog();
+ Assert.equal(win.document.activeElement,
+ win.document.getElementById("pw1").inputField,
+ "First password textbox should have focus");
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+// Tests that the password strength algorithm used is reasonable, and that the
+// Accept button is only enabled if the two passwords match.
+add_task(function* testPasswordStrengthAndEquality() {
+ let [win, retVals] = yield openSetP12PasswordDialog();
+ let password1Textbox = win.document.getElementById("pw1");
+ let password2Textbox = win.document.getElementById("pw2");
+ let strengthProgressBar = win.document.getElementById("pwmeter");
+
+ for (let testCase of TEST_CASES) {
+ password1Textbox.value = testCase.password1;
+ password2Textbox.value = testCase.password2;
+ // Setting the value of the password textboxes via |.value| apparently
+ // doesn't cause the oninput handlers to be called, so we do it here.
+ password1Textbox.oninput();
+ password2Textbox.oninput();
+
+ Assert.equal(win.document.documentElement.getButton("accept").disabled,
+ password1Textbox.value != password2Textbox.value,
+ "Actual and expected accept button disable state should " +
+ `match for ${testCase.name}`);
+ Assert.equal(strengthProgressBar.value, testCase.strength,
+ "Actual and expected strength value should match for" +
+ `${testCase.name}`);
+ }
+
+ yield BrowserTestUtils.closeWindow(win);
+});
+
+// Test that the right values are returned when the dialog is accepted.
+add_task(function* testAcceptDialogReturnValues() {
+ let [win, retVals] = yield openSetP12PasswordDialog();
+ const password = "fooBAR 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三";
+ win.document.getElementById("pw1").value = password;
+ win.document.getElementById("pw2").value = password;
+ info("Accepting dialog");
+ win.document.getElementById("setp12password").acceptDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(retVals.get("confirmedPassword"),
+ "Return value should signal user confirmed a password");
+ Assert.equal(retVals.get("password"), password,
+ "Actual and expected password should match");
+});
+
+// Test that the right values are returned when the dialog is canceled.
+add_task(function* testCancelDialogReturnValues() {
+ let [win, retVals] = yield openSetP12PasswordDialog();
+ info("Canceling dialog");
+ win.document.getElementById("setp12password").cancelDialog();
+ yield BrowserTestUtils.windowClosed(win);
+
+ Assert.ok(!retVals.get("confirmedPassword"),
+ "Return value should signal user didn't confirm a password");
+});
diff --git a/security/manager/ssl/tests/mochitest/browser/ca.pem b/security/manager/ssl/tests/mochitest/browser/ca.pem
new file mode 100644
index 000000000..1a18e2bf0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUL5zykZEc2ro5d6th43aWGfm735cwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
+DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHPYBjNnv//Ssc8Elepb8SWIXRdahKbL
+/dcPoMR+7yhJVaelUaxdwUytJWJAGdkkuv+P+G4b82RVYEXT+9k1S/aAfByFyR9q
+vS7POfdy/ZPfGTXltlnmYX/84a6QeYQa4Nl4JpIOXBCesLxmErBhczka6D26iqsz
+GeseKRSjVPgF3mXc2CRGZnTDRhUmd7wOABLmj7GtuFvOm96363M3IUByMohvoj1G
+dic3s5D0seXwTKnEc5B27lJt7Q0oIXEldL+UW8Mo1hfGWQeXzqTZbpOVLnVWvHBH
+H8yYs5hyH01qFJZbztJ1JJ3F2NpYLlr4P5I6fW2e9w5MG/VMQRU3wzQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/ca.pem.certspec
new file mode 100644
index 000000000..6660f5d47
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/mochitest/browser/code-ee.pem b/security/manager/ssl/tests/mochitest/browser/code-ee.pem
new file mode 100644
index 000000000..a4fdfaed7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/code-ee.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxDCCAa6gAwIBAgIUSbYQoLY1s6wWqgbKhxQZ3XME7ukwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBIxEDAOBgNVBAMMB2NvZGUtZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjFzAVMBMGA1UdJQQMMAoGCCsG
+AQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAV69uBbyc/d1eBdZlT7eAw4onQzkdndd8
+kEXdmP3hd+jJm1+/F733IflLLqE5mmUL9l7q7EJ+TgdZa19T6JHEaVjdJcIuwJO/
+kKSJXXqADQXoxHOZADDWjAFStiR3xd78BzYfuUANgozG6hq7QuVh0cYBx/8Q9gx/
+pGtuCJiN0d2Mknu0SoQzIZlXTuqmnFj7G/88O5Yh5MaFZxbvIJJSIWQoS396GrI6
+yXAdqHNoVM9mwwaMcnG5QeeKSIPuvEkZncQsxFc0zqIjeOVx/zEx2Bocx71dLuVB
+fqrIrAXLpwparoSxLzNqq8UgtXF8NQOuAcUu7ok0r1VbdMbSZHZ3Gg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/code-ee.pem.certspec b/security/manager/ssl/tests/mochitest/browser/code-ee.pem.certspec
new file mode 100644
index 000000000..93f9a8426
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/code-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:code-ee
+extension:extKeyUsage:codeSigning
diff --git a/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem b/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem
new file mode 100644
index 000000000..5b2cfd940
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvjCCAaigAwIBAgIUGzSP8KEmmRm3sIPiyQW35sazlHEwCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCmV4cGlyZWQtY2EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowHTEbMBkGA1UEAwwSZWUtZnJvbS1leHBpcmVkLWNhMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq
+5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SSc
+An7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39
+ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYk
+zBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3u
+JtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQAB
+MAsGCSqGSIb3DQEBCwOCAQEAZ6Nrb/1fit8cALMhcbmuZ5kd3J34d0o9p3g3E7m7
+8RsTbYLA4xp9UmSzpO/10x9q4TUZ8jxW1dotoCVf7OqYYxQewrU2x3qoxKvP/Fvf
+8ssWSIang91w+app+fv7QYDySymT6DJMLWyCmxyhaFjYnmr67GKldcgK9hbyjfDB
+Rj382czI/HMSvw/vCB6rRKchzr5hsDGl+YN0MMI4M7/3b5wvMUmxlXqKu1VlslDZ
+8Ez6ONuMdPJD3aQZMxmEph05pEMvhjFhLh+0n7kfLR+9n0D7IR9paVc6LgHLLxsP
+ENoZLGOwJYNdAwwkd6fIa9E6KCpaRgyvWslm+iFCg3XxoA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem.certspec
new file mode 100644
index 000000000..3e280fc4f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ee-from-expired-ca.pem.certspec
@@ -0,0 +1,2 @@
+issuer:expired-ca
+subject:ee-from-expired-ca
diff --git a/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem b/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem
new file mode 100644
index 000000000..ad2d988e0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUI/4Y+KSEZo8YGQK6Ptrdmev5FO0wCwYJKoZIhvcNAQEL
+MBcxFTATBgNVBAMMDHVudHJ1c3RlZC1jYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
+MTgwMjA1MDAwMDAwWjAfMR0wGwYDVQQDDBRlZS1mcm9tLXVudHJ1c3RlZC1jYTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAATALBgkqhkiG9w0BAQsDggEBAJqsDDoJqxrmV4Mlt815HmJwhr/SuYhPwhoQ
+RyU56Ci5kY/8fYa3F1uxSrpzuiYBX4bq6g8keXmltPZGN9gexPP2QJDAecNt0NKW
++04ZKSiz6Tbu+MEyBaXCINDKaAHVPRnbMWR1eCyHzYpZRKZW2Sb2NinWGebzq0mI
+wt5l7veMkL5ZbeYF8u8bNFsdvhl1PM7/AfAZLJL4+fncaqQeDRyVffxrl4mCooS9
+DYajnw7AhFvN0XtXb5vK3HYiz9mv/OnXeoeWxYcWI6aY6LR0OwHHQQptKQSIOP87
+2mo64IbAwzuBrhxNrdrQKCnf1mtyDZig+2r6R4TP3EM3sCNAoiU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem.certspec
new file mode 100644
index 000000000..833e1a23a
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ee-from-untrusted-ca.pem.certspec
@@ -0,0 +1,2 @@
+issuer:untrusted-ca
+subject:ee-from-untrusted-ca
diff --git a/security/manager/ssl/tests/mochitest/browser/email-ee.pem b/security/manager/ssl/tests/mochitest/browser/email-ee.pem
new file mode 100644
index 000000000..4211ef27d
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/email-ee.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUJctkeS6qP+WqsgOLbjATJuPlN40wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBMxETAPBgNVBAMMCGVtYWlsLWVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4Ngf
+vbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTb
+uUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3S
+O8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR
+3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv
+5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxcwFTATBgNVHSUEDDAKBggr
+BgEFBQcDBDALBgkqhkiG9w0BAQsDggEBAIFmRk4ZfcxWjetAoyYp0bIFLr5AjGqv
+ecmc0khsRkW7NR23ywJsRsCU1u82JIGrE0bpDu/KQPAMJsi6QMc9hZEOzO1t1QmG
+OJFLhCNTe+wf+5X+UKHKo01lEp7vDcO7DjuZIgEZSyOp9qbV88AtEiqESIzRBWYp
+dL15cS1PDH8fa5k7MHCAh0C/HeDRD5EP8derIWWrFIesEdJAhwzMRzJrCWIqzLPP
+Lv2gsXhehXCN7U14zkoGU97sSE09k5BopHd4fgqZesSApJrd2OenQAzdRIs3+UQy
+iCs7oLH16lOl/yeRxVjcHRWaSRM47eGpn5+YOnGkoE/lqfux+jjB3rc=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/email-ee.pem.certspec b/security/manager/ssl/tests/mochitest/browser/email-ee.pem.certspec
new file mode 100644
index 000000000..82e329670
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/email-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:email-ee
+extension:extKeyUsage:emailProtection
diff --git a/security/manager/ssl/tests/mochitest/browser/expired-ca.pem b/security/manager/ssl/tests/mochitest/browser/expired-ca.pem
new file mode 100644
index 000000000..2da553a56
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/expired-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUAfElDw37NeFULPHd+G2eoaHpvEYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTAwMTAxMDAwMDAwWhgPMjAxMTAxMDEwMDAw
+MDBaMBUxEzARBgNVBAMMCmV4cGlyZWQtY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAwGA1UdEwQFMAMB
+Af8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAde8CQNB8dVo5ly7Lu8x9
+5yDz2hpzAqqPDxP3+UqxzEgXeA4vfv1Bzvmxx69XEd+884M9Lkt2WBTrc+OrAgqX
+pCCt4X8bjV2t+mG1shtYEGKk5BtRVnorHhZyf6+5xtOfpV9DeWkf/aA1SJK1Kpt3
+cNSDW10PwaGuaNiUMEtIFLD/MYZCM98RFOSVDWjqafbfUBn4ZSeoyRi1C2d3lg0C
+jRFmOc1I4DQOUezp3C0WyCumJ0SLTIoYJGdAshMbDWPr0OOaB4GmI8miKhS6LM59
+o6C3fU8MJrRYKctYj0k9gW0DI6KuEFZj2AY8brv6Ufx1TKy5Z2pqIPeUbuJInCXM
+qA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/expired-ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/expired-ca.pem.certspec
new file mode 100644
index 000000000..15bdcd7d7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/expired-ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:expired-ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+validity:20100101-20110101
diff --git a/security/manager/ssl/tests/mochitest/browser/has-cn.pem b/security/manager/ssl/tests/mochitest/browser/has-cn.pem
new file mode 100644
index 000000000..8e7c479ae
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-cn.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0DCCAbqgAwIBAgIUfQIwxuYCoWiJuu/qTiEf7fbljnswCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMDcxDDAKBgNVBAMMA0ZvbzEMMAoGA1UECwwDQmFyMQwwCgYDVQQKDANCYXox
+CzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR
+qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv
+WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+
+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv
+JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5
+Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6
+clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAJ2fIigbkc2Lh5Z/s
+Y7s4o0D9UnzttXjjEqKYhttk6PJnmVYG3zn3MBmyWPhDcXYW9fJwx7IOcC0woVdJ
+yjkVZUIlJY6xAqIC6kVNtbI3PJ+mji8qQk/ecXCwhTGk0H2lZXrUtc6WMmD3GUIP
+yNQGN/qAniRLnXzzVY3MJPLKKSlWSJEJCY4F4uDwBtwudPc+1yRIR6XblEL3dazS
+H2kuIzGwIu6/i3AN2WIFWFhcuRTfLZINlNeH9gYEaUrwI3MS0aMPqGXtOHz+imZl
+RwNng0xaiDxZXcEPjrRw5HEZcIEGBc6X8WtSzbWufiWBqMue1ltEpc1AkvUamuB3
+KJxYPA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-cn.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-cn.pem.certspec
new file mode 100644
index 000000000..a4a0fcb5f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-cn.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:/CN=Foo/OU=Bar/O=Baz/C=US
diff --git a/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem b/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem
new file mode 100644
index 000000000..8800bfb73
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIChjCCAXCgAwIBAgIBCjALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP
+MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowADCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhX
+bCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQ
+OCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9
+uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFb
+t+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhO
+NsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG
+9w0BAQsDggEBAF/OD4h9UNl2afVbw/Hv2dCV5uMyDV3T8iEUI9eiCvYDMAOElkAN
+NZbDfGfQdg8rNLKG6r7Vz8VBu0T/Vn2lswtKYPll63ANv9qZVtKGsDTGzN8JSC0k
+xgMbtVsj+OsJs81hmNnW6xw7wehpPw3l1UakAEb6dbYuYCanR/p/u/hvTz7phe9D
+AsJyRAo4a+QDyeqgAPKrzTatawshNnz9O4QhNzUqj53fMkpUq2ebOyIGMOvbh/N5
+nT6AVT2wn95mWawnS5v2VTRPALyMkgbl+0bb/VzXHN6CjDHO+n239lL2uQlAZFHe
+8pKr4lmb82dLU9qUFbY7exLyV1aUyYSXSNU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem.certspec
new file mode 100644
index 000000000..6346f7b83
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-empty-subject.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:
+serialNumber:10
diff --git a/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem b/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem
new file mode 100644
index 000000000..16964b1c0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICpjCCAZCgAwIBAgIUCwPRyN8HCSE5XEIq7e2eEEe1OdIwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAt2CF0E7d
+QYnfn/kc8hb6GF6sYpCFA6egEzr6OsYMYE7jt5mKlMJdbIxw57L8jg8IZ1fjH5AQ
+KA5cchGcgjCkHoJ7jOYfMZCubCBdrsNKx2YYWcna8WIAZjwOIfNC0Ajs3IDiRDWm
+vlBrFP9Z6bGuzNrvLFAB0lU2dM2b99DqzaYNZeQP5DcP6ZjaPkSvqOWr3Lf6ZAvO
+tU70OcTelx74Hj9bI75bxVYd71Vorv5qB77zrl7GHb36f2pkludDOKeZ6XhRgy9e
+vN6DLctM0v6fJprG50xrILDhqsTydTdjhETLaIWhF9aUHzFybpFArp8TLoWbXiX1
+eAVaASutFVprhA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem.certspec
new file mode 100644
index 000000000..cc1b668a6
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-non-empty-subject.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:/C=US
diff --git a/security/manager/ssl/tests/mochitest/browser/has-o.pem b/security/manager/ssl/tests/mochitest/browser/has-o.pem
new file mode 100644
index 000000000..755d3cdae
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-o.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtDCCAZ6gAwIBAgIUeXeYs5jw41bNt0btBeEFNbUQonAwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBsxDDAKBgNVBAoMA0JhejELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcN
+AQELA4IBAQAs60sU1VqjaVQbGBHvBNyiQn9oTugmuEx9ogwVKhnmgRK+hYw+wgBn
+H4yYZF1gF4xG7Rt+ut+EruSd4ht8vY9ZMvKrbgMrZ6HbNIZg9oIX+u0i9Bba2lh7
+p87mCePS5L7U1gPbg/fZ8jd0FvW8EusC/TX5tOeeUnawXWE4ciqPZfIVriU0iCP1
+nKzvFtawYzWwgN+QZ1ruzBi7qqrHNDAhgLu9+3g+9QyBd40XV7/EhDQ18kViaTSj
+WmaUX7jJD1FUkGBkxjqHfgGkaYnt7UXGMDTeQ8vFeja11PJJIdRT8hSu0oTMdE6M
+WCEw02+Fc+qsYH5I6vp3MOV8wyBqIqYc
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-o.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-o.pem.certspec
new file mode 100644
index 000000000..f7cc3ffc7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-o.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:/O=Baz/C=US
diff --git a/security/manager/ssl/tests/mochitest/browser/has-ou.pem b/security/manager/ssl/tests/mochitest/browser/has-ou.pem
new file mode 100644
index 000000000..06f663b3f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-ou.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUU/td7MxWYwvdFLfgNUraIpy3GP8wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMCkxDDAKBgNVBAsMA0JhcjEMMAoGA1UECgwDQmF6MQswCQYDVQQGEwJVUzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAATALBgkqhkiG9w0BAQsDggEBAGbVHQ19S6R62HovLt9Ltir1z9KJ4QXWNAEu
+FKicntKaId+jJY42y1+iAqQHy3FpjfLfx5eVKPW8vHbyTQSL/y0jJ9bPKepYsSay
+5McWggOxMxVFazUCOntZN282WYIg3H/OFaeRarjeHlraZjwmNxrfHKzyBJ6bBqBJ
+2vtmDez/+h+f0reutgnY1v4bJ02x/5YuG39+i08uRI0Vc+lrDiqDPYMxlmzwVvJM
+xqo9TZu9gU4XFbK8c8EUsPjMMO1gKyroiBhthtEZ8a9Q4jdeD92cOZRcPrHtYyvR
+qw9VhFLJRgLJ0DVOWqCHqYXUFfYngFezem1eeNxrz2eAbaURdCs=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/has-ou.pem.certspec b/security/manager/ssl/tests/mochitest/browser/has-ou.pem.certspec
new file mode 100644
index 000000000..8879dabf5
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/has-ou.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:/OU=Bar/O=Baz/C=US
diff --git a/security/manager/ssl/tests/mochitest/browser/head.js b/security/manager/ssl/tests/mochitest/browser/head.js
new file mode 100644
index 000000000..d488e6eeb
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/head.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+var gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+/**
+ * List of certs imported via readCertificate(). Certs in this list are
+ * automatically deleted from the cert DB when a test including this head file
+ * finishes.
+ * @type nsIX509Cert[]
+ */
+var gImportedCerts = [];
+
+registerCleanupFunction(() => {
+ for (let cert of gImportedCerts) {
+ gCertDB.deleteCertificate(cert);
+ }
+});
+
+/**
+ * This function serves the same purpose as the one defined in head_psm.js.
+ */
+function pemToBase64(pem) {
+ return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
+ .replace(/-----END CERTIFICATE-----/, "")
+ .replace(/[\r\n]/g, "");
+}
+
+/**
+ * Given the filename of a certificate, returns a promise that will resolve with
+ * a handle to the certificate when that certificate has been read and imported
+ * with the given trust settings.
+ *
+ * Certs imported via this function will automatically be deleted from the cert
+ * DB once the calling test finishes.
+ *
+ * @param {String} filename
+ * The filename of the certificate (assumed to be in the same directory).
+ * @param {String} trustString
+ * A string describing how the certificate should be trusted (see
+ * `certutil -A --help`).
+ * @return {Promise}
+ * A promise that will resolve with a handle to the certificate.
+ */
+function readCertificate(filename, trustString) {
+ return OS.File.read(getTestFilePath(filename)).then(data => {
+ let decoder = new TextDecoder();
+ let pem = decoder.decode(data);
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ let base64 = pemToBase64(pem);
+ certdb.addCertFromBase64(base64, trustString, "unused");
+ let cert = certdb.constructX509FromBase64(base64);
+ gImportedCerts.push(cert);
+ return cert;
+ }, error => { throw error; });
+}
diff --git a/security/manager/ssl/tests/mochitest/browser/invalid.pem b/security/manager/ssl/tests/mochitest/browser/invalid.pem
new file mode 100644
index 000000000..1911098ef
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/invalid.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvDCCAaagAwIBAgIUcy9NBl2j6kWrXfJ6Na36AnwN2Q8wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBIxEDAOBgNVBAMMB2ludmFsaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjDzANMAsGA1UdDwQEAwIBBjAL
+BgkqhkiG9w0BAQsDggEBAHw1PeRKbGVaiNBPlshPnuEjJ5XN+ls3Lv8CVplvuFgM
+uvOAfuXNcLcQmqU4QZm9PvIboCAe2FTFMJ+szDbCIFaBzzJ4RnuJ0FnBZDf1fKJm
+/Nj4XikPePo5DnsqSs53aNKM7Nf5dcdCCA8kfpMm50Nw6ufWrr8HAEqQbDixecv1
+6as6xc458UU8AXKZb30VfLFAm0uPz2Y/ZjROnSqrNSB5ZRx9m4MqS3/4H7fSnlFU
+yMcetH5ovGk3xJg65qWhaRlaoeExco9E5x1nUr+eK4OmP3MXlGbxxMQx1R43Ea11
+zSyaqlhGUs06uDOl4rk4b2FmkPgGV+A26gtjMYD005k=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/invalid.pem.certspec b/security/manager/ssl/tests/mochitest/browser/invalid.pem.certspec
new file mode 100644
index 000000000..71a1707c3
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/invalid.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:invalid
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/mochitest/browser/md5-ee.pem b/security/manager/ssl/tests/mochitest/browser/md5-ee.pem
new file mode 100644
index 000000000..27bf90085
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/md5-ee.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICqjCCAZSgAwIBAgIURZ4xXpmcV9oh3RekbTwkCGv62NowCwYJKoZIhvcNAQEE
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBExDzANBgNVBAMMBm1kNS1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQQDggEBAKs7
+7/g5m901xqDth2t0tDTFWlfh/h94KLk8d8JAAa8AMdVwpMUMc2IKPk+H+f7JkBeE
+hhJ/r4ZEbQkjZuoLSkAR6aKRprE97Ddw1LJLVish39DitEXxpyDemCIl8V6E8FpW
+CWqbOZtvUScOQOlJ2uJfPwHkh93RJbzP9EY8Hd2arFYKuExi5z8Z465feZ53mdOe
+17WG9IKKIQirr4OAxD+ab1EdMuPuXKQ9qfg4fSW/LDsb97x0/ElRfHwFDxsbEiVi
+zR/gGMW9AQhc+eW2qchjYkO0v/ps7dzjDQFDJzLAd/mlb90cK1cpUz6XVn/HagvZ
+0MRczu3MnE6KRPVpW8Y=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/md5-ee.pem.certspec b/security/manager/ssl/tests/mochitest/browser/md5-ee.pem.certspec
new file mode 100644
index 000000000..279c15802
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/md5-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:md5-ee
+signature:md5WithRSAEncryption
diff --git a/security/manager/ssl/tests/mochitest/browser/moz.build b/security/manager/ssl/tests/mochitest/browser/moz.build
new file mode 100644
index 000000000..49d7d5a11
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+BROWSER_CHROME_MANIFESTS += ['browser.ini']
+
+# Temporarily disabled. See bug 1256495.
+# (Note that when this gets enabled, some extra work will have to happen so
+# that the mochitest harness knows where to get the generated certificates -
+# right now it assumes they're in the source directory, which isn't the case
+# when they're automatically generated.)
+#test_certificates = (
+# 'ca.pem',
+# 'code-ee.pem',
+# 'ee-from-expired-ca.pem',
+# 'ee-from-untrusted-ca.pem',
+# 'email-ee.pem',
+# 'expired-ca.pem',
+# 'has-cn.pem',
+# 'has-empty-subject.pem',
+# 'has-non-empty-subject.pem',
+# 'has-o.pem',
+# 'has-ou.pem',
+# 'invalid.pem',
+# 'md5-ee.pem',
+# 'revoked.pem',
+# 'ssl-ee.pem',
+# 'unknown-issuer.pem',
+# 'untrusted-ca.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/mochitest/browser/revoked.pem b/security/manager/ssl/tests/mochitest/browser/revoked.pem
new file mode 100644
index 000000000..b212e8250
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/revoked.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICqzCCAZWgAwIBAgIUD1t15yWPBLIhosAm9w9++t/F/fkwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBIxEDAOBgNVBAMMB3Jldm9rZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IBAQCy
+eobd3+MhGhQvhKQax5XNBqAEmogtsv6G1ZCoAx0kKU83r3Oj9ha4VfGN0syP8NQV
+nmkecZ630QXQcyCD3RRiiLqU07N3nC5djm8v+vM5RhuDADkIwddH3WNWB+8KUJEd
+3Sym1EN6xAYdQEAwWdPno73sUsFebuoL/c4gpTjD7PF+/vPzN0c3KVanlrMhayKe
+3PLq8jST2OSdLvooa8qMYsFFG2S4A+gmp9Cx30moMG2+w1GBKZdtY2tlFx5DppIU
+AoQzUl9pvT6AFDcY2RO6UvsWF9Pzr4dTjjgk8SO05jKcmj2GnBm480ZezDx5N5zm
++XVGgonJZRAucaVuJY79
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/revoked.pem.certspec b/security/manager/ssl/tests/mochitest/browser/revoked.pem.certspec
new file mode 100644
index 000000000..daf75c670
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/revoked.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:revoked
diff --git a/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem b/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem
new file mode 100644
index 000000000..76a688034
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUYfe94xSwDUoffRodCo1TPdV/PaswCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBExDzANBgNVBAMMBnNzbC1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMhMB8wHQYDVR0lBBYwFAYIKwYB
+BQUHAwEGCCsGAQUFBwMCMAsGCSqGSIb3DQEBCwOCAQEAprVI8tGWBHIN2SV66ZnC
+vOfWcQguUQg8QO3Al+O4X5U18hzgsmCjqt99b+oJCJD0qWBnPPBgqY52pckCgmTY
+w73TZ5w3Rnr3v+BlQ5xPTyAQoUeutm1LMxY/Ju7m1XV44tyDnq6GZbOZLVWtRLXe
+W4UEqVex4qbCw3GOvFyHmubSNUk81v4Iexe1SmIJN8glZsVmWJdaC2Xo7qhz+vvq
+HljfO+/ejiBtZOJSf9qG6HcGW/Rf15Io0e+IA6jbZWrlAzIjBcYKumZF8LjRONHZ
+vwiCwWit/IP6KvmsHAb7wj5c0U/p1TuyGdvu/ccp6nCdx8Ya7/QKfAEQTZXnloBG
+4w==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem.certspec b/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem.certspec
new file mode 100644
index 000000000..c4037675f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/ssl-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ssl-ee
+extension:extKeyUsage:serverAuth,clientAuth
diff --git a/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem b/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem
new file mode 100644
index 000000000..d8e750551
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtzCCAaGgAwIBAgIUEfR3vHTQuzModYBSMepORIL++2gwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB3Vua25vd24wIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowGTEXMBUGA1UEAwwOdW5rbm93bi1pc3N1ZXIwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVo
+V2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p
+0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKk
+fbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZh
+W7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EI
+TjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZI
+hvcNAQELA4IBAQB4pRQvglUpzNZ2fH0oj5bcqfcTjE3dwEzGg7WaMD2t50zKgCRp
+2sDObvEB1Nv5SHSkebxDeS9xQ6Dghf+TvuCnkapi/6q9etP51lkIOhl6okAGUwdZ
+vO3duIvXCVUWbut3ATQghKovDYuJXKMx1OYapxyLKKCsdvTQ8LNQpPcwbpVtqWKC
+jLYpa1i/vtn4Pv8xs/ceOf10z5AdydpFBgZ8JpY0CbRI73WHR5fr1yYI7tfzaAA8
+d+OBZ7nqlg81khD/Oepl/h6/IJ3L2eB+lUZx6+yWML9jRD0HX1xRje19u2vxCuQ+
+tNo6lQr9fTRG76Md1d4fdg9+F9LGqDd+yBBv
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem.certspec b/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem.certspec
new file mode 100644
index 000000000..c76a4e2c7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/unknown-issuer.pem.certspec
@@ -0,0 +1,2 @@
+issuer:unknown
+subject:unknown-issuer
diff --git a/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem b/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem
new file mode 100644
index 000000000..0f874d9a9
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbmgAwIBAgIUT/T//UMr8YnbQBWj+61OMGPKRC4wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBcxFTATBgNVBAMMDHVudHJ1c3RlZC1jYTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUw
+AwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQCiDFgskGRygaarkruu
+gTwsX59ULb7yhXyYKZLTdsUitHi8Zk4KUmsbkBHGaek30Ud9A1GyLzuP3hb1/M7M
+FdARYO8qrl414tW3hiON36R47qtw5cO6a2YZfvxU79esuoa6uxChhHLUugqNotJb
+bbGwSMszKzkGtOQ5ZTFNc8+t1kWeQfFoPMznjg5WC2oq9Pl45Rt9lFrU3SD8MkVA
+8fLAGR5TEOY2ZvjDDMKg+ceJNIaA3SPXDTVSXWNIakJU2vsdUXThTyfnoCw0sMQG
+ZwkmKbCXioYXDB/nrjoVBgJh85JSc4KX137y5m2FK+wHzkKMgf4yn6Ql2eg/yTen
+CaeK
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem.certspec b/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem.certspec
new file mode 100644
index 000000000..04f443057
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/browser/untrusted-ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:untrusted-ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/.eslintrc.js b/security/manager/ssl/tests/mochitest/mixedcontent/.eslintrc.js
new file mode 100644
index 000000000..d61bb2044
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/.eslintrc.js
@@ -0,0 +1,5 @@
+"use strict";
+
+module.exports = { // eslint-disable-line no-undef
+ "extends": "../../../../../../testing/mochitest/mochitest.eslintrc.js"
+};
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/alloworigin.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/alloworigin.sjs
new file mode 100644
index 000000000..8e9afb098
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/alloworigin.sjs
@@ -0,0 +1,6 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.write("<html><body>hello!</body></html>");
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/backward.html b/security/manager/ssl/tests/mochitest/mixedcontent/backward.html
new file mode 100644
index 000000000..825c2aa80
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/backward.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="text/javascript">
+ "use strict";
+ window.onload = function()
+ {
+ window.setTimeout(function()
+ {
+ SpecialPowers.wrap(window).QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
+ .getInterface(SpecialPowers.Ci.nsIWebNavigation)
+ .goBack();
+ }, 100);
+ };
+
+ </script>
+</head>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/bug329869.js b/security/manager/ssl/tests/mochitest/mixedcontent/bug329869.js
new file mode 100644
index 000000000..fd888504a
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/bug329869.js
@@ -0,0 +1,7 @@
+/* import-globals-from mixedContentTest.js */
+"use strict";
+
+document.open();
+document.write("This is insecure XSS script " + document.cookie);
+isSecurityState("broken", "security broken after document write from unsecure script");
+finish();
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/bug383369step2.html b/security/manager/ssl/tests/mochitest/mixedcontent/bug383369step2.html
new file mode 100644
index 000000000..c2ebce364
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/bug383369step2.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 383369 test, step 2</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/does_not_exist.css">
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ window.onload = function runTest() {
+ window.setTimeout(function () {
+ window.location =
+ "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/bug383369step3.html?runtest";
+ }, 0);
+ };
+
+ function afterNavigationTest()
+ {
+ }
+
+ </script>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/bug383369step3.html b/security/manager/ssl/tests/mochitest/mixedcontent/bug383369step3.html
new file mode 100644
index 000000000..1acafcd2f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/bug383369step3.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 383369 test, final step</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("secure", "secure page after insecure download and insecure subcontent still secure");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("secure", "still secure after back/forward");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/download.auto b/security/manager/ssl/tests/mochitest/mixedcontent/download.auto
new file mode 100644
index 000000000..4d2fb7d5a
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/download.auto
@@ -0,0 +1 @@
+Temporary file for security/mixedconent tests \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/download.auto^headers^ b/security/manager/ssl/tests/mochitest/mixedcontent/download.auto^headers^
new file mode 100644
index 000000000..9c3159e15
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/download.auto^headers^
@@ -0,0 +1,2 @@
+Content-disposition: "attachment"
+Content-type: application/x-auto-download
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/emptyimage.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/emptyimage.sjs
new file mode 100644
index 000000000..5cce2826f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/emptyimage.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ //response.setHeader("Content-type", "image/gif");
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/hugebmp.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/hugebmp.sjs
new file mode 100644
index 000000000..20d9dea82
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/hugebmp.sjs
@@ -0,0 +1,13 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-type", "image/bitmap");
+
+ let bmpheader = "\x42\x4D\x36\x10\x0E\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00\x01\x00\x18\x00\x00\x00\x00\x00\x00\x10\x0E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+ let bmpdatapiece = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+ response.bodyOutputStream.write(bmpheader, 54);
+ // Fill 640*480*3 nulls
+ for (let i = 0; i < (640 * 480 * 3) / 64; ++i)
+ response.bodyOutputStream.write(bmpdatapiece, 64);
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html b/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html
new file mode 100644
index 000000000..d67eb6a7a
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+</head>
+
+<body>
+ This is frame 1:
+ <script>
+ "use strict";
+ document.write(location.href);
+ </script>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/iframe2.html b/security/manager/ssl/tests/mochitest/mixedcontent/iframe2.html
new file mode 100644
index 000000000..048ed811b
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/iframe2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+</head>
+
+<body>
+ This is frame 2:
+ <script>
+ "use strict";
+ document.write(location.href);
+ </script>
+ <iframe src="http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html"></iframe>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/iframeMetaRedirect.html b/security/manager/ssl/tests/mochitest/mixedcontent/iframeMetaRedirect.html
new file mode 100644
index 000000000..d033f5b00
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/iframeMetaRedirect.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<META http-equiv="Refresh"
+ Content="0; URL=http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html">
+<html>
+ <body>
+ Redirecting by meta tag...
+ </body>
+</html> \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/iframesecredirect.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/iframesecredirect.sjs
new file mode 100644
index 000000000..ea93b80b7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/iframesecredirect.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 307, "Moved temporarly");
+ response.setHeader("Location", "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html");
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/iframeunsecredirect.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/iframeunsecredirect.sjs
new file mode 100644
index 000000000..937e29954
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/iframeunsecredirect.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 307, "Moved temporarly");
+ response.setHeader("Location", "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html");
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/imgsecredirect.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/imgsecredirect.sjs
new file mode 100644
index 000000000..7af6116e1
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/imgsecredirect.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 307, "Moved temporarly");
+ response.setHeader("Location", "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg");
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/imgunsecredirect.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/imgunsecredirect.sjs
new file mode 100644
index 000000000..a8eb26642
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/imgunsecredirect.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 307, "Moved temporarly");
+ response.setHeader("Location", "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg");
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/mixedContentTest.js b/security/manager/ssl/tests/mochitest/mixedcontent/mixedContentTest.js
new file mode 100644
index 000000000..74c592e59
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/mixedContentTest.js
@@ -0,0 +1,204 @@
+"use strict";
+
+/**
+ * Helper script for mixed content testing. It opens a new top-level window
+ * from a secure origin and '?runtest' query. That tells us to run the test
+ * body, function runTest(). Then we wait for call of finish(). On its first
+ * call it loads helper page 'backward.html' that immediately navigates
+ * back to the test secure test. This checks the bfcache. We got second call
+ * to onload and this time we call afterNavigationTest() function to let the
+ * test check security state after re-navigation back. Then we again wait for
+ * finish() call, that this time finishes completelly the test.
+ */
+
+// Tells the framework if to load the test in an insecure page (http://)
+var loadAsInsecure = false;
+// Set true to bypass the navigation forward/back test
+var bypassNavigationTest = false;
+// Set true to do forward/back navigation over an http:// page, test state leaks
+var navigateToInsecure = false;
+// Open the test in two separate windows, test requests sharing among windows
+var openTwoWindows = false;
+// Override the name of the test page to load, useful e.g. to prevent load
+// of images or other content before the test starts; this is actually
+// a 'redirect' to a different test page.
+var testPage = "";
+// Assign a function to this variable to have a clean up at the end
+var testCleanUp = null;
+// Contains mixed active content that needs to load to run the test
+var hasMixedActiveContent = false;
+
+
+// Internal variables
+var _windowCount = 0;
+
+window.onload = function onLoad() {
+ if (location.search == "?runtest") {
+ try {
+ if (history.length == 1) {
+ // Each test that includes this helper file is supposed to define
+ // runTest(). See the top level comment.
+ runTest(); // eslint-disable-line no-undef
+ } else {
+ // Each test that includes this helper file is supposed to define
+ // afterNavigationTest(). See the top level comment.
+ afterNavigationTest(); // eslint-disable-line no-undef
+ }
+ } catch (ex) {
+ ok(false, "Exception thrown during test: " + ex);
+ finish();
+ }
+ } else {
+ window.addEventListener("message", onMessageReceived, false);
+
+ let secureTestLocation = loadAsInsecure ? "http://example.com"
+ : "https://example.com";
+ secureTestLocation += location.pathname;
+ if (testPage != "") {
+ let array = secureTestLocation.split("/");
+ array.pop();
+ array.push(testPage);
+ secureTestLocation = array.join("/");
+ }
+ secureTestLocation += "?runtest";
+
+ if (hasMixedActiveContent) {
+ SpecialPowers.pushPrefEnv(
+ {"set": [["security.mixed_content.block_active_content", false]]},
+ null);
+ }
+ if (openTwoWindows) {
+ _windowCount = 2;
+ window.open(secureTestLocation, "_new1", "");
+ window.open(secureTestLocation, "_new2", "");
+ } else {
+ _windowCount = 1;
+ window.open(secureTestLocation);
+ }
+ }
+};
+
+function onMessageReceived(event)
+{
+ switch (event.data) {
+ // Indication of all test parts finish (from any of the frames)
+ case "done":
+ if (--_windowCount == 0) {
+ if (testCleanUp) {
+ testCleanUp();
+ }
+ if (hasMixedActiveContent) {
+ SpecialPowers.popPrefEnv(null);
+ }
+
+ SimpleTest.finish();
+ }
+ break;
+
+ // Any other message is an error or success message of a test.
+ default:
+ SimpleTest.ok(!event.data.match(/^FAILURE/), event.data);
+ break;
+ }
+}
+
+function postMsg(message)
+{
+ opener.postMessage(message, "http://mochi.test:8888");
+}
+
+function finish()
+{
+ if (history.length == 1 && !bypassNavigationTest) {
+ window.setTimeout(() => {
+ window.location.assign(navigateToInsecure ?
+ "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/backward.html" :
+ "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/backward.html");
+ }, 0);
+ } else {
+ postMsg("done");
+ window.close();
+ }
+}
+
+function ok(a, message)
+{
+ if (!a) {
+ postMsg("FAILURE: " + message);
+ } else {
+ postMsg(message);
+ }
+}
+
+function is(a, b, message)
+{
+ if (a != b) {
+ postMsg(`FAILURE: ${message}, expected ${b} got ${a}`);
+ } else {
+ postMsg(`${message}, expected ${b} got ${a}`);
+ }
+}
+
+function isSecurityState(expectedState, message, test)
+{
+ if (!test) {
+ test = ok;
+ }
+
+ let ui = SpecialPowers.wrap(window)
+ .QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
+ .getInterface(SpecialPowers.Ci.nsIWebNavigation)
+ .QueryInterface(SpecialPowers.Ci.nsIDocShell)
+ .securityUI;
+
+ let isInsecure = !ui ||
+ (ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_INSECURE);
+ let isBroken = ui &&
+ (ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IS_BROKEN);
+ let isEV = ui &&
+ (ui.state & SpecialPowers.Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL);
+
+ let gotState = "secure";
+ if (isInsecure) {
+ gotState = "insecure";
+ } else if (isBroken) {
+ gotState = "broken";
+ } else if (isEV) {
+ gotState = "EV";
+ }
+
+ test(gotState == expectedState, (message || "") + ", " + "expected " + expectedState + " got " + gotState);
+
+ switch (expectedState) {
+ case "insecure":
+ test(isInsecure && !isBroken && !isEV, "for 'insecure' excpected flags [1,0,0], " + (message || ""));
+ break;
+ case "broken":
+ test(ui && !isInsecure && isBroken && !isEV, "for 'broken' expected flags [0,1,0], " + (message || ""));
+ break;
+ case "secure":
+ test(ui && !isInsecure && !isBroken && !isEV, "for 'secure' expected flags [0,0,0], " + (message || ""));
+ break;
+ case "EV":
+ test(ui && !isInsecure && !isBroken && isEV, "for 'EV' expected flags [0,0,1], " + (message || ""));
+ break;
+ default:
+ throw new Error("Invalid isSecurityState state");
+ }
+}
+
+function waitForSecurityState(expectedState, callback)
+{
+ let roundsLeft = 200; // Wait for 20 seconds (=200*100ms)
+ let interval = window.setInterval(() => {
+ isSecurityState(expectedState, "", isok => {
+ if (isok) {
+ roundsLeft = 0;
+ }
+ });
+ if (!roundsLeft--) {
+ window.clearInterval(interval);
+ callback();
+ }
+ }, 100);
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/mochitest.ini b/security/manager/ssl/tests/mochitest/mixedcontent/mochitest.ini
new file mode 100644
index 000000000..c7a352eb8
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/mochitest.ini
@@ -0,0 +1,62 @@
+[DEFAULT]
+skip-if = toolkit == 'android' #TIMED_OUT
+support-files =
+ alloworigin.sjs
+ backward.html
+ bug329869.js
+ bug383369step2.html
+ bug383369step3.html
+ download.auto
+ download.auto^headers^
+ emptyimage.sjs
+ hugebmp.sjs
+ iframe.html
+ iframe2.html
+ iframeMetaRedirect.html
+ iframesecredirect.sjs
+ iframeunsecredirect.sjs
+ imgsecredirect.sjs
+ imgunsecredirect.sjs
+ mixedContentTest.js
+ moonsurface.jpg
+ nocontent.sjs
+ redirecttoemptyimage.sjs
+ somestyle.css
+ unsecureIframe.html
+ unsecurePictureDup.html
+
+[test_bug329869.html]
+[test_bug383369.html]
+[test_bug455367.html]
+[test_bug472986.html]
+[test_bug477118.html]
+[test_bug521461.html]
+[test_cssBefore1.html]
+[test_cssContent1.html]
+[test_cssContent2.html]
+[test_documentWrite1.html]
+[test_documentWrite2.html]
+[test_dynDelayedUnsecurePicture.html]
+[test_dynDelayedUnsecureXHR.html]
+[test_dynUnsecureBackground.html]
+[test_dynUnsecureIframeRedirect.html]
+[test_dynUnsecurePicture.html]
+[test_dynUnsecurePicturePreload.html]
+# [test_dynUnsecureRedirect.html]
+# intermitently fails, quite often, bug 487402
+[test_innerHtmlDelayedUnsecurePicture.html]
+[test_innerHtmlUnsecurePicture.html]
+[test_javascriptPicture.html]
+[test_secureAll.html]
+[test_securePicture.html]
+[test_unsecureBackground.html]
+[test_unsecureCSS.html]
+[test_unsecureIframe.html]
+[test_unsecureIframe2.html]
+# [test_unsecureIframeMetaRedirect.html]
+# intermittently fails, less often, bug 487632
+[test_unsecureIframeRedirect.html]
+[test_unsecurePicture.html]
+[test_unsecurePictureDup.html]
+[test_unsecurePictureInIframe.html]
+[test_unsecureRedirect.html]
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg b/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg
new file mode 100644
index 000000000..c0ffca256
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg
Binary files differ
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/moz.build b/security/manager/ssl/tests/mochitest/mixedcontent/moz.build
new file mode 100644
index 000000000..8e5cb5d71
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_MANIFESTS += ['mochitest.ini']
+
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/nocontent.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/nocontent.sjs
new file mode 100644
index 000000000..53fa4bc0c
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/nocontent.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 204, "No Content");
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/redirecttoemptyimage.sjs b/security/manager/ssl/tests/mochitest/mixedcontent/redirecttoemptyimage.sjs
new file mode 100644
index 000000000..4d85e1658
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/redirecttoemptyimage.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 307, "Moved temporarly");
+ response.setHeader("Location", "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/emptyimage.sjs");
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/somestyle.css b/security/manager/ssl/tests/mochitest/mixedcontent/somestyle.css
new file mode 100644
index 000000000..9867e3c41
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/somestyle.css
@@ -0,0 +1,4 @@
+body
+{
+ background-color: lightBlue;
+}
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_bug329869.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug329869.html
new file mode 100644
index 000000000..3b8fae25e
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug329869.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>dymanic script load</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("secure");
+ window.setTimeout(function () {
+ let newElement = document.createElement("script");
+ newElement.src = "http://example.org/tests/security/manager/ssl/tests/" +
+ "mochitest/mixedcontent/bug329869.js";
+ document.body.appendChild(newElement);
+ }, 0);
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_bug383369.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug383369.html
new file mode 100644
index 000000000..b68546d0a
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug383369.html
@@ -0,0 +1,102 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 383369 test</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* sendAsyncMessage isn't actually a global - this just mollifies eslint */
+ /* global sendAsyncMessage */
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ // We want to start this test from an insecure context
+ loadAsInsecure = true;
+ // We don't want to go through the navigation back/forward test
+ bypassNavigationTest = true;
+
+ function runTest() {
+ let script = SpecialPowers.loadChromeScript(function() {
+ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+ // Force download to be w/o user assistance for our testing mime type
+ const mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+ let handlerInfo =
+ mimeSvc.getFromTypeAndExtension("application/x-auto-download", "auto");
+ handlerInfo.preferredAction = Ci.nsIHandlerInfo.saveToDisk;
+ handlerInfo.alwaysAskBeforeHandling = false;
+ handlerInfo.preferredApplicationHandler = null;
+
+ const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"]
+ .getService(Ci.nsIHandlerService);
+ handlerSvc.store(handlerInfo);
+
+ let dirProvider = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties);
+ let profileDir = dirProvider.get("ProfDS", Ci.nsIFile);
+ profileDir.append("downloads");
+
+ let prefs = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService);
+ let prefBranch = prefs.getBranch("browser.download.");
+
+ prefBranch.setCharPref("dir", profileDir.path);
+ prefBranch.setBoolPref("useDownloadDir", true);
+ prefBranch.setIntPref("folderList", 2);
+ prefBranch.setBoolPref("manager.closeWhenDone", true);
+ prefBranch.setBoolPref("manager.showWhenStarting", false);
+
+ const { Downloads } =
+ Cu.import("resource://gre/modules/Downloads.jsm", {});
+ Downloads.getList(Downloads.PUBLIC).then(list => {
+ list.addView({
+ onDownloadAdded: function (aDownload) {
+ list.removeView(this);
+ aDownload.whenSucceeded().then(() => {
+ list.removeFinished();
+ sendAsyncMessage("navigate", "bug383369step2.html");
+ });
+ },
+ });
+ sendAsyncMessage("navigate", "download.auto");
+ }).then(null, Cu.reportError);
+ });
+ script.addMessageListener("navigate", function(url) {
+ window.location = url;
+ });
+ }
+
+ function afterNavigationTest() {}
+
+ testCleanUp = function cleanup() {
+ SpecialPowers.loadChromeScript(function() {
+ const { classes: Cc, interfaces: Ci } = Components;
+ const mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+ let handlerInfo =
+ mimeSvc.getFromTypeAndExtension("application/x-auto-download", "auto");
+
+ const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"]
+ .getService(Ci.nsIHandlerService);
+ handlerSvc.remove(handlerInfo);
+
+ let prefs = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService);
+ let prefBranch = prefs.getBranch("browser.download.");
+
+ const prefKeys = ["dir", "useDownloadDir", "folderList",
+ "manager.closeWhenDone", "manager.showWhenStarting"];
+ for (let prefKey of prefKeys) {
+ if (prefBranch.prefHasUserValue(prefKey)) {
+ prefBranch.clearUserPref(prefKey);
+ }
+ }
+ });
+ };
+
+ </script>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_bug455367.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug455367.html
new file mode 100644
index 000000000..ec2b8590a
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug455367.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>No content image doesn't break security</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("broken", "broken");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/redirecttoemptyimage.sjs" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_bug472986.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug472986.html
new file mode 100644
index 000000000..b95cfcf65
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug472986.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>img.src replace</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ SimpleTest.expectAssertions(0, 4);
+
+ // Clear the default onload assigned to test start because we must
+ // wait for replaced image to load and only after that test the security state
+ var onLoadFunction = window.onload;
+ window.onload = function()
+ {
+ let img1 = document.getElementById("img1");
+ img1.addEventListener("load", onLoadFunction, false);
+ img1.src = "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg";
+ };
+
+ function runTest()
+ {
+ isSecurityState("secure", "secure");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("secure", "secure after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img id="img1" src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/hugebmp.sjs" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_bug477118.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug477118.html
new file mode 100644
index 000000000..51a13a4b8
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug477118.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 477118</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("secure", "data <img> doesn't break security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("secure", "still secure after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB9kBDxIAOdxBIbcAAAI+SURBVDjLxZO7TxRhFMV/M/PN7EPYhS02yytggo+ERAgxERsNhYnGzsQojaHT3r9F0cTaUjs6NUQLBRKDi4I8FEwkLMgO+5rdeX3XAoVYiZWnP797cu69Bv8gqZ+0QTqIdRpl1VHGvnV884CJwQgwicVtoB/ku/H4ycOnURgP/Q1g21Fw4+r0RjbbNmaq4ayO35UkXp9S2UzHxK2bE4QNl82FVwD0D49jn+hERBCRgwTiIX7pvGUGYF/BlO327d3ENfV7wuL0AyjPICIsfPvAmev3qdVqlMtlCoUCGxurDPT1kEnPomQKkRTFpXOjh4DN4kvGLuSJ/JC38y/ouXyXYrGIiBDHMVtbu1SrvXTlbfp6HcQcoVwp5hRAaWedPXFYfL+E1lAKswSRy+joKEEQICLkcjm01hiGgRcksW0b4SMKYHb+OSt6ma+VffxWRF3S5OeeMX7pHkqpwy5EBK31H90ogFODF1lbm8OtlEhloDORpbdnhDAMaTabhwbbtkkkEkRRhGVZR4BCfojJO4+o1VwQAItEIolpmliWRVtbG7s/dlDKotGo47U8CvkuAEwA3/eJoxhE0WyGuO4+nucRBAHVahXDMKg3agRhQBAGVKsVtNZHCRzHwTAMcrnc0eX9it3e3g7A6cGzhx0AKHWwQOV5jdXXb2ZOaa3BOP5ffF5ZptVqflG+3xpbWv5kh2FolEo7dnmv7Lium6zXG0nf95MiguM4QTqd9jPZTCvX2eF393QHqVRKZ7KZkP+unzPGLX8Jr7F8AAAAAElFTkSuQmCC" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_bug521461.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug521461.html
new file mode 100644
index 000000000..523b97f59
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_bug521461.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 521461</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ loadAsInsecure = true;
+
+ function runTest()
+ {
+ window.location = "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/nocontent.sjs";
+ window.setTimeout(function() {
+ isSecurityState("insecure", "location.href doesn't effect the security state");
+ is(document.body.innerHTML, "This is an unsecure page!", "Document has not changed content");
+ finish();
+ }, 1000);
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("insecure", "still not secure after navigation");
+ is(document.body.innerHTML, "This is an unsecure page!", "Document has not changed content");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>This is an unsecure page!</body></html> \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_cssBefore1.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_cssBefore1.html
new file mode 100644
index 000000000..72046e032
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_cssBefore1.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>CSS :before styling 1</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <style type="text/css">
+ p:before
+ {
+ content: url(http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg);
+ }
+ </style>
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure content added by :before styling breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <p>
+ There is a moon surface left to this text
+ </p>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_cssContent1.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_cssContent1.html
new file mode 100644
index 000000000..364d652f4
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_cssContent1.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>CSS conent styling 1</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <style type="text/css">
+ p
+ {
+ content: url(http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg);
+ }
+ </style>
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure content added by :before styling breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <p></p>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_cssContent2.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_cssContent2.html
new file mode 100644
index 000000000..c57410b74
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_cssContent2.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>CSS conent styling 2</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ if (navigator.platform.startsWith("Mac")) {
+ SimpleTest.expectAssertions(0, 1);
+ }
+
+ function runTest()
+ {
+ isSecurityState("secure");
+ document.getElementById("para").style.content =
+ "url('http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg')";
+
+ waitForSecurityState("broken", function()
+ {
+ isSecurityState("broken", "insecure content added by styling breaks security");
+ finish();
+ });
+ }
+
+ function afterNavigationTest()
+ {
+ is(document.getElementById("para").style.content, "");
+ isSecurityState("secure", "security full after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <p id="para"></p>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_documentWrite1.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_documentWrite1.html
new file mode 100644
index 000000000..64eec0890
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_documentWrite1.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>document.write('<img src="http://">')</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <img> written dynamically breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <script class="testbody" type="text/javascript">
+ document.write(
+ "<img src='http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg' />");
+ </script>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_documentWrite2.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_documentWrite2.html
new file mode 100644
index 000000000..41878d292
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_documentWrite2.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>document.write('<iframe src="http://">')</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure iframe written dynamically breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <script class="testbody" type="text/javascript">
+ document.write(
+ "<iframe src='http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html'></iframe>");
+ </script>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_dynDelayedUnsecurePicture.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynDelayedUnsecurePicture.html
new file mode 100644
index 000000000..4f7305f41
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynDelayedUnsecurePicture.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>img.src changes to unsecure test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("secure");
+ window.setTimeout(function() {
+ // Don't do this synchronously from onload handler
+ document.getElementById("image1").src =
+ "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg";
+ }, 0);
+
+ waitForSecurityState("broken", function()
+ {
+ isSecurityState("broken", "src='http://...' changed to broken");
+ finish();
+ });
+ }
+
+ function afterNavigationTest()
+ {
+ is(document.getElementById("image1").src,
+ "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg",
+ "img.src secure again");
+ isSecurityState("secure", "security full after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img id="image1" src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_dynDelayedUnsecureXHR.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynDelayedUnsecureXHR.html
new file mode 100644
index 000000000..7dbfdf4da
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynDelayedUnsecureXHR.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>unsecure XHR test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("secure");
+ window.setTimeout(() => {
+ try {
+ let req = new XMLHttpRequest();
+ req.open("GET", "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/alloworigin.sjs", false);
+ req.send(null);
+
+ // Change should be immediate, the request was sent synchronously
+ isSecurityState("broken", "security broken after insecure XHR");
+ } catch (ex) {
+ ok(false, ex);
+ }
+
+ finish();
+ }, 0);
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("secure", "security full after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureBackground.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureBackground.html
new file mode 100644
index 000000000..6d06f1a64
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureBackground.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>body.background changes to unsecure test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ // This test, as is, equals to https://kuix.de/misc/test17/358438.php
+
+ function runTest()
+ {
+ isSecurityState("secure");
+ document.body.background =
+ "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg";
+
+ waitForSecurityState("broken", function () {
+ isSecurityState("broken", "document.body.background='http://...' changed to broken");
+ finish();
+ });
+ }
+
+ function afterNavigationTest()
+ {
+ is(document.body.background,
+ "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg",
+ "document backround secure again");
+ isSecurityState("secure", "secure after re-navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body background="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg">
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureIframeRedirect.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureIframeRedirect.html
new file mode 100644
index 000000000..f846f8919
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureIframeRedirect.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>iframe.src changes to unsecure redirect test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("secure");
+ let self = window;
+ let iframe = document.getElementById("iframe1");
+ iframe.onload = function() {
+ self.isSecurityState("broken", "src='redirect to unsecure' changed to broken");
+ self.finish();
+ };
+
+ iframe.src =
+ "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframeunsecredirect.sjs";
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <iframe id="iframe1" src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html"></iframe>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecurePicture.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecurePicture.html
new file mode 100644
index 000000000..cbb5dccf8
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecurePicture.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>img.src changes to unsecure test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ // This test, as is, equals to https://kuix.de/misc/test17/358438.php
+
+ function runTest()
+ {
+ isSecurityState("secure");
+ document.getElementById("image1").src =
+ "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg";
+
+ window.setTimeout(function() {
+ isSecurityState("broken", "src='http://...' changed to broken");
+ finish();
+ }, 500);
+ }
+
+ function afterNavigationTest()
+ {
+ is(document.getElementById("image1").src,
+ "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg",
+ "img.src secure again");
+ isSecurityState("secure", "security full after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img id="image1" src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecurePicturePreload.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecurePicturePreload.html
new file mode 100644
index 000000000..64a7a4abe
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecurePicturePreload.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>img.src changes to unsecure test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ (new Image()).src =
+ "http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg";
+
+ function runTest()
+ {
+ isSecurityState("broken", "(new Image()).src='http://...' changed to broken");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureRedirect.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureRedirect.html
new file mode 100644
index 000000000..c1af7b29d
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_dynUnsecureRedirect.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>img.src changes to unsecure redirect test</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("secure");
+ document.getElementById("image1").src =
+ "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/imgunsecredirect.sjs";
+
+ window.setTimeout(function() {
+ isSecurityState("broken", "src='redirect to unsecure' changed to broken");
+ finish();
+ }, 500);
+ }
+
+ function afterNavigationTest()
+ {
+ is(document.getElementById("image1").src,
+ "https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg",
+ "img.src secure again");
+ isSecurityState("secure", "security full after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img id="image1" src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_innerHtmlDelayedUnsecurePicture.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_innerHtmlDelayedUnsecurePicture.html
new file mode 100644
index 000000000..5e408b2aa
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_innerHtmlDelayedUnsecurePicture.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>innerHTML changes to unsecure test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("secure");
+
+ window.setTimeout(function () {
+ document.getElementById("buddy").innerHTML =
+ "<img id='image1' src='http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg' />";
+ }, 1);
+
+ waitForSecurityState("broken", function () {
+ isSecurityState("broken", "innerHTML loading insecure changed to broken");
+ finish();
+ });
+ }
+
+ function afterNavigationTest()
+ {
+ is(document.getElementById("buddy").innerHTML, "", "innerHTML back to previous");
+ isSecurityState("secure");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body id="buddy"></body></html> \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_innerHtmlUnsecurePicture.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_innerHtmlUnsecurePicture.html
new file mode 100644
index 000000000..ff3592542
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_innerHtmlUnsecurePicture.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>innerHTML changes to unsecure test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("secure");
+
+ document.getElementById("buddy").innerHTML =
+ "<img id='image1' src='http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg' />";
+
+ window.setTimeout(function() {
+ isSecurityState("broken", "innerHTML loading insecure changed to broken");
+ finish();
+ }, 500);
+ }
+
+ function afterNavigationTest()
+ {
+ is(document.getElementById("buddy").innerHTML, "", "innerHTML back to previous");
+ isSecurityState("secure");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body id="buddy"></body></html> \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_javascriptPicture.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_javascriptPicture.html
new file mode 100644
index 000000000..1efbe4d73
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_javascriptPicture.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Secure img load</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("secure", "javascript: <img> should not break security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("secure", "Still secure after renavigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img src="javascript:'Random data'" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_secureAll.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_secureAll.html
new file mode 100644
index 000000000..cd9f1d0d7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_secureAll.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>All secure anti-regression check</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <link rel="stylesheet" type="text/css"
+ href="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/somestyle.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ // Navigation test goes over an insecure page, test state leak
+ navigateToInsecure = true;
+
+ function runTest()
+ {
+ isSecurityState("secure", "insecure <img> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("secure", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg" />
+ <img src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/imgsecredirect.sjs" />
+ <iframe src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframesecredirect.sjs" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_securePicture.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_securePicture.html
new file mode 100644
index 000000000..96ef9a3c7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_securePicture.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Secure img load</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ loadAsInsecure = true;
+
+ function runTest()
+ {
+ isSecurityState("insecure", "left insecure");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("insecure", "left insecure after renavigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureBackground.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureBackground.html
new file mode 100644
index 000000000..0f741f9b8
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureBackground.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>background unsecure test</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ // This test, as is, equals to https://kuix.de/misc/test17/358438.php
+
+ function runTest()
+ {
+ isSecurityState("broken", "security broken");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body background="http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg">
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureCSS.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureCSS.html
new file mode 100644
index 000000000..19d1379ea
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureCSS.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure css load</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <link rel="stylesheet" type="text/css"
+ href="http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/somestyle.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <img> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframe.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframe.html
new file mode 100644
index 000000000..dd4bd2d8f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframe.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure iframe load</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <iframe> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <iframe src="http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframe.html"></iframe>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframe2.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframe2.html
new file mode 100644
index 000000000..cdd59ce15
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframe2.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure iframe load</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <iframe> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <iframe src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframe2.html"></iframe>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframeMetaRedirect.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframeMetaRedirect.html
new file mode 100644
index 000000000..288526437
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframeMetaRedirect.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure redirect iframe load</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ window.setTimeout(function()
+ {
+ isSecurityState("broken", "insecure meta-tag <iframe> load breaks security");
+ finish();
+ }, 500);
+ }
+
+ function afterNavigationTest()
+ {
+ window.setTimeout(function()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }, 500);
+ }
+
+ </script>
+</head>
+
+<body>
+ <iframe src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframeMetaRedirect.html"></iframe>
+</body>
+</html>
+ \ No newline at end of file
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframeRedirect.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframeRedirect.html
new file mode 100644
index 000000000..1095c769f
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureIframeRedirect.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure redirect iframe load</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <iframe> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <iframe src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/iframeunsecredirect.sjs"></iframe>
+</body>
+</html>
+
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePicture.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePicture.html
new file mode 100644
index 000000000..dc18efa29
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePicture.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure img load</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <img> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img src="http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePictureDup.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePictureDup.html
new file mode 100644
index 000000000..5d02de95c
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePictureDup.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure img load in two windows</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ openTwoWindows = true;
+ testPage = "unsecurePictureDup.html";
+
+ </script>
+</head>
+
+<body>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePictureInIframe.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePictureInIframe.html
new file mode 100644
index 000000000..2ece07342
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecurePictureInIframe.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure img in iframe load</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <img> in an <iframe> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <iframe src="http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/unsecureIframe.html"></iframe>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureRedirect.html b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureRedirect.html
new file mode 100644
index 000000000..a796b41b5
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/test_unsecureRedirect.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Redirect from secure to unsecure img</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ hasMixedActiveContent = true;
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <img> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img src="https://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/imgunsecredirect.sjs" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/unsecureIframe.html b/security/manager/ssl/tests/mochitest/mixedcontent/unsecureIframe.html
new file mode 100644
index 000000000..228267741
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/unsecureIframe.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+</head>
+
+<body>
+ <img src="http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/moonsurface.jpg" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/mixedcontent/unsecurePictureDup.html b/security/manager/ssl/tests/mochitest/mixedcontent/unsecurePictureDup.html
new file mode 100644
index 000000000..f53fb4830
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/mixedcontent/unsecurePictureDup.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Unsecure img load in two windows</title>
+ <script type="text/javascript" src="/MochiKit/Base.js"></script>
+ <script type="text/javascript" src="/MochiKit/DOM.js"></script>
+ <script type="text/javascript" src="/MochiKit/Style.js"></script>
+ <script type="text/javascript" src="/MochiKit/Signal.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="mixedContentTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ /* import-globals-from mixedContentTest.js */
+ "use strict";
+
+ function runTest()
+ {
+ isSecurityState("broken", "insecure <img> load breaks security");
+ finish();
+ }
+
+ function afterNavigationTest()
+ {
+ isSecurityState("broken", "security still broken after navigation");
+ finish();
+ }
+
+ </script>
+</head>
+
+<body>
+ <img src="http://example.com/tests/security/manager/ssl/tests/mochitest/mixedcontent/hugebmp.sjs" />
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/moz.build b/security/manager/ssl/tests/mochitest/moz.build
new file mode 100644
index 000000000..05c6b7906
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+TEST_DIRS += [
+ 'browser',
+ 'mixedcontent',
+ 'stricttransportsecurity',
+]
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/.eslintrc.js b/security/manager/ssl/tests/mochitest/stricttransportsecurity/.eslintrc.js
new file mode 100644
index 000000000..74b7a1a07
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/.eslintrc.js
@@ -0,0 +1,9 @@
+"use strict";
+
+module.exports = { // eslint-disable-line no-undef
+ // mochitest-chrome tests also exist in this directory, but don't appear to
+ // use anything not also available to plain mochitests. Since plain mochitests
+ // are the majority, we take the safer option and only extend the
+ // mochitest-plain eslintrc file.
+ "extends": "../../../../../../testing/mochitest/mochitest.eslintrc.js"
+};
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/chrome.ini b/security/manager/ssl/tests/mochitest/stricttransportsecurity/chrome.ini
new file mode 100644
index 000000000..b2ce8fef0
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/chrome.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+tags = psm
+skip-if = os == 'android'
+support-files = page_blank.html
+
+[test_sts_privatebrowsing_perwindowpb.html]
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/mochitest.ini b/security/manager/ssl/tests/mochitest/stricttransportsecurity/mochitest.ini
new file mode 100644
index 000000000..100f45840
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/mochitest.ini
@@ -0,0 +1,13 @@
+[DEFAULT]
+tags = psm
+support-files =
+ nosts_bootstrap.html
+ nosts_bootstrap.html^headers^
+ plain_bootstrap.html
+ plain_bootstrap.html^headers^
+ subdom_bootstrap.html
+ subdom_bootstrap.html^headers^
+ verify.sjs
+
+[test_stricttransportsecurity.html]
+skip-if = toolkit == 'android' #TIMED_OUT
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/moz.build b/security/manager/ssl/tests/mochitest/stricttransportsecurity/moz.build
new file mode 100644
index 000000000..cd73f7716
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/moz.build
@@ -0,0 +1,10 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_MANIFESTS += ['mochitest.ini']
+
+MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
+
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/nosts_bootstrap.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/nosts_bootstrap.html
new file mode 100644
index 000000000..f9b0f9381
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/nosts_bootstrap.html
@@ -0,0 +1,26 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>STS test iframe</title>
+ <script>
+ "use strict";
+ let windowRef = window;
+ window.addEventListener("load", function() {
+ windowRef.parent.postMessage("BOOTSTRAP plain",
+ "http://mochi.test:8888");
+ }, false);
+ </script>
+ </head>
+ <body>
+ <!-- This frame should be loaded over HTTPS to set the STS header. -->
+ This frame was loaded using
+ <script>
+ document.write(document.location.protocol);
+ </script>
+ and set the STS header to force this site and allow subdomain upgrading.
+ </body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/nosts_bootstrap.html^headers^ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/nosts_bootstrap.html^headers^
new file mode 100644
index 000000000..9e23c73b7
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/nosts_bootstrap.html^headers^
@@ -0,0 +1 @@
+Cache-Control: no-cache
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/page_blank.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/page_blank.html
new file mode 100644
index 000000000..db5d31a96
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/page_blank.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ PAGE BLANK
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/plain_bootstrap.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/plain_bootstrap.html
new file mode 100644
index 000000000..f9b0f9381
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/plain_bootstrap.html
@@ -0,0 +1,26 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>STS test iframe</title>
+ <script>
+ "use strict";
+ let windowRef = window;
+ window.addEventListener("load", function() {
+ windowRef.parent.postMessage("BOOTSTRAP plain",
+ "http://mochi.test:8888");
+ }, false);
+ </script>
+ </head>
+ <body>
+ <!-- This frame should be loaded over HTTPS to set the STS header. -->
+ This frame was loaded using
+ <script>
+ document.write(document.location.protocol);
+ </script>
+ and set the STS header to force this site and allow subdomain upgrading.
+ </body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/plain_bootstrap.html^headers^ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/plain_bootstrap.html^headers^
new file mode 100644
index 000000000..a46bf65bd
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/plain_bootstrap.html^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-cache
+Strict-Transport-Security: max-age=60
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/subdom_bootstrap.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/subdom_bootstrap.html
new file mode 100644
index 000000000..24a364158
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/subdom_bootstrap.html
@@ -0,0 +1,26 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>STS test iframe</title>
+ <script>
+ "use strict";
+ let windowRef = window;
+ window.addEventListener("load", function() {
+ windowRef.parent.postMessage("BOOTSTRAP subdom",
+ "http://mochi.test:8888");
+ }, false);
+ </script>
+ </head>
+ <body>
+ <!-- This frame should be loaded over HTTPS to set the STS header. -->
+ This frame was loaded using
+ <script>
+ document.write(document.location.protocol);
+ </script>
+ and set the STS header to force this site and allow subdomain upgrading.
+ </body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/subdom_bootstrap.html^headers^ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/subdom_bootstrap.html^headers^
new file mode 100644
index 000000000..e54fc6a1d
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/subdom_bootstrap.html^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-cache
+Strict-Transport-Security: max-age=60; includeSubDomains
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html
new file mode 100644
index 000000000..675688638
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_stricttransportsecurity.html
@@ -0,0 +1,120 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>opens additional content that should be converted to https</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <script class="testbody" type="text/javascript">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+
+ const STSPATH = "/tests/security/manager/ssl/tests/mochitest/stricttransportsecurity";
+
+ // initialized manually here
+ var testsleft = {'plain': 4, 'subdom': 4};
+ var roundsLeft = 2;
+
+ var testframes = {
+ 'samedom':
+ {'url': "http://example.com" + STSPATH + "/verify.sjs",
+ 'expected': {'plain': 'SECURE', 'subdom': 'SECURE'}},
+ 'subdom':
+ {'url': "http://test1.example.com" + STSPATH + "/verify.sjs",
+ 'expected': {'plain': 'INSECURE', 'subdom': 'SECURE'}},
+ 'otherdom':
+ {'url': "http://example.org" + STSPATH + "/verify.sjs",
+ 'expected': {'plain': 'INSECURE', 'subdom': 'INSECURE'}},
+ 'alreadysecure':
+ {'url': "https://test2.example.com" + STSPATH + "/verify.sjs",
+ 'expected': {'plain': 'SECURE', 'subdom': 'SECURE'}},
+ };
+
+ function startRound(round) {
+ let frame = document.createElement("iframe");
+ frame.setAttribute('id', 'ifr_bootstrap');
+ frame.setAttribute('src', "https://example.com" + STSPATH + "/" + round + "_bootstrap.html");
+ document.body.appendChild(frame);
+ }
+
+ function endRound(round) {
+ // remove all the iframes in the document
+ document.body.removeChild(document.getElementById('ifr_bootstrap'));
+ for (let test in testframes) {
+ document.body.removeChild(document.getElementById('ifr_' + test));
+ }
+
+ // clean up the STS state
+ SpecialPowers.cleanUpSTSData("http://example.com");
+ }
+
+ function loadVerifyFrames(round) {
+ for (let test in testframes) {
+ let frame = document.createElement("iframe");
+ frame.setAttribute('id', 'ifr_' + test);
+ frame.setAttribute('src', testframes[test].url + '?id=' + test);
+ document.body.appendChild(frame);
+ }
+ }
+
+ /* Messages received are in this format:
+ * (BOOTSTRAP|SECURE|INSECURE) testid
+ * For example: "BOOTSTRAP plain"
+ * or: "INSECURE otherdom"
+ */
+ function onMessageReceived(event) {
+ let result = event.data.split(/\s+/);
+ if (result.length != 2) {
+ SimpleTest.ok(false, event.data);
+ return;
+ }
+
+ // figure out which round of tests we're in
+ let round = (roundsLeft == 2) ? "plain" : "subdom";
+
+ if (result[0] === "BOOTSTRAP") {
+ loadVerifyFrames(round);
+ return;
+ }
+
+ // check if the result (SECURE/INSECURE) is expected for this round/test combo
+ SimpleTest.is(result[0], testframes[result[1]].expected[round],
+ "in ROUND " + round + ", test " + result[1]);
+ testsleft[round]--;
+
+ // check if there are more tests to run.
+ if (testsleft[round] < 1) {
+ // if not, advance to next round
+ endRound(round);
+ roundsLeft--;
+
+ // defer this so it doesn't muck with the stack too much.
+ if (roundsLeft == 1) {
+ setTimeout(function () {
+ startRound("subdom");
+ }, 0);
+ }
+ }
+
+ if (roundsLeft < 1) {
+ SimpleTest.finish();
+ }
+ }
+
+ // listen for calls back from the sts-setting iframe and then
+ // the verification frames.
+ window.addEventListener("message", onMessageReceived, false);
+ window.addEventListener("load", () => { startRound("plain"); }, false);
+ </script>
+</head>
+
+<body>
+ This test will load some iframes and do some tests.
+
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html
new file mode 100644
index 000000000..882030b67
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/test_sts_privatebrowsing_perwindowpb.html
@@ -0,0 +1,275 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>opens additional content that should be converted to https</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+
+ <script class="testbody" type="text/javascript">
+ "use strict";
+
+ // We define |content| as a global as a hack to prevent use of |content|
+ // inside a ContentTask tripping ESLint no-undef checks.
+ /* global content */
+
+ SimpleTest.waitForExplicitFinish();
+
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const Cu = Components.utils;
+ const STSPATH = "/tests/security/manager/ssl/tests/mochitest/stricttransportsecurity";
+ const NUM_TEST_FRAMES = 4;
+ const CONTENT_PAGE =
+ "http://mochi.test:8888/chrome/security/manager/ssl/tests/mochitest/stricttransportsecurity/page_blank.html";
+
+ Cu.import("resource://testing-common/BrowserTestUtils.jsm");
+ Cu.import("resource://testing-common/ContentTask.jsm");
+ Cu.import("resource://gre/modules/Task.jsm");
+
+ // This is how many sub-tests (testframes) in each round.
+ // When the round begins, this will be initialized.
+ var testsleftinround = 0;
+ var currentround = "";
+ var mainWindow =
+ window.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).
+ rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIDOMWindow);
+
+ SpecialPowers.Services.prefs.setIntPref("browser.startup.page", 0);
+
+ var testframes = {
+ 'samedom':
+ {'url': "http://example.com" + STSPATH + "/verify.sjs",
+ 'expected': {'plain': 'SECURE',
+ 'subdom': 'SECURE',
+ 'nosts': 'INSECURE'}},
+ 'subdom':
+ {'url': "http://test1.example.com" + STSPATH + "/verify.sjs",
+ 'expected': {'plain': 'INSECURE',
+ 'subdom': 'SECURE',
+ 'nosts': 'INSECURE'}},
+ 'otherdom':
+ {'url': "http://example.org" + STSPATH + "/verify.sjs",
+ 'expected': {'plain': 'INSECURE',
+ 'subdom': 'INSECURE',
+ 'nosts': 'INSECURE'}},
+ 'alreadysecure':
+ {'url': "https://test2.example.com" + STSPATH + "/verify.sjs",
+ 'expected': {'plain': 'SECURE',
+ 'subdom': 'SECURE',
+ 'nosts': 'SECURE'}},
+ };
+
+ function whenDelayedStartupFinished(aWindow, aCallback) {
+ SpecialPowers.Services.obs.addObserver(function observer(aSubject, aTopic) {
+ if (aWindow == aSubject) {
+ SpecialPowers.Services.obs.removeObserver(observer, aTopic);
+ SimpleTest.executeSoon(aCallback);
+ }
+ }, "browser-delayed-startup-finished", false);
+ }
+
+ function testOnWindow(aIsPrivate, aCallback) {
+ let win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
+
+ Task.spawn(function* () {
+ yield new Promise(resolve => whenDelayedStartupFinished(win, resolve));
+
+ let browser = win.gBrowser.selectedBrowser;
+ yield BrowserTestUtils.loadURI(browser, CONTENT_PAGE);
+ yield BrowserTestUtils.browserLoaded(browser);
+
+ aCallback(win);
+ });
+ }
+
+ function startRound(win, isPrivate, round) {
+ currentround = round;
+ testsleftinround = NUM_TEST_FRAMES;
+ SimpleTest.info("TESTS LEFT IN ROUND " + currentround + ": " + testsleftinround);
+
+ let browser = win.gBrowser.selectedBrowser;
+ let src = "https://example.com" + STSPATH + "/" + round + "_bootstrap.html";
+
+ ContentTask.spawn(browser, src, function* (contentSrc) {
+ let frame = content.document.createElement("iframe");
+ frame.setAttribute('id', 'ifr_bootstrap');
+ frame.setAttribute('src', contentSrc);
+
+ return new Promise(resolve => {
+ frame.addEventListener("load", resolve);
+ content.document.body.appendChild(frame);
+ });
+ }).then(() => {
+ onMessageReceived(win, isPrivate, "BOOTSTRAP " + round);
+ });
+ }
+
+ function loadVerifyFrames(win, isPrivate, round) {
+ loadVerifyFrame(win, isPrivate, testframes.samedom, 'samedom', function() {
+ loadVerifyFrame(win, isPrivate, testframes.subdom, 'subdom', function() {
+ loadVerifyFrame(win, isPrivate, testframes.otherdom, 'otherdom', function() {
+ loadVerifyFrame(win, isPrivate, testframes.alreadysecure, 'alreadysecure');
+ });
+ });
+ });
+ }
+
+ function loadVerifyFrame(win, isPrivate, test, testName, aCallback) {
+ let id = 'ifr_' + testName;
+ let src = test.url + '?id=' + testName;
+ let browser = win.gBrowser.selectedBrowser;
+
+ ContentTask.spawn(browser, [id, src], function* ([contentId, contentSrc]) {
+ let frame = content.document.createElement("iframe");
+ frame.setAttribute('id', contentId);
+ frame.setAttribute('src', contentSrc);
+
+ return new Promise(resolve => {
+ frame.addEventListener("load", () => {
+ resolve(frame.contentDocument.location.protocol);
+ });
+
+ content.document.body.appendChild(frame);
+ });
+ }).then(scheme => {
+ if (scheme == 'https:') {
+ onMessageReceived(win, isPrivate, "SECURE " + testName);
+ } else {
+ onMessageReceived(win, isPrivate, "INSECURE " + testName);
+ }
+
+ if (aCallback) {
+ aCallback();
+ }
+ });
+ }
+
+ /**
+ * Messages received are in this format:
+ * (BOOTSTRAP|SECURE|INSECURE) testid
+ * For example: "BOOTSTRAP subdom"
+ * or: "INSECURE otherdom"
+ */
+ function onMessageReceived(win, isPrivate, data) {
+ let result = data.split(/\s+/);
+ if (result.length != 2) {
+ SimpleTest.ok(false, data);
+ return;
+ }
+
+ if (result[0] === "BOOTSTRAP") {
+ loadVerifyFrames(win, isPrivate, currentround);
+ return;
+ }
+
+ // check if the result (SECURE/INSECURE) is expected for this round/test
+ // combo
+ dump_STSState(isPrivate);
+ SimpleTest.is(result[0], testframes[result[1]].expected[currentround],
+ "in ROUND " + currentround +
+ ", test " + result[1]);
+ testsleftinround--;
+
+ // if this round is complete...
+ if (testsleftinround < 1) {
+ SimpleTest.info("DONE WITH ROUND " + currentround);
+ // remove all the iframes in the document
+ let browser = win.gBrowser.selectedBrowser;
+ ContentTask.spawn(browser, testframes, function* (contentTestFrames) {
+ content.document.body.removeChild(
+ content.document.getElementById('ifr_bootstrap'));
+ for (let test in contentTestFrames) {
+ content.document.body.removeChild(
+ content.document.getElementById('ifr_' + test));
+ }
+ }).then(() => {
+ currentround = "";
+
+ if (!isPrivate) {
+ clean_up_sts_state(isPrivate);
+ }
+ // Close test window.
+ win.close();
+ // And advance to the next test.
+ // Defer this so it doesn't muck with the stack too much.
+ SimpleTest.executeSoon(nextTest);
+ });
+ }
+ }
+
+ function test_sts_before_private_mode() {
+ testOnWindow(false, function(win) {
+ SimpleTest.info("In public window");
+ dump_STSState(false);
+ startRound(win, false, 'plain');
+ });
+ }
+
+ function test_sts_in_private_mode() {
+ testOnWindow(true, function(win) {
+ SimpleTest.info("In private window");
+ dump_STSState(true);
+ startRound(win, true, 'subdom');
+ });
+ }
+
+ function test_sts_after_exiting_private_mode() {
+ testOnWindow(false, function(win) {
+ SimpleTest.info("In a new public window");
+ dump_STSState(false);
+ startRound(win, false, 'nosts');
+ });
+ }
+
+ function clean_up_sts_state(isPrivate) {
+ // erase all signs that this test ran.
+ SimpleTest.info("Cleaning up STS data");
+ let flags = isPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
+ SpecialPowers.cleanUpSTSData("http://example.com", flags);
+ dump_STSState(isPrivate);
+ }
+
+ function dump_STSState(isPrivate) {
+ let sss = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ let flags = isPrivate ? Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
+ SimpleTest.info("State of example.com: " + sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS, "example.com", flags));
+ }
+
+ // These are executed in the order presented.
+ // 0. test that STS works before entering private browsing mode.
+ // (load sts-bootstrapped "plain" tests)
+ // ... clear any STS data ...
+ // 1. test that STS works in private browsing mode
+ // (load sts-bootstrapped "subdomain" tests)
+ // 2. test that after exiting private browsing, STS data is forgotten
+ // (verified with non-sts-bootstrapped pages)
+ // ... clear any STS data ...
+ var tests = [
+ test_sts_before_private_mode,
+ test_sts_in_private_mode,
+ test_sts_after_exiting_private_mode
+ ];
+
+ function finish() {
+ SpecialPowers.Services.prefs.clearUserPref("browser.startup.page");
+ SimpleTest.finish();
+ }
+ function nextTest() {
+ SimpleTest.executeSoon(tests.length ? tests.shift() : finish);
+ }
+ window.addEventListener('load', nextTest, false);
+ </script>
+</head>
+
+<body>
+ This test will load some iframes and do some tests.
+</body>
+</html>
diff --git a/security/manager/ssl/tests/mochitest/stricttransportsecurity/verify.sjs b/security/manager/ssl/tests/mochitest/stricttransportsecurity/verify.sjs
new file mode 100644
index 000000000..e5e4eb5f6
--- /dev/null
+++ b/security/manager/ssl/tests/mochitest/stricttransportsecurity/verify.sjs
@@ -0,0 +1,47 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// SJS file that serves un-cacheable responses for STS tests that postMessage
+// to the parent saying whether or not they were loaded securely.
+
+function handleRequest(request, response)
+{
+ var query = {};
+ request.queryString.split('&').forEach(function (val) {
+ var [name, value] = val.split('=');
+ query[name] = unescape(value);
+ });
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ if ('id' in query) {
+ var outstr = [
+ " <!DOCTYPE html>",
+ " <html> <head> <title>subframe for STS</title>",
+ " <script type='text/javascript'>",
+ " var self = window;",
+ " window.addEventListener('load', function() {",
+ " if (document.location.protocol === 'https:') {",
+ " self.parent.postMessage('SECURE " + query['id'] + "',",
+ " 'http://mochi.test:8888');",
+ " } else {",
+ " self.parent.postMessage('INSECURE " + query['id'] + "',",
+ " 'http://mochi.test:8888');",
+ " }",
+ " }, false);",
+ " </script>",
+ " </head>",
+ " <body>",
+ " STS state verification frame loaded via",
+ " <script>",
+ " document.write(document.location.protocol);",
+ " </script>",
+ " </body>",
+ " </html>"].join("\n");
+ response.write(outstr);
+ } else {
+ response.write("ERROR: no id provided");
+ }
+}
diff --git a/security/manager/ssl/tests/moz.build b/security/manager/ssl/tests/moz.build
new file mode 100644
index 000000000..e7c06c21e
--- /dev/null
+++ b/security/manager/ssl/tests/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += ['unit']
+
+TEST_DIRS += [
+ 'gtest',
+ 'mochitest',
+]
+
+XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
+
+if not CONFIG['MOZ_NO_SMART_CARDS']:
+ XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell-smartcards.ini']
diff --git a/security/manager/ssl/tests/unit/.eslintrc.js b/security/manager/ssl/tests/unit/.eslintrc.js
new file mode 100644
index 000000000..1f96e7821
--- /dev/null
+++ b/security/manager/ssl/tests/unit/.eslintrc.js
@@ -0,0 +1,5 @@
+"use strict";
+
+module.exports = { // eslint-disable-line no-undef
+ "extends": "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+};
diff --git a/security/manager/ssl/tests/unit/bad_certs/badSubjectAltNames.pem b/security/manager/ssl/tests/unit/bad_certs/badSubjectAltNames.pem
new file mode 100644
index 000000000..62406aaac
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/badSubjectAltNames.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5DCCAc6gAwIBAgIUaauScBIwFX7ueYmCXknl2gMYElAwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowJjEkMCIGA1UEAwwbRUUgd2l0aCBiYWQgc3ViamVjdEFsdE5hbWVz
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2
+ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdF
+h/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6n
+cOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAv
+OnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2nj
+tIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXt
+jQIDAQABox4wHDAaBgNVHREEEzARgg8qLiouZXhhbXBsZS5jb20wCwYJKoZIhvcN
+AQELA4IBAQBQsZKhZe/1VkfifLqD4bni/7VY8xfXQO4DDu9HSkFmeJOhaIzfdQls
+q4LN+HVuJcJQZD1ni24UbJib+Jh8cbuzRA8l6w+PUBB6XPeF8BfYDkSbDoIYxj6h
+OclX4HInco4O4Ul+1K0u7qF9xtMYK+xaAZqiEzU638nW2n5EWV8v7y5dJsmx7rz3
+s7boQNkjgZo7R0Lw5Z8zzKYE0jVp+dRztP/f0X9uG6YW3thFIfHbewXBKP1kiIv6
+jymQMdcdnc+LhtM5/+KJcCstGA1YUaZ7pNkU7/KyB0Ch1m+b40EOSnZKelUFkmvp
+yaMC1hUND9LZjKwnGKNwuF5HR4OX/w0g
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/badSubjectAltNames.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/badSubjectAltNames.pem.certspec
new file mode 100644
index 000000000..1b368c26f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/badSubjectAltNames.pem.certspec
@@ -0,0 +1,3 @@
+issuer:Test CA
+subject:EE with bad subjectAltNames
+extension:subjectAlternativeName:*.*.example.com
diff --git a/security/manager/ssl/tests/unit/bad_certs/beforeEpoch.pem b/security/manager/ssl/tests/unit/bad_certs/beforeEpoch.pem
new file mode 100644
index 000000000..ffb961c45
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/beforeEpoch.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJzCCAhGgAwIBAgIUdXLIuQ4fxP+03n9N/HH0ZlV0c7owCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMTk0NjAyMTQwMDAwMDBaGA8yMDMxMDEw
+MTAwMDAwMFowLDEqMCgGA1UEAwwhQmVmb3JlIFVOSVggRXBvY2ggVGVzdCBFbmQt
+ZW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB
+/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRx
+CHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMC
+OosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdm
+Wqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGz
+ey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUD
+rNoYCjXtjQIDAQABo1swWTAjBgNVHREEHDAaghhiZWZvcmUtZXBvY2guZXhhbXBs
+ZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxo
+b3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEAgkj+Gwj2oJbjTvT8ivsSVfs1XHg6
+VOkPc8+DvFUY9l+lffyGUf8JQV0HuHHWOdPkSNAthqCYvsvzn1p21OFVo8EB7f5/
+mCz+u/YiWDDDjRfIYPUxvKIL4qqz+1dW3YcYOCG7luyNgajR9M9ivHGh7pX23Loa
+726oYYXWaY0KU2/CkLWLSvrdbcEiw/mUMrpKa7H2Zh0OVg6pcL1LNlUTGOWoyl9X
+u50M4iKLlb1wHiBTqXskKu6lM3yob6fVQ53S6Q6vKPsmD0hiKzGP5k8NLp5m0tHm
+a18x76ggEprPxGI3XXOCejGBbBIdswEX+WA904jMRwrrbLXxXLKSG72UKg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/beforeEpoch.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/beforeEpoch.pem.certspec
new file mode 100644
index 000000000..ac97b2231
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/beforeEpoch.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Before UNIX Epoch Test End-entity
+validity:19460214-20310101
+extension:subjectAlternativeName:before-epoch.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/beforeEpochINT.pem b/security/manager/ssl/tests/unit/bad_certs/beforeEpochINT.pem
new file mode 100644
index 000000000..62ddea52a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/beforeEpochINT.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6zCCAdWgAwIBAgIUewecPPOfV1pIxDqNQZDAK7WnmikwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMTk0NjAyMTQwMDAwMDBaGA8yMDMxMDEw
+MTAwMDAwMFowLjEsMCoGA1UEAwwjQmVmb3JlIFVOSVggRXBvY2ggVGVzdCBJbnRl
+cm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W
+1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtq
+ZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx
+0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthV
+t2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo
+4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx
+1QOs2hgKNe2NAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAsG
+CSqGSIb3DQEBCwOCAQEAZOcbi3DKkzazT2A2ZlqHdeY7tgVL8fiQnPvzfYpNgB+R
+pM3gkZRagkliv8o0ZKlkaoLDula6Q5Rhe2hY2+PSQNi/BkDdg/ituWOnH2ruX8Dm
+cWFFWJfGehf12dpJWhW+lovgQvbUmAVeMKMDfNIHgGZmwdVarYTN4LV7uu1abtIP
+mxFLc8x2CkGk9XQJXbts3cLwtZJiqAdMCuX5P4fmnLkaFAw+Vs+6aLBLOOD5WMF9
+vqwTRPDedtG+xmOhZ+J0YijRRfm4go5gCZj3XF3RgA35V7A/i3MCX2jPRfXDRywV
+8bsqZlIgILgdm4YCHlXpF9aqHJxz9AMKZs3Wk8mu7Q==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/beforeEpochINT.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/beforeEpochINT.pem.certspec
new file mode 100644
index 000000000..835e63f2b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/beforeEpochINT.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Before UNIX Epoch Test Intermediate
+validity:19460214-20310101
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/bad_certs/beforeEpochIssuer.pem b/security/manager/ssl/tests/unit/bad_certs/beforeEpochIssuer.pem
new file mode 100644
index 000000000..c234f9365
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/beforeEpochIssuer.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVjCCAkCgAwIBAgIUHY/2g5fyvV2MONrnjGi3fWc83j0wCwYJKoZIhvcNAQEL
+MC4xLDAqBgNVBAMMI0JlZm9yZSBVTklYIEVwb2NoIFRlc3QgSW50ZXJtZWRpYXRl
+MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMDgxNjA0BgNVBAMM
+LVRlc3QgRW5kLWVudGl0eSB3aXRoIEJlZm9yZSBVTklYIEVwb2NoIGlzc3VlcjCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAAaNiMGAwKgYDVR0RBCMwIYIfYmVmb3JlLWVwb2NoLWlzc3Vlci5leGFtcGxl
+LmNvbTAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9sb2NhbGhv
+c3Q6ODg4OC8wCwYJKoZIhvcNAQELA4IBAQAAYmpIy15lrWSrorG+HfjZNckhAsCG
+1BOVYRr+s1Zks4wj1aMXFSzblgNgdRuZA20TkRfJKw40cyuNLfm5DhKZUbo+0LAN
+jthu2cHFBaQn+XV6xMb2tEKTU8rBqzAYIAnmEIlLukYQBVICL9tirC1JJhqe1/S8
+U139izFYNnSqNmss2cJOuI4VM7B951v1h4mQYfcX1Sv27qWaKBK7k9fKBWWE0DCX
+YR1nB4RlI+92ncTOwbjtXR92gqR/z1wGDOPj/0VNNUn4SKo5Xif9TqXh4LhnY9fD
+HgoZSMDxftXou1MjN0cWnIP6QMyLfg2kSN0vnQpVle6KgsxpfrgLiMoU
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/beforeEpochIssuer.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/beforeEpochIssuer.pem.certspec
new file mode 100644
index 000000000..9aabe2162
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/beforeEpochIssuer.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Before UNIX Epoch Test Intermediate
+subject:Test End-entity with Before UNIX Epoch issuer
+extension:subjectAlternativeName:before-epoch-issuer.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/ca-used-as-end-entity.pem b/security/manager/ssl/tests/unit/bad_certs/ca-used-as-end-entity.pem
new file mode 100644
index 000000000..ae40112c3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/ca-used-as-end-entity.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAiugAwIBAgIUBUmy5jtGrDso26TeIelwmtF+KFAwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowLzEtMCsGA1UEAwwkVGVzdCBJbnRlcm1lZGlhdGUgdXNlZCBhcyBF
+bmQtRW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABo3IwcDAMBgNVHRMEBTADAQH/MDIGCCsGAQUFBwEBBCYw
+JDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzAsBgNVHREEJTAj
+giFjYS11c2VkLWFzLWVuZC1lbnRpdHkuZXhhbXBsZS5jb20wCwYJKoZIhvcNAQEL
+A4IBAQApr3pPS4uWz6oPEhrTO73K+JTP2VRTKgtbooPhOZ6tCRz75P729RzVOEZF
+Vf87VSFTTXUdG5Q6+SDNuCdDuyyPR4q38s+8jgv3OVfsEbhPuSx73pLAzYg727Ip
+U2ROGoVysc3JrUfwPZSvQ/i4iqdb2sVwtqR5LM1nApy5+p6Ef8cwjfm9qsdrHlnx
+3VdiioEOp+8SKH5rzfZe+1jepRODlqvFEO9gFbaqjHLzL005xAcfpsZPH5JzDhqD
+g4QiIFlm+wwQ9pTBpk1ZmbgDyk4frrxughFsbR4zDDTfJCREa5RlwH34xOkx/cTu
+ee/qZzerx61VI88GvLK87eX2ZiH1
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/ca-used-as-end-entity.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/ca-used-as-end-entity.pem.certspec
new file mode 100644
index 000000000..8e16705b5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/ca-used-as-end-entity.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Test Intermediate used as End-Entity
+extension:basicConstraints:cA,
+extension:authorityInformationAccess:http://localhost:8888/
+extension:subjectAlternativeName:ca-used-as-end-entity.example.com
diff --git a/security/manager/ssl/tests/unit/bad_certs/default-ee.key b/security/manager/ssl/tests/unit/bad_certs/default-ee.key
new file mode 100644
index 000000000..8af23e068
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/default-ee.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAECggEBAJ7LzjhhpFTsseD+j4XdQ8kvWCXOLpl4hNDhqUnaosWs
+VZskBFDlrJ/gw+McDu+mUlpl8MIhlABO4atGPd6e6CKHzJPnRqkZKcXmrD2IdT9s
+JbpZeec+XY+yOREaPNq4pLDN9fnKsF8SM6ODNcZLVWBSXn47kq18dQTPHcfLAFeI
+r8vh6Pld90AqFRUw1YCDRoZOs3CqeZVqWHhiy1M3kTB/cNkcltItABppAJuSPGgz
+iMnzbLm16+ZDAgQceNkIIGuHAJy4yrrK09vbJ5L7kRss9NtmA1hb6a4Mo7jmQXqg
+SwbkcOoaO1gcoDpngckxW2KzDmAR8iRyWUbuxXxtlEECgYEA3W4dT//r9o2InE0R
+TNqqnKpjpZN0KGyKXCmnF7umA3VkTVyqZ0xLi8cyY1hkYiDkVQ12CKwn1Vttt0+N
+gSfvj6CQmLaRR94GVXNEfhg9Iv59iFrOtRPZWB3V4HwakPXOCHneExNx7O/JznLp
+xD3BJ9I4GQ3oEXc8pdGTAfSMdCsCgYEA16dz2evDgKdn0v7Ak0rU6LVmckB3Gs3r
+ta15b0eP7E1FmF77yVMpaCicjYkQL63yHzTi3UlA66jAnW0fFtzClyl3TEMnXpJR
+3b5JCeH9O/Hkvt9Go5uLODMo70rjuVuS8gcK8myefFybWH/t3gXo59hspXiG+xZY
+EKd7mEW8MScCgYEAlkcrQaYQwK3hryJmwWAONnE1W6QtS1oOtOnX6zWBQAul3RMs
+2xpekyjHu8C7sBVeoZKXLt+X0SdR2Pz2rlcqMLHqMJqHEt1OMyQdse5FX8CT9byb
+WS11bmYhR08ywHryL7J100B5KzK6JZC7smGu+5WiWO6lN2VTFb6cJNGRmS0CgYAo
+tFCnp1qFZBOyvab3pj49lk+57PUOOCPvbMjo+ibuQT+LnRIFVA8Su+egx2got7pl
+rYPMpND+KiIBFOGzXQPVqFv+Jwa9UPzmz83VcbRspiG47UfWBbvnZbCqSgZlrCU2
+TaIBVAMuEgS4VZ0+NPtbF3yaVv+TUQpaSmKHwVHeLQKBgCgGe5NVgB0u9S36ltit
+tYlnPPjuipxv9yruq+nva+WKT0q/BfeIlH3IUf2qNFQhR6caJGv7BU7naqNGq80m
+ks/J5ExR5vBpxzXgc7oBn2pyFJYckbJoccrqv48GRBigJpDjmo1f8wZ7fNt/ULH1
+NBinA5ZsT8d0v3QCr2xDJH9D
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/default-ee.key.keyspec b/security/manager/ssl/tests/unit/bad_certs/default-ee.key.keyspec
new file mode 100644
index 000000000..4ad96d515
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/default-ee.key.keyspec
@@ -0,0 +1 @@
+default
diff --git a/security/manager/ssl/tests/unit/bad_certs/default-ee.pem b/security/manager/ssl/tests/unit/bad_certs/default-ee.pem
new file mode 100644
index 000000000..0a9eaebb5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/default-ee.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhTCCAm+gAwIBAgIUNRvpOhsDHEYbRf6bsiAPbvKe2VAwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowGjEYMBYGA1UEAwwPVGVzdCBFbmQtZW50aXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABo4HKMIHH
+MIGQBgNVHREEgYgwgYWCCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbYIVKi5waW5u
+aW5nLmV4YW1wbGUuY29tgigqLmluY2x1ZGUtc3ViZG9tYWlucy5waW5uaW5nLmV4
+YW1wbGUuY29tgigqLmV4Y2x1ZGUtc3ViZG9tYWlucy5waW5uaW5nLmV4YW1wbGUu
+Y29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9z
+dDo4ODg4LzALBgkqhkiG9w0BAQsDggEBAH6+Qe/y1TTCx2w6f31VWp5lcizPkS8s
+ODfbgT9pKYqqvYDeiDu3q8SLGHTTsHWWewBCu5Jd0mXPXfZ4FEHcwbVJZUZBvQVr
+1aNBCriuzhNUyfjkvfCgM4OuxgNwjbihGDE8VzfxTiz8mDN0AgACCZaUTQnybQc0
+SW+ldxspBgQJom0tkZ+TGi80L3/5P5J2+7AchxhAZzQmebDnxNYDZXCJH8w15was
+OzM5BrQzz3vuxupO7lsRzZIzAU+uQD4bjcMpz3oMdj3/0lb0HZGMdU22Ub36PvLC
+6mYbTtf0IS5TVyLnbCNeliE6zoPnQPBzAUfoOeD1Tn6HQUQUT8oTf2E=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/default-ee.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/default-ee.pem.certspec
new file mode 100644
index 000000000..554339ff5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/default-ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Test End-entity
+extension:subjectAlternativeName:localhost,*.example.com,*.pinning.example.com,*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/eeIssuedByNonCA.pem b/security/manager/ssl/tests/unit/bad_certs/eeIssuedByNonCA.pem
new file mode 100644
index 000000000..08c574fd1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/eeIssuedByNonCA.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDITCCAgugAwIBAgIURex/TuOH9TNqma6czhjn0gJqzqwwCwYJKoZIhvcNAQEL
+MBoxGDAWBgNVBAMMD1Rlc3QgRW5kLWVudGl0eTAiGA8yMDE1MTEyODAwMDAwMFoY
+DzIwMTgwMjA1MDAwMDAwWjAeMRwwGgYDVQQDDBNFRSBJc3N1ZWQgYnkgbm9uLUNB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2
+ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdF
+h/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6n
+cOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAv
+OnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2nj
+tIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXt
+jQIDAQABo1swWTAjBgNVHREEHDAagglsb2NhbGhvc3SCDSouZXhhbXBsZS5jb20w
+MgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4
+ODgvMAsGCSqGSIb3DQEBCwOCAQEAnLI+egtdtaCj/pGgINrEi98m6gvK+wANDhDS
+RhX2IztG/xuLCXIEcecjl2ifppklo6BnGqMebuLxndygkEGXiuvTvAbtd8Ac3s7O
+Cln/JW3OOBs6a3UJJeo1rpADn5F7tSXJshnVFNshZlXACnb25JIvKKIZwEhNKCmz
+whfX5xVW7RumZ5I4BYrE16YkQKQ9Fc7orioPbcTfH/zmoBBseMFi9UHCsI/u6P2/
+2DpdD2hlld/Cy0cEzb8IJFnx1CYIpfKCP2OZR+YEn8i1P6WwEyYy47YlFmZGkVmQ
+t1zEXNWT6xdW9+jREoyvl2pb/4BzQDzUhUg6P1jbFqHKtBgFqg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/eeIssuedByNonCA.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/eeIssuedByNonCA.pem.certspec
new file mode 100644
index 000000000..63c36d34b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/eeIssuedByNonCA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test End-entity
+subject:EE Issued by non-CA
+extension:subjectAlternativeName:localhost,*.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/eeIssuedByV1Cert.pem b/security/manager/ssl/tests/unit/bad_certs/eeIssuedByV1Cert.pem
new file mode 100644
index 000000000..e24448493
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/eeIssuedByV1Cert.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5jCCAdCgAwIBAgIUWdJEDrMcdJcIJoGstXeNPWoUzCcwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1YxIENlcnQwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowHzEdMBsGA1UEAwwURUUgSXNzdWVkIGJ5IFYxIENlcnQwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erk
+NUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwC
+fs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1m
+CyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTM
+HGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m
+1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGj
+JzAlMCMGA1UdEQQcMBqCCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbTALBgkqhkiG
+9w0BAQsDggEBAFlYTwajTjFg0lvULVveYmWQWzPlRjdDi+TM/guuC13D9sDXN9vi
+y5ofPdtqlGo2owjEe8XII/3enZHJqJAk/zDcjVg7ErXoui54K5q6eZGN+6hdhiGB
+iT4TxrHAQXPfkXgLr6AQx0JkIO5G8l/PZDETLkxNMoFssQwb1x2D28LxYhqcGQJY
+A7h8M8kMNZiltGqLUBXdYdmM1IljJb/BlqULV7QbCh8jXsvdP3leIQCRK+vUONcK
+MjnLEzAYhNhRYWkjCBF/Q+qsPlL/aSbkupr6z4lXuCUIPF8TWs8q0V0uwGeOT0MZ
+aWkw8tsi1UYRR9Z5WdTe8l0dYF0G/kpD44Q=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/eeIssuedByV1Cert.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/eeIssuedByV1Cert.pem.certspec
new file mode 100644
index 000000000..9ed9b33db
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/eeIssuedByV1Cert.pem.certspec
@@ -0,0 +1,3 @@
+issuer:V1 Cert
+subject:EE Issued by V1 Cert
+extension:subjectAlternativeName:localhost,*.example.com
diff --git a/security/manager/ssl/tests/unit/bad_certs/emptyIssuerName.pem b/security/manager/ssl/tests/unit/bad_certs/emptyIssuerName.pem
new file mode 100644
index 000000000..719f4e760
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/emptyIssuerName.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5TCCAc+gAwIBAgIUWcXPQzwjDQvgxBhAb1cUwuJNgfswCwYJKoZIhvcNAQEL
+MAAwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowLTErMCkGA1UE
+AwwiRW5kIGVudGl0eSBzaWduZWQgYnkgZW1wdHkgbmFtZSBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs
+9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8
+HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7Ak
+kqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJet
+lmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2r
+kQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMqMCgw
+JgYDVR0RBB8wHYIbZW1wdHlpc3N1ZXJuYW1lLmV4YW1wbGUuY29tMAsGCSqGSIb3
+DQEBCwOCAQEAqbRuhfV+zSaD8FqWMaaX3Q0V08aazNE+xt/4z0E79Ap0LWUs8h2j
+IVC61EsJKrgYMseNd6DqyzhucQYgH1yuyZjb9VC+BuEA/GvcbzxMKr9jf9hMFXvf
+PtyrAPDKbkscfjF1Xpq0nfTld0zxDaa01lZEyY175Ga8OM0oUaOr9tsa/m6d4/qT
+2J1qOus/doyoD8CJB5vOAFjK1C0u4EMmZoayjiOQori61wsmcn6I077Pdwbhi49d
+iuZGc3UU9VBPyQ6CWN5tP2e2OSfT3p1ep/7gb7RJXQXEHksokq53Rg8HM97wQxLi
+134jJOJFJmeq+8pZ9NSTwrA6mo1nLfiPwA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/emptyIssuerName.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/emptyIssuerName.pem.certspec
new file mode 100644
index 000000000..a99d84b79
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/emptyIssuerName.pem.certspec
@@ -0,0 +1,3 @@
+issuer:
+subject:End entity signed by empty name CA
+extension:subjectAlternativeName:emptyissuername.example.com
diff --git a/security/manager/ssl/tests/unit/bad_certs/emptyNameCA.pem b/security/manager/ssl/tests/unit/bad_certs/emptyNameCA.pem
new file mode 100644
index 000000000..1946feeb1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/emptyNameCA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvTCCAaegAwIBAgIUQYl3Nyjq38ZPBpJZBi8APD7LGXcwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahE
+jhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1
+a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1p
+GrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW
+2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcO
+p2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJR
+xDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYw
+CwYJKoZIhvcNAQELA4IBAQAbXSUfUwpYXLieOce+6P1Sqtcg0nuDf46vmR+1vykN
+sRZNnvsO32PNCh+WgsvJ/Yy6SPS3LKG/NwBK2yH0fiq/b+JPK15cvV/hRkb23ght
+4D1+CZ6hMgirvMDFMk9wb24zUMn1MshHSfed5RM01GCnSTsBUldM93bFaMNlghyH
+AIFz3aj2VTMZvL8XeoytDChfE/RYoI4eFD8O2MPyRCkJ1grN8PmpoU5xdiDIpKIp
+4UK5/SnRnyci6oBpjJTECnboTv0qyfpODr/QBU5iO+8Yg02Uco27fiy5MmcejRg1
+7+pRFfrvBU7DP3uJhGOTKZzsrgsrYK6qSo7zbPyhD8oJ
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/emptyNameCA.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/emptyNameCA.pem.certspec
new file mode 100644
index 000000000..0a7cfdfd8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/emptyNameCA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/bad_certs/ev-test-intermediate.pem b/security/manager/ssl/tests/unit/bad_certs/ev-test-intermediate.pem
new file mode 100644
index 000000000..dc231eafb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/ev-test-intermediate.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDNzCCAiGgAwIBAgIUeWc23T2mQmvsb7b3an7jH8J3eAwwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAfMR0wGwYDVQQDDBRldi10ZXN0LWludGVybWVkaWF0ZTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
+SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYL
+K7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwc
+bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
+JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaN5
+MHcwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwRwYIKwYBBQUHAQEEOzA5MDcG
+CCsGAQUFBzABhitodHRwOi8vbG9jYWxob3N0Ojg4ODgvZXYtdGVzdC1pbnRlcm1l
+ZGlhdGUvMBEGA1UdIAQKMAgwBgYEVR0gADALBgkqhkiG9w0BAQsDggEBAHZl5S4d
+aiBNutInbA5t4qjcyhimG10JI70r14ijN5RXNf0TjCJjE1GDCEz3/VGAH+TFMO+c
+6jAKGro2hojGPwnth49D359dMMgppcpRGq+G4paB8PuXcmTlF3slFfDa8KIay4bB
++g2db724ctqtXEHE5/FcmpTNkZftO1lHCEw+O1Sle1Firulo75WivLWyNsOh2znO
++pBQ98oYqb3q+LmKnlFw61cFLcpJ6qOs9d0X0IvGHbh7KL9Hc97orLZ5qH3UsV7k
+Ews3BJjSqjZj75nciNzQUfEAYCK+t/I/tDSgebn/Ka5bVAv0iuglYHQksc4oXVgB
+WIn/SxQDsNphGGQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/ev-test-intermediate.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/ev-test-intermediate.pem.certspec
new file mode 100644
index 000000000..d5b585967
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/ev-test-intermediate.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:ev-test-intermediate
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://localhost:8888/ev-test-intermediate/
+extension:certificatePolicies:any
diff --git a/security/manager/ssl/tests/unit/bad_certs/ev-test.pem b/security/manager/ssl/tests/unit/bad_certs/ev-test.pem
new file mode 100644
index 000000000..7bdcf4d4d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/ev-test.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiigAwIBAgIUJ/RiEbbZUXgHnSnds1C7ViloXtQwCwYJKoZIhvcNAQEL
+MB8xHTAbBgNVBAMMFGV2LXRlc3QtaW50ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAw
+MDAwWhgPMjAxODAyMDUwMDAwMDBaMBIxEDAOBgNVBAMMB2V2LXRlc3QwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erk
+NUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwC
+fs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1m
+CyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTM
+HGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m
+1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGj
+fzB9MDoGCCsGAQUFBwEBBC4wLDAqBggrBgEFBQcwAYYeaHR0cDovL2xvY2FsaG9z
+dDo4ODg4L2V2LXRlc3QvMB8GA1UdIAQYMBYwFAYSKwYBBAHrSYUahRqFGgGDdAkB
+MB4GA1UdEQQXMBWCE2V2LXRlc3QuZXhhbXBsZS5jb20wCwYJKoZIhvcNAQELA4IB
+AQBvoPaWE/YaF3sD+tYoAGdjNDbmQcP8QRhVG8wlIWSAfk9RRbvUbs8RNjdXntYV
+8J4ikq9/ajwHN85rJsRq3054qbqjit2Cn73tVhTzhe/h8xnXjLA357w/jXXXx1lD
+VZKxUvWqTvC9tHPjF3w17A2a1/3OltdLHPfzWF0Zf6Zo4uaaI8x+ayMMF6MCS3ZC
+FM2fNvIW/euVhjtLC3b+++5lMq/ZZCuJGB1kANDsX5LpXSZ23AXNhPrPxvgkmfoB
+TPoBoy2kD814qljp8G8RguNYpaz5wSYXZNROnVBCqafEbE8VlIAwAxWp5H5qN6Et
+F3OoQMb5dBIffK3lNw6UjFaZ
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/ev-test.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/ev-test.pem.certspec
new file mode 100644
index 000000000..10f802258
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/ev-test.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ev-test-intermediate
+subject:ev-test
+extension:authorityInformationAccess:http://localhost:8888/ev-test/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/bad_certs/evroot.key b/security/manager/ssl/tests/unit/bad_certs/evroot.key
new file mode 100644
index 000000000..a756a0705
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/evroot.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC1SYlcnQAQjRGh
++Z+HqePRpdtd+uzxiNpXv2QTaI8s5HIs/xCQOMF0Ask6Kkc9vShq7T/c02PPWikU
+dwG92BjXYVv5NWvV08gzaqqMCXE2igbDzURhuT5RQk4XRLsuqtRqqzjOGWghlh+H
+cUoWY2k/CXYc301roSXqzse+Jw04j3ifbN94rjFE7SjEXnkpOGOnoipImAo2pA5y
+1XnJuSXf+MeTNi/9aJenwXVMXpfJZ8Pq3RquiqLMzjSKAWm4Diii1wwalgxvM18t
+oJubZD9av7pJ6Kqpgelg4n2HSAvdVd2UF/oYUJ+7VUzPgaQ5fouoEoo0vfJ4ZcGJ
+5XNPsikFAgMBAAECggEBAJg9VPlNb0x26yPW+T14UjUwz3Ow0WJUxueBdo1F9VaB
+0dAvsr0qrGq8HDiYYJNcUqDY9BSCAQOUd4MUHYZL/zCANjilwBUlcK6dGPPYyhY+
++0dbDd3zLn4W7HVl5rteAlxBxcZuV6A87eVUIh+DBFNHosTEUcPc5Ha3h84MBXJE
+vp4E7xMRjbuz1eCmzIcCnq/Upp7ZsUdZsV452KmITlb1TS+asBPw0V8xipq2svc9
+HsPJ/idK6JQxoQZAvniZsAEcXlCToYNHCGid4QBjTaveYPvWqu+joz3zSh829gwE
+MDa3SNHJ7pjEAxoK/sYO/aCpkL5ST1YU6sT9s0pS+VECgYEA6twssz5f8co3a72V
+vWoXd9LPT6xHVF6S0RpiCbnV5N7UeDRYHBabPIhHQqCeoYdQXBylVBTY0ltJdjLV
+7CqqBSM0MPrUmJJ3en1o4Dj1YaO4lp5gsKJj3vv9pIqbD/OdlbyIsVJnyK3pe1EH
+lI5B5DMknYf32xCdXXRYTYa8wdcCgYEAxZrldqIWRwJI2USlW56b+TKZ2jQexW5V
+jrqCGrzhv1e3nPQR0pBMd0+duh8VGF9gewV0oIIF1uwotmo21jQjLqry/qN1Yauv
+nWRLaNs4yZZMuMluwKxh66ZNBbRGVC9COXb1rN5OzJVTbS31eJVPk/DP2cWPt4ui
+p23VrChNyIMCgYEAwdLvOQYzHFKspkgR+f5CW+somDIvs9tRAyzo1+n8MiQL6SAZ
+zySA/NXjKYNxJxGLKlmhv+BsiD46REfz8DHNmuvQuNNo/Hl0DSzOjq2zJN9/CR6v
+4VZDYdVJILAbBHEjDl5H2T+O0zljxRe8T8ePbYsfnrqFvM7bcDMCZQjbYoUCgYEA
+hSG421aU376ASjFfnvybZSdcVJCs8qNFbWXm5hC/n2R/xnUB1PV3LyMqxwzN75/C
+pt+kFcfEG2r8evnQfDygP37ZPAnwuZ8sMEQ0Mi8QcXCbvBuqTJFXX6apWeB9SZaV
+bZXiK1eTi25HyNUf/t/Jv4iM4NGj5CtlqJvtS5HT5fUCgYEA3El7BrkgyL4LAHe3
+mOl37vdEqQ7Cxdfmy7IkSPrHLagaMxgODYoC6DFGDH/H/TphL3uZMLYbeZ+OkI5j
+LpugQJtqpwsDo7p4dCYmO1vVhD34R27bXRT2qGE+uvW5zVykL1+9KALgjk5J5XCf
+UVFRDKpassHG6z7+kpXRbowlyRY=
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/evroot.key.keyspec b/security/manager/ssl/tests/unit/bad_certs/evroot.key.keyspec
new file mode 100644
index 000000000..1a3d76a55
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/evroot.key.keyspec
@@ -0,0 +1 @@
+ev
diff --git a/security/manager/ssl/tests/unit/bad_certs/evroot.pem b/security/manager/ssl/tests/unit/bad_certs/evroot.pem
new file mode 100644
index 000000000..cd2fd7ed8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/evroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUW9j5PS8YoKgynZdYa9i2Kwexnp8wCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MDEwMTAwMDAwMFoYDzIwMzUwMTAx
+MDAwMDAwWjARMQ8wDQYDVQQDDAZldnJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC1SYlcnQAQjRGh+Z+HqePRpdtd+uzxiNpXv2QTaI8s5HIs/xCQ
+OMF0Ask6Kkc9vShq7T/c02PPWikUdwG92BjXYVv5NWvV08gzaqqMCXE2igbDzURh
+uT5RQk4XRLsuqtRqqzjOGWghlh+HcUoWY2k/CXYc301roSXqzse+Jw04j3ifbN94
+rjFE7SjEXnkpOGOnoipImAo2pA5y1XnJuSXf+MeTNi/9aJenwXVMXpfJZ8Pq3Rqu
+iqLMzjSKAWm4Diii1wwalgxvM18toJubZD9av7pJ6Kqpgelg4n2HSAvdVd2UF/oY
+UJ+7VUzPgaQ5fouoEoo0vfJ4ZcGJ5XNPsikFAgMBAAGjHTAbMAwGA1UdEwQFMAMB
+Af8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAO1EZ134zXCiYSMixYSVP
+gAXWdR8zvaeS8UF0Xihle6nBdtkcmhiMgxXecMv7P7xO/U/wz5NAyJ1cvqaxrPbn
+8bekVCCsAAae6mVJIsVeuLtg3f89Qmx6KF6By2NI5R/AX5gxs0V9Tvjp9NfpIWh9
+I0BO0/REmq+CxKWjO6Loq0JA/QRW1jnD3XLitJ9QiCfnLqgUAG8JnkhG/JtpcJC3
+91SluwhVw+8i7caDOgHZGvjBEycyje0iyDLybaVjv2PpyuQx8H6hDzTGd2bNDl22
+fZ0FsOYCH6TJPx7nsCJCQ8/jGsRAGPxbItwSpTQJegKVaJ9s2dOAreJdkQFSIEo+
+3g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/evroot.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/evroot.pem.certspec
new file mode 100644
index 000000000..3121f3486
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/evroot.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:evroot
+subjectKey:ev
+issuerKey:ev
+validity:20150101-20350101
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/bad_certs/expired-ee.pem b/security/manager/ssl/tests/unit/bad_certs/expired-ee.pem
new file mode 100644
index 000000000..3c97dc9f3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/expired-ee.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGDCCAgKgAwIBAgIUW6mdE/nOX+M5zMEeIHpOn0cOWLgwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxMzAxMDEwMDAwMDBaGA8yMDE0MDEw
+MTAwMDAwMFowIjEgMB4GA1UEAwwXRXhwaXJlZCBUZXN0IEVuZC1lbnRpdHkwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
+2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
+JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
+jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
+BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
+He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
+AAGjVjBUMB4GA1UdEQQXMBWCE2V4cGlyZWQuZXhhbXBsZS5jb20wMgYIKwYBBQUH
+AQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqG
+SIb3DQEBCwOCAQEAsojdWfBBJsaUmPKLdSCOn3/7PMoWE7m1mmKXf2dz+qW4SKWb
+b2cVxoDMzU/AooTDRnrYveB1ir4Ej/e1a7Wjs8iZgHL9udIlQ7Yw7N7EB/Vt6dM8
+yEkwuiCd1XmiEEkUQtRk0DmJxCCyxrFNDGUDt7HOWX+jvbpnULKL9J26ax3exBpk
+J6F7WlmxFynroxHdxFPzxRCC+oUYt1jfvGjASIBl7tMJ/z8wO2ISMLaHpRX8iOIz
+e2bg02Z97zf63lTOtDa3034MUjBxcAuouHjgzKhyWQI0jZlWCeJSnM5MuhDbpiD+
+N3uDz6VBj13PpCGpA1esoM1ojrkQbmvHvWT+3A==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/expired-ee.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/expired-ee.pem.certspec
new file mode 100644
index 000000000..0a03bc36f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/expired-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Expired Test End-entity
+validity:20130101-20140101
+extension:subjectAlternativeName:expired.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/expiredINT.pem b/security/manager/ssl/tests/unit/bad_certs/expiredINT.pem
new file mode 100644
index 000000000..c6e51c000
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/expiredINT.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4TCCAcugAwIBAgIUP/xjJPJw5E0F3vjDGmPIDtk82ggwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxMTAxMDEwMDAwMDBaGA8yMDEzMDEw
+MTAwMDAwMFowJDEiMCAGA1UEAwwZRXhwaXJlZCBUZXN0IEludGVybWVkaWF0ZTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQEL
+A4IBAQAUWUmrK2X6alxQ6fWuj/3HNONQMipMDk7CQB/MhoWll+7tCHUMxck/QKaC
+1cnI0EY/c/ibX0J/NBm4AO1u3+qHfo5heFana/ybSj1trGEYWXXnDnRFr8SSRSjx
+VATBHBd1m9lckd+zDhLSk/lnYXyzJX8D39yYp2udP0cVGrbCT58aUXHwsEhfQpYY
+LN6xNYLcDCLtkrtZs4uwzFteL4NE8WflIlOTe+2Y/s1RTEzhs0+8avkaLyMzM+MI
+XDiVO3tFcX3ygsb+ndQaIL8vFUhLFEdr8xrjRuFuzbUu9EiR2oKiiNq1gZTyInqz
+S57UfV5LyaUa8mv2qNF2b3/FySXR
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/expiredINT.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/expiredINT.pem.certspec
new file mode 100644
index 000000000..38a0abd8a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/expiredINT.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Expired Test Intermediate
+validity:20110101-20130101
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/bad_certs/expiredissuer.pem b/security/manager/ssl/tests/unit/bad_certs/expiredissuer.pem
new file mode 100644
index 000000000..ff00cc00b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/expiredissuer.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPDCCAiagAwIBAgIUS9fUW0vPRYOaV8nstqC62Y6Qk08wCwYJKoZIhvcNAQEL
+MCQxIjAgBgNVBAMMGUV4cGlyZWQgVGVzdCBJbnRlcm1lZGlhdGUwIhgPMjAxNTEx
+MjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowLjEsMCoGA1UEAwwjVGVzdCBFbmQt
+ZW50aXR5IHdpdGggZXhwaXJlZCBpc3N1ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjXDBaMCQGA1UdEQQdMBuC
+GWV4cGlyZWRpc3N1ZXIuZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsG
+AQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEA
+alq65e2NhGZhr/ph19pR7V6Tijqwd5ZubfMOQX/kVex5EerZGYWvc31+wBk6nf5r
+0z6MscHAtu/M6kN/obrFoYYro7cWFCBd6GeaSG6aDBqrjT2nnBuZ2TGICRc4h8jM
+274y1x9qzC3/kzXKS0XqeFQmbwJ9eEaqn3m9Kb8jQPbyC+hZyUFatGhcKYbFPaAo
+fdgZL2FQpJ9uG1QsblYQ1ERBvbabN4Y0jg5XFza5nQftFkY6xevmYt7asc+npNkv
+qh2aNL3pmG9E0hXZD5N3LMbndP8rzG6vnBq/6SO2eGtos2AjEVXGypJzFhBGNOfs
+mwNzXXuiatkIHp2r5pyQuw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/expiredissuer.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/expiredissuer.pem.certspec
new file mode 100644
index 000000000..855f45422
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/expiredissuer.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Expired Test Intermediate
+subject:Test End-entity with expired issuer
+extension:subjectAlternativeName:expiredissuer.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem b/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem
new file mode 100644
index 000000000..f8baeea9f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAeOgAwIBAgIUPxkDf9AiLxVWjs21J/3by0oWUJcwCwYJKoZIhvcNAQEL
+MBkxFzAVBgNVBAMMDlVua25vd24gSXNzdWVyMCIYDzIwMTUxMTI4MDAwMDAwWhgP
+MjAxODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD0lETiBDZXJ0aWZpY2F0ZTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ
+6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUk
+nAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N
+/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAG
+JMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd
+7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEA
+AaM4MDYwNAYDVR0RBC0wK4IpYnVnNDEzOTA5LnhuLS1oeGFqYmhlZzJhejNhbC54
+bi0tanhhbHBkbHAwCwYJKoZIhvcNAQELA4IBAQBOBtdU6gEu6bu2pVN4QobNL1eS
+TFEGDazNKDq2s/90ddUz7DL029rhnzaIJib7dc4/dxgl5TgcL/8PwPUHRZXteRTX
+3hAA+XCunBacQYfZDiG8Bpp1ClslU0FVOngivFHw/mseM7hxOCAJg++1oa1uCqBz
+bcVvau/ISa/fApWBICmfRjaD7ztrdVyE5b2M90T7ywedBJHShk8gpJKp3s2/neQB
+CcBp3LNoIb0JDMZCk4pVCNTRB9DOpa5zMTu/Emd3EpV9wISEGvDmNUGmuunrgr2h
+xZ01TDSLknEJyZR7IbMjkhS4SFpIc6bK19h9yblzDUcCJj+ZH1Po23Fk6muT
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem.certspec
new file mode 100644
index 000000000..b3d840fbd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/idn-certificate.pem.certspec
@@ -0,0 +1,3 @@
+issuer:Unknown Issuer
+subject:IDN Certificate
+extension:subjectAlternativeName:bug413909.xn--hxajbheg2az3al.xn--jxalpdlp
diff --git a/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.key b/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.key
new file mode 100644
index 000000000..d10324fb3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICcAIBADANBgkqhkiG9w0BAQEFAASCAlowggJWAgEAAoGAANKbsS+4T93NKbOl
+GctmxDuNj4vlRbp5OEzmY+0D33WZFgDrkgeQ0lMM7OVE25mnHwWJaj7SBxZVNKqZ
+BX5HxH47yBrab6HhLjcmi1BGpVJo+drXzLSF2BouGdUNTwtoVKyvbXvmnZoIMTbh
+WvqPU8HIyE/GB3J53Q5V1zaaW90CAwEAAQJ/PEllBwvzkMJR1aLFJ3xbX9C97oXK
+1/4rJ5grsoURSlBwBANq4c+K5Usl5Ns5IVq9fpA/YYwtiy8IzGzRLbzNciBeSUW2
+s984nl5D3goUi7LITiQx/b5ZILBEuycvRez/ByG337YDl/xhOp6jXCIwBTDK6PkV
+nFNN878JEJUZAQJAD58XWXyFuAUbnGmvtV71dsmW29CQR9DM3ludYOpcZ/5PrGe+
+gD9LasWj8FD3a5ZvsU9c8QV2HlrebdlgsYO6VQJADXtjcRLOYaVRaMD5yThvsnmr
+QMug1Ukza7plJ3JjqseCYRosgdm2Nc94xAAYhZ4BjF6QBtEuPS7m80bnn6QzaQJA
+Cf1smj6m6RrjIHD5/BwhD/k1L5e+XR7rlRuzloHp3FtnKlMiIbPYkAyanZm50KTh
+AtxFDKG4ewsTid5lFsCuDQJAAUG4MkkbfdSoMwiSACTHnK5kvUR9+IO7TFZyqWur
+SLcSOzTyYyRFLNzrF/IeVw40fL4v1MLY+ZEOrCy22JW4yQJABFjdau4YyIsvm4Hx
+vDB1riDcH5lz0gck8gsGBD1hR8h4nUoHroi8gshDjIk+AXsTlH9i4LGJWKMetmSx
+nmTT4A==
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.key.keyspec b/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.key.keyspec
new file mode 100644
index 000000000..21ed73d60
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.key.keyspec
@@ -0,0 +1 @@
+rsa1016
diff --git a/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.pem b/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.pem
new file mode 100644
index 000000000..2ad219824
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICszCCAZ2gAwIBAgIULXNWBRUzJ/V70VPd4+9U6rf/lYswCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMCkxJzAlBgNVBAMMHkluYWRlcXVhdGUgS2V5IFNp
+emUgRW5kLUVudGl0eTCBnjANBgkqhkiG9w0BAQEFAAOBjAAwgYgCgYAA0puxL7hP
+3c0ps6UZy2bEO42Pi+VFunk4TOZj7QPfdZkWAOuSB5DSUwzs5UTbmacfBYlqPtIH
+FlU0qpkFfkfEfjvIGtpvoeEuNyaLUEalUmj52tfMtIXYGi4Z1Q1PC2hUrK9te+ad
+mggxNuFa+o9TwcjIT8YHcnndDlXXNppb3QIDAQABo2UwYzAtBgNVHREEJjAkgiJp
+bmFkZXF1YXRlLWtleS1zaXplLWVlLmV4YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYw
+JDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0B
+AQsDggEBALhNoeoHzQoeaGR/5bxF8VGE2XrCPoDatHwanND8rp1esVsmkkOSLof1
+DXgjZpg9ZJWw1PnprkYkV3XU1PIZWfUh/B/ir7QnsjRrORfJ+BP3Az+Sf1vX8fTB
+rfInVWtmRzTkzX/taouPBwJj+CN14hncbaT1FxX74XXmkZXHf2MfRjHjzuB1dNPP
+dAu+YVJSxZMv7QD/6qYZoy81dfqcN31IjxoFO0039ZmKrLpUjOZzOnmqzy0+wJpc
+Gz7lBvoHNv8SjVeUslb9IpP0uAqkpVYNZhWpPFpJ7xOdVKSWAUG1jDeMAD1tXC7R
+N0iiOloMHZ70o84Z6b7IB10IpoymVt4=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.pem.certspec
new file mode 100644
index 000000000..02b595dc9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/inadequateKeySizeEE.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test Intermediate
+subject:Inadequate Key Size End-Entity
+subjectKey:rsa1016
+extension:subjectAlternativeName:inadequate-key-size-ee.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/inadequatekeyusage-ee.pem b/security/manager/ssl/tests/unit/bad_certs/inadequatekeyusage-ee.pem
new file mode 100644
index 000000000..7e73075c1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/inadequatekeyusage-ee.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPTCCAiegAwIBAgIUOTTgOhTYLxvzfXf1OSZs5pCrnTUwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowLzEtMCsGA1UEAwwkSW5hZGVxdWF0ZSBLZXkgVXNhZ2UgVGVzdCBF
+bmQtZW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABo24wbDALBgNVHQ8EBAMCAQIwKQYDVR0RBCIwIIIeaW5h
+ZGVxdWF0ZWtleXVzYWdlLmV4YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYwJDAiBggr
+BgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0BAQsDggEB
+ABOkyemfFGxIC9qMI5B7cYQJ7Mrc8qG1wlnc5aKFZ65wnBURgQUw2TtVwBOweLGz
+82qR+MnDho8inUTyilydw7WwyLAi2A2jlqcgCaBcyRh8g7/BBJ9dEP2u1BNp2r9R
+8VvTlUKj/4Ta8/GG2mEKqyhd8bpevZaaTyjQUGcFYr76/XZ0D6TxtOM0SBLrybNg
+A/hbKste6MIXE0rJwUzN2+xWBvfeFqMwzRYZ3F/393qT3vWMgHZt4ZBo/RqQzEM4
+I8k6n3s7zssdPOXHy0lezYwkCtnya2OPdGEAyABviARZjIl9Hn+0nsymZmFUkV9A
+vUw83907j7buWerBFwnAxuo=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/inadequatekeyusage-ee.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/inadequatekeyusage-ee.pem.certspec
new file mode 100644
index 000000000..4d553890b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/inadequatekeyusage-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Inadequate Key Usage Test End-entity
+extension:keyUsage:cRLSign
+extension:subjectAlternativeName:inadequatekeyusage.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/ipAddressAsDNSNameInSAN.pem b/security/manager/ssl/tests/unit/bad_certs/ipAddressAsDNSNameInSAN.pem
new file mode 100644
index 000000000..6b7c848a1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/ipAddressAsDNSNameInSAN.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICzDCCAbagAwIBAgIUaWHoyJhhB4GixK3MP8mpJLbOZYMwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowFDESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvB
+xyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmT
+qyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5
+kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYS
+wHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwk
+BCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxgwFjAUBgNVHREE
+DTALggkxMjcuMC4wLjEwCwYJKoZIhvcNAQELA4IBAQCFFyBe938Z1/1WFILrNZ//
+3YlpJW0ww46JXCD+RheG2IdI2zdnbNOr7hUnLt4KprntLwmzWFYJInj+sq886c6x
+yKImpnVvjB0yDxJki85lNX6ARRHQrTNNf3wczSHdUmGlpzFUUuDkjYZS5Y6P//ms
+wPBxppkYguZVvU1s6nvHnuG2wDPKogeD5wmBSfJf8oVo03M6TqNYRK5socyeQ740
+LxXjlLYqQaUI+FEQLrCfv4LLrWpoH6mKg3hyKWoG6bEcCyvMBBJ+vDxCCpGE7b2L
+tMLn8BML+23CQ5SO53FR7dnWOuxSjnR+GRoFxw5E0qOZEGt+Fb9An5+R4xxRENfB
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/ipAddressAsDNSNameInSAN.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/ipAddressAsDNSNameInSAN.pem.certspec
new file mode 100644
index 000000000..766233847
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/ipAddressAsDNSNameInSAN.pem.certspec
@@ -0,0 +1,3 @@
+issuer:Test CA
+subject:127.0.0.1
+extension:subjectAlternativeName:127.0.0.1
diff --git a/security/manager/ssl/tests/unit/bad_certs/md5signature-expired.pem b/security/manager/ssl/tests/unit/bad_certs/md5signature-expired.pem
new file mode 100644
index 000000000..b81dbafa4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/md5signature-expired.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDMjCCAhygAwIBAgIUO/qAw3/gzbpGANaN0lKQaxLhTPwwCwYJKoZIhvcNAQEE
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxMTAxMDEwMDAwMDBaGA8yMDEzMDEw
+MTAwMDAwMFowLzEtMCsGA1UEAwwkVGVzdCBNRDVTaWduYXR1cmUtRXhwaXJlZCBF
+bmQtZW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABo2MwYTArBgNVHREEJDAigiBtZDVzaWduYXR1cmUtZXhw
+aXJlZC5leGFtcGxlLmNvbTAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0
+dHA6Ly9sb2NhbGhvc3Q6ODg4OC8wCwYJKoZIhvcNAQEEA4IBAQCJtN322gHdXy56
+sBTdOg+d3AS8AlXpOkm1yDyhICQznqsjdCz5qIUZQI+qm8cHVlLUjioTHWLds1i3
+wCQy4+l4VFFdP3Y7I2V49l3U9FPCHuZY1j8fyGyczAgKv/OYA2aQbcOPt1iR1S3J
+hji6e/bbxftBAXedt3QmvOmtqXRxuaiAaWgnL+nA2GfS3HQBaI0B13hxboPT9G8a
+u70eMAkBvloAwyrS2O/1cAZUPzCrqHeTVMidziHOXHHh4vFxBFICXYxG9ocFcWOb
+pA7E/QrHsTKI0OAr7336EWx1P5XITFZfe/SbBySCj088fMqW0yUuPN8+fvYMVoQr
+ifC5kUCZ
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/md5signature-expired.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/md5signature-expired.pem.certspec
new file mode 100644
index 000000000..e4c2b7008
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/md5signature-expired.pem.certspec
@@ -0,0 +1,6 @@
+issuer:Test CA
+subject:Test MD5Signature-Expired End-entity
+validity:20110101-20130101
+signature:md5WithRSAEncryption
+extension:subjectAlternativeName:md5signature-expired.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/md5signature.pem b/security/manager/ssl/tests/unit/bad_certs/md5signature.pem
new file mode 100644
index 000000000..de1317577
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/md5signature.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDKDCCAhKgAwIBAgIUCcBjO7AcpbQJxZbg9Jic6+Wjd88wCwYJKoZIhvcNAQEE
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowLTErMCkGA1UEAwwiVGVzdCBFbmQtZW50aXR5IHdpdGggTUQ1IHNp
+Z25hdHVyZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbW
+Qf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pk
+cQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHT
+AjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3
+ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jh
+s3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHV
+A6zaGAo17Y0CAwEAAaNbMFkwIwYDVR0RBBwwGoIYbWQ1c2lnbmF0dXJlLmV4YW1w
+bGUuY29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2Fs
+aG9zdDo4ODg4LzALBgkqhkiG9w0BAQQDggEBAGEUSKisSADWzD5jGCfvXOoUsYdh
+AuGaJqbQFQ+D3hJlmuPXcqOFV8oZNAaaMt0tcyH6Ak4KjpLcitRLQE2W6ChF2nQK
+qxz0OWYuFhtDg6c7JBXIT0c0/nM1NCoyDxZLK7oTpjAR5Ji6LIwuvj6uW0CLFZz2
+CqwlS+7RirFyzHr279ylFJxoGmApJjIG4Fds0BJoAdU8V4ZbDNE8LwcrYfI+h817
+y0IGGkrfpZ2eT94Ih+UfuYhKWyJ5pkxNtoG85It63MN+8i2flxSazuEk9sqRJznF
+OTYfaktXXlgBTlvr9m7P8kg+JQbwf915GMN3cgHuN00NiRqsvOQxJQl1BHs=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/md5signature.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/md5signature.pem.certspec
new file mode 100644
index 000000000..02742d910
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/md5signature.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Test End-entity with MD5 signature
+signature:md5WithRSAEncryption
+extension:subjectAlternativeName:md5signature.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch-expired.pem b/security/manager/ssl/tests/unit/bad_certs/mismatch-expired.pem
new file mode 100644
index 000000000..9924dfb7e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch-expired.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJTCCAg+gAwIBAgIUE8pDZuVKk0GpcycnYoniDg5yXqwwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxMzAxMDEwMDAwMDBaGA8yMDE0MDEw
+MTAwMDAwMFowKzEpMCcGA1UEAwwgTWlzbWF0Y2gtRXhwaXJlZCBUZXN0IEVuZC1l
+bnRpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAGjWjBYMCIGA1UdEQQbMBmCF2RvZXNudG1hdGNoLmV4YW1wbGUu
+Y29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9z
+dDo4ODg4LzALBgkqhkiG9w0BAQsDggEBACTILZlbbJ0JN8lnC7ckWE6+/l/y2WOl
+uF23jWbhElQrqJS/YHLqeu1we1LJYQAdN+w/Ro2F6bpxmGea2kZV8jLWRVL1e8ek
+b8+AwSMDmMLcWV6eS+3XLxCF9YPHNIIM3mrUAcI3Oc1Pmf9xWiNxrHukuAk8CJbp
+6Q/Xrdtt4sgpYRDEsciB1Vn14NEDP1SoPi86dcFNpNfuheG/Bjdosi5CAxKfLakr
+WWQbTmCR1m+1OyNsiGEsUisIOXyCTTehTuhcZp+EyR5SHy0cNg6tVStMU49k4XsC
+jG+UmcQRsNHgNqJK+k2KM7yvGjuonokDfKUrQ6EtgWSvkqcFasmCPbQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch-expired.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/mismatch-expired.pem.certspec
new file mode 100644
index 000000000..262f08d6b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch-expired.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Mismatch-Expired Test End-entity
+validity:20130101-20140101
+extension:subjectAlternativeName:doesntmatch.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch-notYetValid.pem b/security/manager/ssl/tests/unit/bad_certs/mismatch-notYetValid.pem
new file mode 100644
index 000000000..bfbb973c1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch-notYetValid.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDKzCCAhWgAwIBAgIUT/IgcHtYb6NXOgazofG+tsSh5RcwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAzMzAxMDEwMDAwMDBaGA8yMDM0MDEw
+MTAwMDAwMFowMTEvMC0GA1UEAwwmTWlzbWF0Y2gtTm90IFlldCBWYWxpZCBUZXN0
+IEVuZC1lbnRpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGo
+RI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9a
+dWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6t
+aRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8n
+FthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kX
+Dqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/py
+UcQx1QOs2hgKNe2NAgMBAAGjWjBYMCIGA1UdEQQbMBmCF2RvZXNudG1hdGNoLmV4
+YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xv
+Y2FsaG9zdDo4ODg4LzALBgkqhkiG9w0BAQsDggEBAE12bvoPuLY/rJGy1ijqXgTe
+1JkVgsL9YxL3yqUsNwvLwdtOA9OtvUprqNaq90niYJ2P58c9ZrloGy5YSjl0cNDv
+GbWiNJoxmY0jsR7Ql45t7uWOEArw81rMeqBjs0dNB99IoJ7xxSNWvmpOGprHw3An
+nVTSmQF4L5qQVAgf1ki2Y43I1ahu04BTAWgzaTppwfX8tAJhZ62HQ+44FetYHnIa
+FZMh/LLiuI0FadRLVaH6uxo7BcvrO8s5zDZ+9W08Fqv60Trl6k+y/N229g+txVhQ
+LULSLizQNoJeSDBVcbq0uYTGvvr/VhPdFDLbR6KOtYGy6VtJgnziQFlL5JS7EGM=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch-notYetValid.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/mismatch-notYetValid.pem.certspec
new file mode 100644
index 000000000..947eb7d67
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch-notYetValid.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Mismatch-Not Yet Valid Test End-entity
+validity:20330101-20340101
+extension:subjectAlternativeName:doesntmatch.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted-expired.pem b/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted-expired.pem
new file mode 100644
index 000000000..47c8d4c3a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted-expired.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDNTCCAh+gAwIBAgIUBRVeuOJA+GTXgxh+UUrNUeli1lowCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxMTAxMDEwMDAwMDBaGA8y
+MDEzMDEwMTAwMDAwMFowNTEzMDEGA1UEAwwqTWlzbWF0Y2gtVW50cnVzdGVkLUV4
+cGlyZWQgVGVzdCBFbmQtZW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGc
+BptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzC
+a2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8Xg
+uEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK
+9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGP
+mRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABo1owWDAiBgNVHREEGzAZghdkb2Vz
+bnRtYXRjaC5leGFtcGxlLmNvbTAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGG
+Fmh0dHA6Ly9sb2NhbGhvc3Q6ODg4OC8wCwYJKoZIhvcNAQELA4IBAQAP9DQC50r0
+B5xvOnkJxB+IFlr8dv2bLNg5Dm3ITmobaHvjEywXzP8RwYVwqgZsVG1Z6FyNBgey
+qJXDXHbrPI81G6286p+rQgEeu7DcoFoHL2umpAXSEVzLw/MyIqbsD9tXKe7fYKvu
+R7Vz/OhQsZMy+ShHGn0Ze6mRdFbdmUYzcrYuCyAKLfqsvpnQ9y7+bd0lgMSHxPG3
+kruIQs5MZ/VUraVtvdoLUxoUy3v7oaCyUJgCS6Wls3nlAECpDTEg986HOVaysKtH
+hRG82KctN5RK40H6EuUGa83Yxp0zF6OnqiOVtm7vHmkk4WNIP2i+gG+/zex78/P6
+EhZHLdk5fS/M
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted-expired.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted-expired.pem.certspec
new file mode 100644
index 000000000..adc8ebaf8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted-expired.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Other test CA
+subject:Mismatch-Untrusted-Expired Test End-entity
+validity:20110101-20130101
+extension:subjectAlternativeName:doesntmatch.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted.pem b/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted.pem
new file mode 100644
index 000000000..723ed4dae
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDLTCCAhegAwIBAgIUBUkHM4qYlHhlajaquYXsh/XJw+swCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowLTErMCkGA1UEAwwiTWlzbWF0Y2gtVW50cnVzdGVkIFRl
+c3QgRW5kLWVudGl0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqI
+UahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvi
+r1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/x
+fq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD
+7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnv
+uRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj
++nJRxDHVA6zaGAo17Y0CAwEAAaNaMFgwIgYDVR0RBBswGYIXZG9lc250bWF0Y2gu
+ZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8v
+bG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEAstqHR4upkLa4tJcDD4vH
+cUAJrMT+FzazHXIe4ukUiWG1HtyCjUiFI+NhS7YhCY2+rigO58UKgNkaG6BkrlJM
+I81gnyfljMUmukNDmOmsOtXHhP8MXdEa6ye266M/CflTI1oAnLir/6ZJm8AwcLVW
+vh4rhEjARMMPpmUC7vpf2aK4qTAcxuymei9Q7uy2tjJT4PExwa4aMBc195yXAyat
+oMnVQWZqcQE1Gq/AUzQpHsZAvZOPzEQVLk1gAnZrDLZCQucEbd0P2cJ929cK5Zz0
+8t13hDTRa4NpHeaqCTz1l8tVf70FyeQn/tpRQT3uw6aUTbVpELONOFsgt/n/7RBb
+Tg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted.pem.certspec
new file mode 100644
index 000000000..91c5f548b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch-untrusted.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Other test CA
+subject:Mismatch-Untrusted Test End-entity
+extension:subjectAlternativeName:doesntmatch.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch.pem b/security/manager/ssl/tests/unit/bad_certs/mismatch.pem
new file mode 100644
index 000000000..205fa23b9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPDCCAiagAwIBAgIUexDM8FvRSX/MKvVCro1JmGq023EwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowIzEhMB8GA1UEAwwYTWlzbWF0Y2ggVGVzdCBFbmQtZW50aXR5MIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08
+E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc
+1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAP
+DY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQ
+gAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqV
+YR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQID
+AQABo3kwdzBBBgNVHREEOjA4ghdkb2VzbnRtYXRjaC5leGFtcGxlLmNvbYIdKi5h
+bHNvZG9lc250bWF0Y2guZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsG
+AQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEA
+CGnfn+l13zgSEIzCmZL2JLUHCKH7OilQ0tE7QjGTXo12KXUML8uNhoxXgH/z7ZnG
+0N2ya+Y1pGOyAFsj37nAipH5xsM2mP1aAlPEjgrmoskyhiMszKxr8OD8TFHOfvkS
+BlRjnGVjWpwkc2sAbHneN/aitkWDoQ2nacipdQl0OuW4jEjNXa1GE60kCmlfI72b
+aP0yN0NPnIcx8Q4M++tfQ7imJbnonxIdQGJdjHHjIRE2CNFyt2Qeb66IyK/pnEDm
+oVjx5VZPLUr0g1Ubg6W65LbIuNzalpzPBP30CAEqLXNNZ6wqKTgEHB5UB8sQnFTS
+2AZeBlTZ42e5UpU/+h8Mog==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatch.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/mismatch.pem.certspec
new file mode 100644
index 000000000..b93599fc8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatch.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Mismatch Test End-entity
+extension:subjectAlternativeName:doesntmatch.example.com,*.alsodoesntmatch.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatchCN.pem b/security/manager/ssl/tests/unit/bad_certs/mismatchCN.pem
new file mode 100644
index 000000000..004ce48e6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatchCN.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaqgAwIBAgIUJzlO5E47g+NUJjL7EcrQMDmXq04wCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowIjEgMB4GA1UEAwwXZG9lc250bWF0Y2guZXhhbXBsZS5jb20wggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
+2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
+JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
+jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
+BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
+He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
+AAEwCwYJKoZIhvcNAQELA4IBAQBy/KCwjrh0emnzBnuw+yEZElSD23wKKhAjUISO
+27ndrI6Gmv/wKHdgUP2yBPZbTcUT7RrzamdkOrsVASL2vAFAI1r/wHp/PXEnuNY5
+mUWVZLH3kCzJjvZXvGbdQUJhNraNbvDgV+GI/AAo+67QnSmYM0bqhaMsgbGHILGl
+qZNOE6GZdWDFBSdNIdKz3AXeKiTXduR7rb03CiuGkG+RmByPEARiUdt2xdZMxx+Q
+nhOTnBEu3KsyvJ0Y79Z6T8s3qo2dUsjHF9Kn77CKNYQFTbyoDMsBnulZZuL3uL0A
+Fn7CB+VWzVooOhq+BvbeynWGDj3rHsMQUPyP8DMKuwJZwSxa
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/mismatchCN.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/mismatchCN.pem.certspec
new file mode 100644
index 000000000..86ef45b7c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/mismatchCN.pem.certspec
@@ -0,0 +1,2 @@
+issuer:Test CA
+subject:doesntmatch.example.com
diff --git a/security/manager/ssl/tests/unit/bad_certs/moz.build b/security/manager/ssl/tests/unit/bad_certs/moz.build
new file mode 100644
index 000000000..5402f3c21
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/moz.build
@@ -0,0 +1,68 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'badSubjectAltNames.pem',
+# 'beforeEpoch.pem',
+# 'beforeEpochINT.pem',
+# 'beforeEpochIssuer.pem',
+# 'ca-used-as-end-entity.pem',
+# 'default-ee.pem',
+# 'eeIssuedByNonCA.pem',
+# 'eeIssuedByV1Cert.pem',
+# 'emptyIssuerName.pem',
+# 'emptyNameCA.pem',
+# 'ev-test-intermediate.pem',
+# 'ev-test.pem',
+# 'evroot.pem',
+# 'expired-ee.pem',
+# 'expiredINT.pem',
+# 'expiredissuer.pem',
+# 'idn-certificate.pem',
+# 'inadequateKeySizeEE.pem',
+# 'inadequatekeyusage-ee.pem',
+# 'ipAddressAsDNSNameInSAN.pem',
+# 'md5signature-expired.pem',
+# 'md5signature.pem',
+# 'mismatchCN.pem',
+# 'mismatch-expired.pem',
+# 'mismatch-notYetValid.pem',
+# 'mismatch.pem',
+# 'mismatch-untrusted-expired.pem',
+# 'mismatch-untrusted.pem',
+# 'notYetValidINT.pem',
+# 'notYetValidIssuer.pem',
+# 'notYetValid.pem',
+# 'noValidNames.pem',
+# 'nsCertTypeCritical.pem',
+# 'nsCertTypeCriticalWithExtKeyUsage.pem',
+# 'nsCertTypeNotCritical.pem',
+# 'other-issuer-ee.pem',
+# 'other-test-ca.pem',
+# 'self-signed-EE-with-cA-true.pem',
+# 'selfsigned-inadequateEKU.pem',
+# 'selfsigned.pem',
+# 'test-ca.pem',
+# 'test-int.pem',
+# 'unknownissuer.pem',
+# 'untrusted-expired.pem',
+# 'untrustedissuer.pem',
+# 'v1Cert.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
+#
+#test_keys = (
+# 'default-ee.key',
+# 'evroot.key',
+# 'inadequateKeySizeEE.key',
+# 'other-test-ca.key',
+#)
+#
+#for test_key in test_keys:
+# GeneratedTestKey(test_key)
diff --git a/security/manager/ssl/tests/unit/bad_certs/noValidNames.pem b/security/manager/ssl/tests/unit/bad_certs/noValidNames.pem
new file mode 100644
index 000000000..36d258cb0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/noValidNames.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAemgAwIBAgIUD8+FcBmecy2K1vllEQ2SgGucJCQwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowKTEnMCUGA1UEAwweRW5kLWVudGl0eSB3aXRoIG5vIHZhbGlkIG5h
+bWVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62
+iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHql
+WqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosq
+Qe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+
+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8i
+b2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoY
+CjXtjQIDAQABozYwNDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6
+Ly9sb2NhbGhvc3Q6ODg4OC8wCwYJKoZIhvcNAQELA4IBAQBiwTfHRmir5VnSNxOs
+S806Ao1xXqaz7ff/qi32Nnio855qHulmKjsRfmEv09N7/PNFkAa6yILe0/8YdroC
+aOd1iOdawsNMoeud7mD0FjuOYcjSnCx0WTeW5LZ/yXkgKwA8+shZzhr9TYiXQtnt
+TIgQma15CyjpFp9ztHj6MtInVFhjDxe9DzJsgLv8EAxbLacPN6ZFB6DevvI+NL6M
+wsy27OMdFvW7M4AWlWIyCFJg1moxaw8Ht8vUooe3EWbRknuM5IasgwZDt5YUeXkO
+0nQF4IKtLoASla3UOL7exkMLJA7kE4zTlOKADXi56lNZd/2ck/+wd9hrwo8aXLsO
+T34M
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/noValidNames.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/noValidNames.pem.certspec
new file mode 100644
index 000000000..87088e87e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/noValidNames.pem.certspec
@@ -0,0 +1,3 @@
+issuer:Test CA
+subject:End-entity with no valid names
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/notYetValid.pem b/security/manager/ssl/tests/unit/bad_certs/notYetValid.pem
new file mode 100644
index 000000000..a380ffc9a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/notYetValid.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDIjCCAgygAwIBAgIUM4uC0JcSpF7UST7x6F6ZPc9KOrswCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAzMTAxMDEwMDAwMDBaGA8yMDMyMDEw
+MTAwMDAwMFowKDEmMCQGA1UEAwwdTm90IFlldCBWYWxpZCBUZXN0IEVuZC1lbnRp
+dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braI
+BjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVa
+p0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB
+7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4C
+kC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJv
+aeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgK
+Ne2NAgMBAAGjWjBYMCIGA1UdEQQbMBmCF25vdHlldHZhbGlkLmV4YW1wbGUuY29t
+MDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4
+ODg4LzALBgkqhkiG9w0BAQsDggEBALSZFFaWXBJQZrEnbKcmqL4FKsB4/ZNK7fXd
+KI0LpaFtOwjXV6HxmuoBQ3PH87XXF5wpbsibZd7Ua4ZnKV0w7aW7BJSphIfkFVzK
+dJFAiMPKVTCGOQzRZeXPjSrGzExyVHq2IAvcWIogN5vXxR3icS6fb9WbJEtdmEdZ
+LtS9FfFxTBQBVnJKldMqbotpKS7gUm4KHUF57Q6f9Az41PlUaSqpXbnqsQ5BTCzv
+d3PjsYAwkdlN8TSUC6iDfQnEP6zo9L49jsUxAOoOEaIVP5SJEASYq4uvcl8Z7IoY
+PXpypjIP56Q5FKA1hrU0KwjZYcR4KRIhvTHEybgxK/XUA1znaf0=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/notYetValid.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/notYetValid.pem.certspec
new file mode 100644
index 000000000..5b60c29eb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/notYetValid.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Not Yet Valid Test End-entity
+validity:20310101-20320101
+extension:subjectAlternativeName:notyetvalid.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/notYetValidINT.pem b/security/manager/ssl/tests/unit/bad_certs/notYetValidINT.pem
new file mode 100644
index 000000000..aa4a031d3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/notYetValidINT.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAdGgAwIBAgIULzhHWvpIqD6LDAt8W+Os9YEJmkwwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAzMTAxMDEwMDAwMDBaGA8yMDMzMDEw
+MTAwMDAwMFowKjEoMCYGA1UEAwwfTm90IFlldCBWYWxpZCBUZXN0IEludGVybWVk
+aWF0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1u
+togGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6
+pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqL
+KkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3Zlqq
+fgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3sv
+Im9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6za
+GAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZI
+hvcNAQELA4IBAQCkGkkzHDXywFs2/YUNbwEttgV//Rj74yqYZJeiAfUapIIMyocs
+hgKqSWGhtSyDzBzZhoNE8hzFtJ7c7OxZynpDpS/fhjLqX/dCiA2BlPkeliewdiaT
+lpH45OjdaU5u0s/p9qn5CZMe5OFKR7tIj+fDrz79sO3Z749WXdyyCd97wDc37BMo
+uTHIs07D5cJmG5vLYQRPE+RU0YZgk4QW4gmKp2tlcpkardFv1nTuc9fYokU98+87
+woE1nAZRS6JPnYekwxz2ToOCXyh/CKhhrrnxvGCXvVcaoDg5okI2Ri75nqXL9770
+dTyzwv3wPEOcmcqX2vwN5RaNzUCMOY4x/qzU
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/notYetValidINT.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/notYetValidINT.pem.certspec
new file mode 100644
index 000000000..8a00f2ee2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/notYetValidINT.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Not Yet Valid Test Intermediate
+validity:20310101-20330101
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/bad_certs/notYetValidIssuer.pem b/security/manager/ssl/tests/unit/bad_certs/notYetValidIssuer.pem
new file mode 100644
index 000000000..10e11c82c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/notYetValidIssuer.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjagAwIBAgIUd2Xdl3VR8l0IU2OPSgy6zPCjvaQwCwYJKoZIhvcNAQEL
+MCoxKDAmBgNVBAMMH05vdCBZZXQgVmFsaWQgVGVzdCBJbnRlcm1lZGlhdGUwIhgP
+MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowNDEyMDAGA1UEAwwpVGVz
+dCBFbmQtZW50aXR5IHdpdGggbm90IHlldCB2YWxpZCBpc3N1ZXIwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq0
+7PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D
+/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuw
+JJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyX
+rZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWd
+q5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjYDBe
+MCgGA1UdEQQhMB+CHW5vdHlldHZhbGlkaXNzdWVyLmV4YW1wbGUuY29tMDIGCCsG
+AQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzAL
+BgkqhkiG9w0BAQsDggEBAEI5yQNpc3afAa4iN9uVBBDv9gT3X2FbhrWKCNYbLsRD
+dtntFIuZMHJvH0IuKqgUoDnFMJciOkhY8GrJUi6bZIOd15YL/jsodJHxYO9g0vT0
+0E33/Ka+0DEy4g/skJTy7xQsF0OTw042Aoe23RFxwbAmzqQn0BDRzJ6Qhx4WLQ2f
+QVhmDrvwF+VRshrp6bJKjcTZRmgIX3nVYAR0THuJu+zcB8de7G3lOH7YCl0rpboI
+fFkQxnTSt/MtU3FEJaajmz3PvzLkCI4FHFv8SouQ3ZIp/XRHk6luW0QWO3z6cy5l
+3V9BkhP0jkPpr9wfCZcmqu8EkCWZCfiu0Rf+k2uR2wo=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/notYetValidIssuer.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/notYetValidIssuer.pem.certspec
new file mode 100644
index 000000000..d8420898e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/notYetValidIssuer.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Not Yet Valid Test Intermediate
+subject:Test End-entity with not yet valid issuer
+extension:subjectAlternativeName:notyetvalidissuer.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCritical.pem b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCritical.pem
new file mode 100644
index 000000000..0602dbb8f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCritical.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC+zCCAeWgAwIBAgIUQaNz+iusE21wkn6JJ/qLaB6Q8gEwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowHjEcMBoGA1UEAwwTbnNDZXJ0VHlwZSBDcml0aWNhbDCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
+SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYL
+K7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwc
+bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
+JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaM9
+MDswIwYDVR0RBBwwGoIJbG9jYWxob3N0gg0qLmV4YW1wbGUuY29tMBQGCWCGSAGG
++EIBAQEB/wQEAwIGQDALBgkqhkiG9w0BAQsDggEBAKWjJlobJfQhQxSNmvhokt1f
+rSWbHFyePtawqHSBKIOG9RrNB9E+nbDsI/gVvgVwi1GVu7cmg5SJDAuK19dpWXTh
+Pf4FPTm+FrLXwfPUOay5S3aGSwg29/PjnVayuBrJbMeYvtMJd7NGtadyv5wg3K3P
+SSFqYjUKOeWewt2NrX07LII68uctBja3BVpAPVvcoYsnR30ozuuiZTy6rBu0n4g0
+KU2stuuOnVLf7A7C2clj/ls0uX0hbSAaFH2RNQPsu+TL2ziSEEV9DYUm4pPMnpuO
+dhSDgTDkCTMqzS84FFTemzbkOUxBechMogtPkEhr157kbBXYzjytYgGLL7FGGRc=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCritical.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCritical.pem.certspec
new file mode 100644
index 000000000..b236bdea4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCritical.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:nsCertType Critical
+extension:subjectAlternativeName:localhost,*.example.com
+extension:nsCertType[critical]:sslServer
diff --git a/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCriticalWithExtKeyUsage.pem b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCriticalWithExtKeyUsage.pem
new file mode 100644
index 000000000..24d6ba742
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCriticalWithExtKeyUsage.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDLzCCAhmgAwIBAgIUL0RNPgFGtsQZxanRCa2IGPqVWZIwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowLzEtMCsGA1UEAwwkbnNDZXJ0VHlwZSBDcml0aWNhbCBXaXRoIGV4
+dEtleVVzYWdlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABo2AwXjAjBgNVHREEHDAagglsb2NhbGhvc3SCDSouZXhh
+bXBsZS5jb20wFAYJYIZIAYb4QgEBAQH/BAQDAgZAMAwGA1UdEwQFMAMBAQAwEwYD
+VR0lBAwwCgYIKwYBBQUHAwEwCwYJKoZIhvcNAQELA4IBAQAO+rOEK3vhTmoLNg5w
+upxSODlCFghBLZ1qui7RWJME62JG/1sxZw4rHa0Pl2NP1U/Wy0ErAT/QQLyIahBL
+mjggdD3Vh9wfx4Qf4FwHGzJEopfsx6YQlHcXR1v5qb7lLeuywhA6m7agn9DWBGlg
+lLFNqtHmofQFaileQOA50Uu9qOAdbea5+rjZn9rBBvUUVeSc9hNWjDRCMk/5PSm4
+6ONpFjal4npPA8V/U7LleJR+VNbiCWNHaQD/9H+xBoay81m8GL0CdM9udBjbyf9W
+NlYtu87XanZn2//LghGGUW4HQn1YXWD6UeZngo91UdQeIOs+dCiTI8CldgpGafld
+8UdC
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCriticalWithExtKeyUsage.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCriticalWithExtKeyUsage.pem.certspec
new file mode 100644
index 000000000..0ae63e20f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeCriticalWithExtKeyUsage.pem.certspec
@@ -0,0 +1,6 @@
+issuer:Test CA
+subject:nsCertType Critical With extKeyUsage
+extension:subjectAlternativeName:localhost,*.example.com
+extension:nsCertType[critical]:sslServer
+extension:basicConstraints:,
+extension:extKeyUsage:serverAuth
diff --git a/security/manager/ssl/tests/unit/bad_certs/nsCertTypeNotCritical.pem b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeNotCritical.pem
new file mode 100644
index 000000000..b894c0bce
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeNotCritical.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC/DCCAeagAwIBAgIUSeaDecTuqo807NV7Z4OGuTUEoKowCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowIjEgMB4GA1UEAwwXbnNDZXJ0VHlwZSBOb3QgQ3JpdGljYWwwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
+2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
+JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
+jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
+BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
+He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
+AAGjOjA4MCMGA1UdEQQcMBqCCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbTARBglg
+hkgBhvhCAQEEBAMCBkAwCwYJKoZIhvcNAQELA4IBAQBUkcVO1xXJv8/BR5tUyQDt
+Y6gQMH9hfg2MZwR7mKj/ZdTEUMUqpOo4zfxRj8j3WNAF01g88D/oQw3IcDay9kpE
+EZDSLLQpVYW6l9xEWuCl+p9jNbFDmNxyPe2KOD+Pmp0ggkyeKyfC2l1cZS9kuQjW
+rIYgGdDVcXvBH/cfi8Dxl4IjWa/Fmkpw/W4uvcKcpLdtwZkGAa2CH1ymmeE3gtE8
++uYJuWWP9RE1cwXtwoGTPoU2fxBP8V2gRgPrlHQlhlJzyWthJ30Cv+RBNU6IkzNT
+ZO10f39iPQScLbrcaDULX44vhUGhXlaXsOBWZnyX7exBWdUxNNpIjReO1nrZxufi
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/nsCertTypeNotCritical.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeNotCritical.pem.certspec
new file mode 100644
index 000000000..a44a1feee
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/nsCertTypeNotCritical.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:nsCertType Not Critical
+extension:subjectAlternativeName:localhost,*.example.com
+extension:nsCertType:sslServer
diff --git a/security/manager/ssl/tests/unit/bad_certs/other-issuer-ee.pem b/security/manager/ssl/tests/unit/bad_certs/other-issuer-ee.pem
new file mode 100644
index 000000000..13ba23a19
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/other-issuer-ee.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmWgAwIBAgIUNVbKGlj3T9hCc0QZzD1Zs4cFzeUwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowJzElMCMGA1UEAwwcV3JvbmcgQ0EgUGluIFRlc3QgRW5k
+LUVudGl0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93
+CCpnkfG4dsN/XOU4sGxKzSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8
+EgJExYSkxEgzBeUTjAEGzwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbL
+PMcG680wcOyYzOQKpZHXKVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmV
+hmYlR5ftQmkIiAgRQiBpmIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+
+8Bbxh83VToMrNbiTD3S6kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8d
+HhkdcSFo07sCAwEAAaOBrTCBqjB0BgNVHREEbTBrgigqLmluY2x1ZGUtc3ViZG9t
+YWlucy5waW5uaW5nLmV4YW1wbGUuY29tgigqLmV4Y2x1ZGUtc3ViZG9tYWlucy5w
+aW5uaW5nLmV4YW1wbGUuY29tghUqLnBpbm5pbmcuZXhhbXBsZS5jb20wMgYIKwYB
+BQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsG
+CSqGSIb3DQEBCwOCAQEArJqM6iooFNCAk11WMdPCxa4iGkG4V5zYuFjdd2K3LTLM
+ai5SZS875tXNol+YZgUh6cdTbVARdsB4saYGH1v5pAmK+VJniYQHWYsSLofgBfFw
+yAk1Ymj5pz8y6+ExYzWPBV5ihevtyCRPGG8xgZqRbERTdB2uBZGmQ441LLnZZZFX
+BByEFQ4M7qYmOTZaIxncSGZbwVncBYkLbYmOIPdcahVtnK1mIm1q7ET0KeUEPTLB
+5UEdNa7bd5ULWeCIVZxRWdawzktWdF7CfBVO2KeWiEE6wkL1Y3N29mUOynWKRs7w
+wo5ETwxEw/6UqOaGCmbCTN5Xa+N+ZE5/4g0gEEcFUg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/other-issuer-ee.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/other-issuer-ee.pem.certspec
new file mode 100644
index 000000000..a905a66ac
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/other-issuer-ee.pem.certspec
@@ -0,0 +1,6 @@
+issuer:Other test CA
+subject:Wrong CA Pin Test End-Entity
+issuerKey:alternate
+subjectKey:alternate
+extension:subjectAlternativeName:*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com,*.pinning.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/other-test-ca.key b/security/manager/ssl/tests/unit/bad_certs/other-test-ca.key
new file mode 100644
index 000000000..6db74b5c5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/other-test-ca.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBdcZSZgmfdwgq
+Z5HxuHbDf1zlOLBsSs0iscvUb6Za2irdQcjCSYrEo7PB9hSH9BtpiUG9gKUcPBIC
+RMWEpMRIMwXlE4wBBs8IvpqGJ2C65qLo828jxdmDE7nfrzeDRdrOUdTW3NKmyzzH
+BuvNMHDsmMzkCqWR1ylaf3HFvmZpHSst/shJRFkLxaPqSf2TsddTQF8Xc3aZlYZm
+JUeX7UJpCIgIEUIgaZiKQ/7kjOaHgd0itqac0oN1Ex+TKxKM4ob6fSUcBirSfvAW
+8YfN1U6DKzW4kw90upCqi8dhZyQqsf1tYhQNGMTAuMaPw3SEVzJK196G5lUvHR4Z
+HXEhaNO7AgMBAAECggEAfj9tfLg572auXX3ZL/VBC7NB3BRyjTkDRXDho3B5DzDw
+aBNV//QeKtTpqdn86/vRJ736uMAK/7Hzzqcyfq1HqhYh8qwe4UygLwSzsnhgF5gL
+GBpEnQOwPmnRErg1ceVUNPASBWV10oMu1nMdznmeN8g/bVHFWrcetYAVrwXhrxXH
+R2A+9/J9A6b/BJ2Wu/hUweTlDvWwWND7CBgOCsf3vo8v8Wc9l/yeVduoOAd7v4p8
+/ylihXeFJpzZ1brStXRp5K/NM8TKLS9pnxHnyPvc1ITwjY77ijy4qXLrJL7Zcu+q
+5LtxIJPkj+lKRutimodQeMQCGposk8mnA5Dp0KVEAQKBgQDmP8clprp2klp/+MtZ
+xPVt1+yD/oW/H1PhHKyagSWLz8CugZB3sPLRR3qvho3mqOy+r3uyKxlvKprYLTKG
+8NDMKd5xnl8r6OUJtyhNWWPt02L5J4h6TEqJeZ00DVGzAax2AasnF5Ak/KrdOL9l
+Iq9j6xZGHsAqfyewb+Cd3afAoQKBgQDXGLH+n4+Z8A6DKuH73G/iqyfzTgScSYAQ
++g63CEhSGCNGCDtclsPu5VksAUpBDGuTCxZcE7XCaqMurG58klqFUcJRNPL0pyxk
+IfGacxSKDt+rpdOmiIs1y6GMAP047lqvC1RXMdcgdhu8ze50SlLKQV6Y5N4Bzf52
+TBlns+jK2wKBgAHlrKJmyUqI0i4TwrkuokcRbGV6B2gXvf0w20s6nTCVuaS2dJZH
+4vhOenhPx4OLCMhZcc96A2+jDjuRw8TQ3yePgMG26FnYRWrbE33vqp8fCsW6yakY
+T9TqJ51yLqYm8WDXiq17yDhFzLKd8RXIP2G3YiuZvUOcYJtXkKY8WVGBAoGBAIDM
+RdENJITuDRKX/Ae/gLO+/0Yeon4fOPNxeJw69mtKDt0hksIneR208cd64ka/NC8x
+hWsPVlgbWKlbETHAxTltsqjDxvOeouM2vCBa5qKgs2hp/KmMu6czzwExmm+bsmt8
+oj0wF/xVHNjaiv3Rf2+i4w00hoeYHNYjTVcekLffAoGAb3fAwfKuesFpVhzKSZxS
+vfvgTN3M29wSrsWoVpHoWUt+4pkI8w57lqpiVLgO1K7sm5k3gr38ebadjVjGiHD6
+S+G8DDUnKIxcgrtK668V7f8RBAP8eOas5qgoJ79C8M+nUeUHZRxWONuTk90j3R9r
+KVFR3kS3f+Vaew3yceGaZcA=
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/other-test-ca.key.keyspec b/security/manager/ssl/tests/unit/bad_certs/other-test-ca.key.keyspec
new file mode 100644
index 000000000..cbd5f309c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/other-test-ca.key.keyspec
@@ -0,0 +1 @@
+alternate
diff --git a/security/manager/ssl/tests/unit/bad_certs/other-test-ca.pem b/security/manager/ssl/tests/unit/bad_certs/other-test-ca.pem
new file mode 100644
index 000000000..09bd4bb04
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/other-test-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAcWgAwIBAgIUexJUIJpq50jgqOwQluhVrAzTF74wCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNTAxMDEwMDAwMDBaGA8y
+MDI1MDEwMTAwMDAwMFowGDEWMBQGA1UEAwwNT3RoZXIgdGVzdCBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
+zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
+zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
+KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
+mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
+kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMd
+MBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQCL
+jKgNGmCVYhntJo024WL8bF6hekERMYQbu/CK9moz6wlOpRMOQX1x7U/ianPW9Whi
+yoMAgAgNhLr2+t4ewqU2xRxMY0DvMSOuF9l08mptCW5sd/ocrRZuv/RcBmLcRnJm
+Y+HuaVOvf1ac32pNN5HYagGQbvvpAaHB5/DyYcywqUM7SttK1QF+AOsGePZdYUK2
+Od5wJwB7yE1Fpgf6O4vZaE0JkTVh8GQipwoPms2GYk2E1sJXu9eUrLBfioVVN0TF
+QF4xJxSwyxY8ys5E4+ftIVixVdetrcotUdYR64x9Hd5OPr5Q7VaAvd85ZvuB7xeK
+eHxNGBjaJMf1tkamLr3p
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/other-test-ca.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/other-test-ca.pem.certspec
new file mode 100644
index 000000000..3bc975aa2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/other-test-ca.pem.certspec
@@ -0,0 +1,7 @@
+issuer:Other test CA
+subject:Other test CA
+issuerKey:alternate
+subjectKey:alternate
+validity:20150101-20250101
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/bad_certs/self-signed-EE-with-cA-true.pem b/security/manager/ssl/tests/unit/bad_certs/self-signed-EE-with-cA-true.pem
new file mode 100644
index 000000000..badc58376
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/self-signed-EE-with-cA-true.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl+gAwIBAgIUOZxBsWqmNkNX1bk4vwjN7oalyxcwCwYJKoZIhvcNAQEL
+MDMxMTAvBgNVBAMMKFRlc3QgU2VsZi1zaWduZWQgRW5kLWVudGl0eSB3aXRoIENB
+IHRydWUwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowMzExMC8G
+A1UEAwwoVGVzdCBTZWxmLXNpZ25lZCBFbmQtZW50aXR5IHdpdGggQ0EgdHJ1ZTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAAaOBgDB+MAwGA1UdEwQFMAMBAf8wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUF
+BzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMDoGA1UdEQQzMDGCL3NlbGYtc2ln
+bmVkLWVuZC1lbnRpdHktd2l0aC1jQS10cnVlLmV4YW1wbGUuY29tMAsGCSqGSIb3
+DQEBCwOCAQEAOOiI4FYCOj5N75+ix87qQQjtyG//CTUi8SMRAIG9sQId7fRtXAcl
+qEtWKxdcNy4RYVoEQTNPrY6gr9amiPEpZ9IobtX1WW8gJiVj3EFLfXBKTE3B6Kxp
+Qim7bJvrqoumLgXtH7eljHdfN86I6Xnyk7L4tl30UhlOSd24jiQ8T5FxF7lcmEnT
+w+AthUUhOyKyDRXvV3jUpM3SKv6mz0rzm19A/qBOYM6Q+bAS5n47d/TPbmCff8T/
+zKU/Su7WYXsw7gU208DhWrqLjpUzPuGSRRTZgHCG35KpOlNcN81iZsvEYIyL+b68
+G2rlSZK2C3LaGi/0t7s3O8gUep20KSF7WA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/self-signed-EE-with-cA-true.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/self-signed-EE-with-cA-true.pem.certspec
new file mode 100644
index 000000000..0ca92d7fd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/self-signed-EE-with-cA-true.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test Self-signed End-entity with CA true
+subject:Test Self-signed End-entity with CA true
+extension:basicConstraints:cA,
+extension:authorityInformationAccess:http://localhost:8888/
+extension:subjectAlternativeName:self-signed-end-entity-with-cA-true.example.com
diff --git a/security/manager/ssl/tests/unit/bad_certs/selfsigned-inadequateEKU.pem b/security/manager/ssl/tests/unit/bad_certs/selfsigned-inadequateEKU.pem
new file mode 100644
index 000000000..87b0ca2e7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/selfsigned-inadequateEKU.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDgzCCAm2gAwIBAgIUV9yIaHMDuAdDCVBEzuEE5tSGIncwCwYJKoZIhvcNAQEL
+MDUxMzAxBgNVBAMMKlNlbGYtc2lnbmVkIEluYWRlcXVhdGUgRUtVIFRlc3QgRW5k
+LWVudGl0eTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjA1MTMw
+MQYDVQQDDCpTZWxmLXNpZ25lZCBJbmFkZXF1YXRlIEVLVSBUZXN0IEVuZC1lbnRp
+dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braI
+BjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVa
+p0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB
+7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4C
+kC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJv
+aeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgK
+Ne2NAgMBAAGjgYowgYcwCwYDVR0PBAQDAgQwMBMGA1UdJQQMMAoGCCsGAQUFBwMB
+MC8GA1UdEQQoMCaCJHNlbGZzaWduZWQtaW5hZGVxdWF0ZUVLVS5leGFtcGxlLmNv
+bTAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9sb2NhbGhvc3Q6
+ODg4OC8wCwYJKoZIhvcNAQELA4IBAQAhtt1BOrCjch5fzJ+OIvqSF2qERDB7CJDA
+avhypMbCVCEabM1JBD8vtA5U7izjWpAJVlOwFBUPtGpeCtXkCZEyy6/JPOdc5hhJ
+1h0+c9CeKkmjwyydqqz3v4quXAI0WX7ChuO5WfsVY1swFcp6TYtGYBsjMVpVQaTw
+CGNFZ73EEksRWP0NH/SKABo+6dlvOghivAa3Wx1HEOVTFUo8u6odwZ596Xl/IhY4
+I0G/GuGCwMhBE/5GGpSI8qH8DxRXT7nrvdHZmuiRB2SJYeuF4Cs08KHO+ymiST/d
+OLnAKR1WWgslQbxZu3zdBDqKuKf2vOKS9xo6sQXP3TsLsSPxY1v2
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/selfsigned-inadequateEKU.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/selfsigned-inadequateEKU.pem.certspec
new file mode 100644
index 000000000..477b90ce1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/selfsigned-inadequateEKU.pem.certspec
@@ -0,0 +1,6 @@
+issuer:Self-signed Inadequate EKU Test End-entity
+subject:Self-signed Inadequate EKU Test End-entity
+extension:keyUsage:keyEncipherment,dataEncipherment
+extension:extKeyUsage:serverAuth
+extension:subjectAlternativeName:selfsigned-inadequateEKU.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/selfsigned.pem b/security/manager/ssl/tests/unit/bad_certs/selfsigned.pem
new file mode 100644
index 000000000..436f9ef8e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/selfsigned.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDMzCCAh2gAwIBAgIUFdYBQ3rk5hXCs0Bz6ERmayqrMTYwCwYJKoZIhvcNAQEL
+MCYxJDAiBgNVBAMMG1NlbGYtc2lnbmVkIFRlc3QgRW5kLWVudGl0eTAiGA8yMDE1
+MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAmMSQwIgYDVQQDDBtTZWxmLXNp
+Z25lZCBUZXN0IEVuZC1lbnRpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwG
+m24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJr
+bA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4
+SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3
+/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+Z
+FzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjWTBXMCEGA1UdEQQaMBiCFnNlbGZz
+aWduZWQuZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZo
+dHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEAiPY8Ka4thJkS
+6HzgnIpJyd09rmAls/LwAPRwhk8s652FEEGpZzkreDjOJ9LGYx01JWGQPDxOgddt
+ynYtbZVzwnSuJnISglU/mAsmgG47hSeBamOm9zg2KAC1+64nVgpkmYMEDGQC4h79
+cADh5g5ay0E47x/9u7F02z4ovXyJCDC/bOTFKv4WCkHEaIKhnbrv4EGT+lkfCFol
+obLR6h4mwclIDycIR9D2hg4ZSrnace1JzF0OALMVshwtclmJMS4yH+yACSeovT6t
+fN1CTvLAY8nYtyuxWc3D/gv0T5MWVvkSSfbrvt+nCUvrEsLFnDgKqMzh7S/iph3M
+UyeHQjtRIQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/selfsigned.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/selfsigned.pem.certspec
new file mode 100644
index 000000000..99a814be1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/selfsigned.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Self-signed Test End-entity
+subject:Self-signed Test End-entity
+extension:subjectAlternativeName:selfsigned.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/test-ca.pem b/security/manager/ssl/tests/unit/bad_certs/test-ca.pem
new file mode 100644
index 000000000..1d50176e4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/test-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbmgAwIBAgIUH9DaznYx1NE1Cu9I8cBqxV9VgF4wCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowEjEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUw
+AwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQA1o3GayNFRlVTrsoj2
+Ag06YatbGe94M/FT0MXngjlmrMkGZqHaDlrii7Jz+JP16CBjaIZ0ZP7I56Nn/l8y
+/kfe++zvr1uwRaKjtRGBiFpCjx10rI508wzSnOox3+bOtv9qjYaY7UjkBV3F40IS
+P8qKMtNspsR4tjS/D1jbculhngkPqhskefZFQQvcgG54L5j921GFKNeeX6i9QAzV
+jjM6i/iQYpAWCuh5+CetwUnfFuZCM80npp/qHMESkT3PyPpwqT9A5K+xQdVfpXq5
+SmVy5+QGWALuSV1sfIRXRwOh+2jCWwWPbyi9TlHrvlO5mL38qikdYBDPat3ve4cq
+5viq
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/test-ca.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/test-ca.pem.certspec
new file mode 100644
index 000000000..5d2435d7b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/test-ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Test CA
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/bad_certs/test-int.pem b/security/manager/ssl/tests/unit/bad_certs/test-int.pem
new file mode 100644
index 000000000..df9ad3ddb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/test-int.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2TCCAcOgAwIBAgIUBVio/iQ21GCi2iUven8oJ/gae74wCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTAxMDEwMDAwMDBaGA8yMDI1MDEw
+MTAwMDAwMFowHDEaMBgGA1UEAwwRVGVzdCBJbnRlcm1lZGlhdGUwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq0
+7PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D
+/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuw
+JJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyX
+rZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWd
+q5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAb
+MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAry6Z
+DoUhexYUJTzWwN1ZIwWeXW/QxJR5u4DvK6pBPInDdyfv20EuxXKODYWXXPGbOY8X
+5SEsUtS+1WUlMAXenmejPvDcjeEGLS8tfJQbgHtPrDhQR43fnYGZrA2pWVmxQ+TJ
+Lrg18uGIuMcfAr3RwMzeK+uj81bybeYZN5haISWa6bF2a81vMx/WDgyFSYYBOYph
+nCPWVSqPTK/6NwbyWZORs474Flx45uzo7g9mMCmbwz9IzdJYpVrViVAFTU1gSbNQ
+ED3LzwGkS7eO8Lqzk9a94uIGqhxtGDvxFe+6Be/Il3M/5d2WC2Jmqzv8cU/u4GLb
+dKrXnD3epofIjHnOUA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/test-int.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/test-int.pem.certspec
new file mode 100644
index 000000000..33b42c2f4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/test-int.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Test Intermediate
+validity:20150101-20250101
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/bad_certs/unknownissuer.pem b/security/manager/ssl/tests/unit/bad_certs/unknownissuer.pem
new file mode 100644
index 000000000..d9ba29653
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/unknownissuer.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDpTCCAo+gAwIBAgIUHccbzbbSEhGlmiWbLlfHcRQFD7MwCwYJKoZIhvcNAQEL
+MCYxJDAiBgNVBAMMG1Rlc3QgSW50ZXJtZWRpYXRlIHRvIGRlbGV0ZTAiGA8yMDE1
+MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAuMSwwKgYDVQQDDCNUZXN0IEVu
+ZC1lbnRpdHkgZnJvbSB1bmtub3duIGlzc3VlcjCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBwjCBvzCBiAYDVR0R
+BIGAMH6CGXVua25vd25pc3N1ZXIuZXhhbXBsZS5jb22CNHVua25vd25pc3N1ZXIu
+aW5jbHVkZS1zdWJkb21haW5zLnBpbm5pbmcuZXhhbXBsZS5jb22CK3Vua25vd25p
+c3N1ZXIudGVzdC1tb2RlLnBpbm5pbmcuZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEE
+JjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3
+DQEBCwOCAQEAjvk1a9yDZSYDNilWlvRcUk6stPfmjG7p0Owu0a+Lh8JIxOZXflZ1
+/hpVp0L5ds6mc74Q5VBJgqpkrpYBIVDPa3LJzW4HX8y7FtDo71Ca/ob+Xyc4hFdg
+3G2DqLePZXqkV+h6bsg/Rqv2FUt/GbUmv4sIkTwL5KgMEjLJGxwRTyrQZJlTMC5N
+uSxtWiCv+wLnP9NbkMgBHE1NnBQjF5nR/mJC7HUGykGYe+oJHuozq+/VCn3bXFUm
+kq9YXS0R84LcQH7gHtOlp5xwxiYXPH3C2cxobaJNdo5qsyOZYc5Diq/ukCN5rg0N
+5IOg9SPThtEzlCjTFRVHKE7ncgo7JxJ3gw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/unknownissuer.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/unknownissuer.pem.certspec
new file mode 100644
index 000000000..a735c730c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/unknownissuer.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test Intermediate to delete
+subject:Test End-entity from unknown issuer
+extension:subjectAlternativeName:unknownissuer.example.com,unknownissuer.include-subdomains.pinning.example.com,unknownissuer.test-mode.pinning.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/untrusted-expired.pem b/security/manager/ssl/tests/unit/bad_certs/untrusted-expired.pem
new file mode 100644
index 000000000..497b3472c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/untrusted-expired.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDMjCCAhygAwIBAgIUEb4CKRVPjI1eurD3IgLllUvomHgwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxMTAxMDEwMDAwMDBaGA8y
+MDEzMDEwMTAwMDAwMFowLDEqMCgGA1UEAwwhVW50cnVzdGVkLUV4cGlyZWQgVGVz
+dCBFbmQtZW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR
+qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv
+WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+
+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv
+JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5
+Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6
+clHEMdUDrNoYCjXtjQIDAQABo2AwXjAoBgNVHREEITAfgh11bnRydXN0ZWQtZXhw
+aXJlZC5leGFtcGxlLmNvbTAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0
+dHA6Ly9sb2NhbGhvc3Q6ODg4OC8wCwYJKoZIhvcNAQELA4IBAQB+nHMbzEEVQFPF
+ahU0cR3xT8hyv0R0rNFTFQzGmAJpLz+xJN+GsOLuqGHqZ7Yc8lSOEQq4m/EDNncL
+SWnNbQHZPb4BAgz6n84gKazPfvkQmzx2QFqJs8s/Nfj8kxygUbCF5h+R+KBQbQd3
+qjAEeJK7pUoJjBB236JwBlM0Rqbv7QgTibm5VnNcfkZcwlBpwfCXdc6jtG9hkyhD
+h/8H0mZ+gvMpgnXx3TascLWJuPrYpDSgayRClfvs+FQtY8Lv5qkCR2TLLU779O8f
+TNTZLWogZ/tlOy268M5iFaOS71g0dQM9sU++XpUjtQlf6T1a2HtyZ8CmiG+Ffsym
+mAJNGYT8
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/untrusted-expired.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/untrusted-expired.pem.certspec
new file mode 100644
index 000000000..3efd1ce67
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/untrusted-expired.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Other test CA
+subject:Untrusted-Expired Test End-entity
+validity:20110101-20130101
+extension:subjectAlternativeName:untrusted-expired.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/untrustedissuer.pem b/security/manager/ssl/tests/unit/bad_certs/untrustedissuer.pem
new file mode 100644
index 000000000..842e7e7bd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/untrustedissuer.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDNDCCAh6gAwIBAgIUC7+ekJBbfCa4+95t1Lc9QFnFM00wCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowMDEuMCwGA1UEAwwlVGVzdCBFbmQtZW50aXR5IHdpdGgg
+dW50cnVzdGVkIGlzc3VlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG
+8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0V
+gg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g3
+04hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l
+0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz
+/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaNeMFwwJgYDVR0RBB8wHYIbdW50cnVzdGVk
+aXNzdWVyLmV4YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYW
+aHR0cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0BAQsDggEBADoMA0m+eXNs
+tdp2WpRyK3F9+FXIYbZGdlQFi+G9Dku/8J/cysb3jnN7zdSiCwkSJ38XR/8z4M0O
+x4i3/alFWP1HTvQmVOwP7U31u1h56QlS8ltFasZtd+lOELWvaj9WzG2glcFGTynT
+iIIl3LCm47O6u501xZsp5XPRaeY9956vuP7TwVIx8v2JR5H3hFhk9fR/mhR8QCOB
+HVu/iW9ux7g/9Up1Fi5mYAq6cmArpJ2LzEr57gdV1lfgKObTE++ZWtRa5N+zMZGX
+TU6WARBPH+vVHC1VKxY2SYENxswFtkgCSVoRFzn7sj/8jQ6iaJ86sf9poK0NrHdg
+P0ybC9Y8juA=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/untrustedissuer.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/untrustedissuer.pem.certspec
new file mode 100644
index 000000000..5ba0bc253
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/untrustedissuer.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Other test CA
+subject:Test End-entity with untrusted issuer
+extension:subjectAlternativeName:untrustedissuer.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/bad_certs/v1Cert.pem b/security/manager/ssl/tests/unit/bad_certs/v1Cert.pem
new file mode 100644
index 000000000..c6e59a7a8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/v1Cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICqzCCAZUCFDt6FYWPwMbZVlZa329PtAVVBtsnMAsGCSqGSIb3DQEBCzASMRAw
+DgYDVQQDDAdUZXN0IENBMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBIxEDAOBgNVBAMMB1YxIENlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IBAQCW
+fJUaT3AtmftAlBtS3e1hs6V1XoQNaeSiff8PR6ootvISg5MpU1b2whEvNalJCUMD
+zBXkM7y3ERSgAvROu+CbBFOrOTPPStg88iZFm4WDrgotADxepbYd+x3IOL0vGq7F
+vcqdiQCRuhVRoopipqmowWF4KZtm0SnXoce7GnDhIjLtGxwz+zq3ls/2MrdaxdpL
+ggRkBUNfbTmDMvsjc3GxFHsXuX5cJUKVM2V8x5gNvtDBINiavy8HyQjhwSyTprRM
+KBConOKsh/WntsiakcsefVpc9kAR6DJjVvhFmLqHBUMrpBtDf5pb2JVgp/qn0oCw
+YqD30umtSUWyZaW1I1Nh
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/bad_certs/v1Cert.pem.certspec b/security/manager/ssl/tests/unit/bad_certs/v1Cert.pem.certspec
new file mode 100644
index 000000000..7824630bb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/bad_certs/v1Cert.pem.certspec
@@ -0,0 +1,3 @@
+issuer:Test CA
+subject:V1 Cert
+version:1
diff --git a/security/manager/ssl/tests/unit/head_psm.js b/security/manager/ssl/tests/unit/head_psm.js
new file mode 100644
index 000000000..b6489d605
--- /dev/null
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -0,0 +1,863 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+const { AppConstants } =
+ Cu.import("resource://gre/modules/AppConstants.jsm", {});
+const { ctypes } = Cu.import("resource://gre/modules/ctypes.jsm", {});
+const { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
+const { HttpServer } = Cu.import("resource://testing-common/httpd.js", {});
+const { MockRegistrar } =
+ Cu.import("resource://testing-common/MockRegistrar.jsm", {});
+const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
+const { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
+const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
+
+const isDebugBuild = Cc["@mozilla.org/xpcom/debug;1"]
+ .getService(Ci.nsIDebug2).isDebugBuild;
+
+// The test EV roots are only enabled in debug builds as a security measure.
+//
+// Bug 1008316: B2G doesn't have EV enabled, so EV is not expected even in debug
+// builds.
+const gEVExpected = isDebugBuild && !("@mozilla.org/b2g-process-global;1" in Cc);
+
+const SSS_STATE_FILE_NAME = "SiteSecurityServiceState.txt";
+const PRELOAD_STATE_FILE_NAME = "SecurityPreloadState.txt";
+
+const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
+const SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
+const MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE;
+
+// This isn't really a valid PRErrorCode, but is useful for signalling that
+// a test is expected to succeed.
+const PRErrorCodeSuccess = 0;
+
+// Sort in numerical order
+const SEC_ERROR_INVALID_TIME = SEC_ERROR_BASE + 8;
+const SEC_ERROR_BAD_DER = SEC_ERROR_BASE + 9;
+const SEC_ERROR_BAD_SIGNATURE = SEC_ERROR_BASE + 10;
+const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
+const SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12;
+const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
+const SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20;
+const SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21;
+const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30;
+const SEC_ERROR_CA_CERT_INVALID = SEC_ERROR_BASE + 36;
+const SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION = SEC_ERROR_BASE + 41;
+const SEC_ERROR_INADEQUATE_KEY_USAGE = SEC_ERROR_BASE + 90;
+const SEC_ERROR_INADEQUATE_CERT_TYPE = SEC_ERROR_BASE + 91;
+const SEC_ERROR_CERT_NOT_IN_NAME_SPACE = SEC_ERROR_BASE + 112;
+const SEC_ERROR_CERT_BAD_ACCESS_LOCATION = SEC_ERROR_BASE + 117;
+const SEC_ERROR_OCSP_MALFORMED_REQUEST = SEC_ERROR_BASE + 120;
+const SEC_ERROR_OCSP_SERVER_ERROR = SEC_ERROR_BASE + 121;
+const SEC_ERROR_OCSP_TRY_SERVER_LATER = SEC_ERROR_BASE + 122;
+const SEC_ERROR_OCSP_REQUEST_NEEDS_SIG = SEC_ERROR_BASE + 123;
+const SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST = SEC_ERROR_BASE + 124;
+const SEC_ERROR_OCSP_UNKNOWN_CERT = SEC_ERROR_BASE + 126;
+const SEC_ERROR_OCSP_MALFORMED_RESPONSE = SEC_ERROR_BASE + 129;
+const SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE = SEC_ERROR_BASE + 130;
+const SEC_ERROR_OCSP_OLD_RESPONSE = SEC_ERROR_BASE + 132;
+const SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE = SEC_ERROR_BASE + 141;
+const SEC_ERROR_OCSP_INVALID_SIGNING_CERT = SEC_ERROR_BASE + 144;
+const SEC_ERROR_POLICY_VALIDATION_FAILED = SEC_ERROR_BASE + 160;
+const SEC_ERROR_OCSP_BAD_SIGNATURE = SEC_ERROR_BASE + 157;
+const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
+
+const SSL_ERROR_NO_CYPHER_OVERLAP = SSL_ERROR_BASE + 2;
+const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12;
+const SSL_ERROR_BAD_CERT_ALERT = SSL_ERROR_BASE + 17;
+const SSL_ERROR_WEAK_SERVER_CERT_KEY = SSL_ERROR_BASE + 132;
+
+const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = MOZILLA_PKIX_ERROR_BASE + 0;
+const MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = MOZILLA_PKIX_ERROR_BASE + 1;
+const MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = MOZILLA_PKIX_ERROR_BASE + 2;
+const MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA = MOZILLA_PKIX_ERROR_BASE + 3;
+const MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 5;
+const MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 6;
+const MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING = MOZILLA_PKIX_ERROR_BASE + 8;
+const MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING = MOZILLA_PKIX_ERROR_BASE + 10;
+const MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME = MOZILLA_PKIX_ERROR_BASE + 12;
+
+// Supported Certificate Usages
+const certificateUsageSSLClient = 0x0001;
+const certificateUsageSSLServer = 0x0002;
+const certificateUsageSSLCA = 0x0008;
+const certificateUsageEmailSigner = 0x0010;
+const certificateUsageEmailRecipient = 0x0020;
+const certificateUsageObjectSigner = 0x0040;
+const certificateUsageVerifyCA = 0x0100;
+const certificateUsageStatusResponder = 0x0400;
+
+// A map from the name of a certificate usage to the value of the usage.
+// Useful for printing debugging information and for enumerating all supported
+// usages.
+const allCertificateUsages = {
+ certificateUsageSSLClient,
+ certificateUsageSSLServer,
+ certificateUsageSSLCA,
+ certificateUsageEmailSigner,
+ certificateUsageEmailRecipient,
+ certificateUsageObjectSigner,
+ certificateUsageVerifyCA,
+ certificateUsageStatusResponder
+};
+
+const NO_FLAGS = 0;
+
+// Commonly certificates are represented as PEM. The format is roughly as
+// follows:
+//
+// -----BEGIN CERTIFICATE-----
+// [some lines of base64, each typically 64 characters long]
+// -----END CERTIFICATE-----
+//
+// However, nsIX509CertDB.constructX509FromBase64 and related functions do not
+// handle input of this form. Instead, they require a single string of base64
+// with no newlines or BEGIN/END headers. This is a helper function to convert
+// PEM to the format that nsIX509CertDB requires.
+function pemToBase64(pem) {
+ return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
+ .replace(/-----END CERTIFICATE-----/, "")
+ .replace(/[\r\n]/g, "");
+}
+
+function readFile(file) {
+ let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Ci.nsIFileInputStream);
+ fstream.init(file, -1, 0, 0);
+ let data = NetUtil.readInputStreamToString(fstream, fstream.available());
+ fstream.close();
+ return data;
+}
+
+function addCertFromFile(certdb, filename, trustString) {
+ let certFile = do_get_file(filename, false);
+ let certBytes = readFile(certFile);
+ let successful = false;
+ try {
+ certdb.addCert(certBytes, trustString, null);
+ successful = true;
+ } catch (e) {}
+ if (!successful) {
+ // It might be PEM instead of DER.
+ certdb.addCertFromBase64(pemToBase64(certBytes), trustString, null);
+ }
+}
+
+function constructCertFromFile(filename) {
+ let certFile = do_get_file(filename, false);
+ let certBytes = readFile(certFile);
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ try {
+ return certdb.constructX509(certBytes, certBytes.length);
+ } catch (e) {}
+ // It might be PEM instead of DER.
+ return certdb.constructX509FromBase64(pemToBase64(certBytes));
+}
+
+function setCertTrust(cert, trustString) {
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ certdb.setCertTrustFromString(cert, trustString);
+}
+
+function getXPCOMStatusFromNSS(statusNSS) {
+ let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"]
+ .getService(Ci.nsINSSErrorsService);
+ return nssErrorsService.getXPCOMFromNSSError(statusNSS);
+}
+
+// certdb implements nsIX509CertDB. See nsIX509CertDB.idl for documentation.
+// In particular, hostname is optional.
+function checkCertErrorGenericAtTime(certdb, cert, expectedError, usage, time,
+ /*optional*/ hasEVPolicy,
+ /*optional*/ hostname) {
+ do_print(`cert cn=${cert.commonName}`);
+ do_print(`cert issuer cn=${cert.issuerCommonName}`);
+ let verifiedChain = {};
+ let error = certdb.verifyCertAtTime(cert, usage, NO_FLAGS, hostname, time,
+ verifiedChain, hasEVPolicy || {});
+ Assert.equal(error, expectedError,
+ "Actual and expected error should match");
+}
+
+// certdb implements nsIX509CertDB. See nsIX509CertDB.idl for documentation.
+// In particular, hostname is optional.
+function checkCertErrorGeneric(certdb, cert, expectedError, usage,
+ /*optional*/ hasEVPolicy,
+ /*optional*/ hostname) {
+ do_print(`cert cn=${cert.commonName}`);
+ do_print(`cert issuer cn=${cert.issuerCommonName}`);
+ let verifiedChain = {};
+ let error = certdb.verifyCertNow(cert, usage, NO_FLAGS, hostname,
+ verifiedChain, hasEVPolicy || {});
+ Assert.equal(error, expectedError,
+ "Actual and expected error should match");
+}
+
+function checkEVStatus(certDB, cert, usage, isEVExpected) {
+ let hasEVPolicy = {};
+ checkCertErrorGeneric(certDB, cert, PRErrorCodeSuccess, usage, hasEVPolicy);
+ Assert.equal(hasEVPolicy.value, isEVExpected,
+ "Actual and expected EV status should match");
+}
+
+function _getLibraryFunctionWithNoArguments(functionName, libraryName,
+ returnType) {
+ // Open the NSS library. copied from services/crypto/modules/WeaveCrypto.js
+ let path = ctypes.libraryName(libraryName);
+
+ // XXX really want to be able to pass specific dlopen flags here.
+ let nsslib;
+ try {
+ nsslib = ctypes.open(path);
+ } catch (e) {
+ // In case opening the library without a full path fails,
+ // try again with a full path.
+ let file = Services.dirsvc.get("GreBinD", Ci.nsILocalFile);
+ file.append(path);
+ nsslib = ctypes.open(file.path);
+ }
+
+ let SECStatus = ctypes.int;
+ let func = nsslib.declare(functionName, ctypes.default_abi,
+ returnType || SECStatus);
+ return func;
+}
+
+function clearOCSPCache() {
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ certdb.clearOCSPCache();
+}
+
+function clearSessionCache() {
+ let SSL_ClearSessionCache = null;
+ try {
+ SSL_ClearSessionCache =
+ _getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "ssl3");
+ } catch (e) {
+ // On Windows, this is actually in the nss3 library.
+ SSL_ClearSessionCache =
+ _getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "nss3");
+ }
+ if (!SSL_ClearSessionCache || SSL_ClearSessionCache() != 0) {
+ throw new Error("Failed to clear SSL session cache");
+ }
+}
+
+function getSSLStatistics() {
+ let SSL3Statistics = new ctypes.StructType("SSL3Statistics",
+ [ { "sch_sid_cache_hits": ctypes.long },
+ { "sch_sid_cache_misses": ctypes.long },
+ { "sch_sid_cache_not_ok": ctypes.long },
+ { "hsh_sid_cache_hits": ctypes.long },
+ { "hsh_sid_cache_misses": ctypes.long },
+ { "hsh_sid_cache_not_ok": ctypes.long },
+ { "hch_sid_cache_hits": ctypes.long },
+ { "hch_sid_cache_misses": ctypes.long },
+ { "hch_sid_cache_not_ok": ctypes.long },
+ { "sch_sid_stateless_resumes": ctypes.long },
+ { "hsh_sid_stateless_resumes": ctypes.long },
+ { "hch_sid_stateless_resumes": ctypes.long },
+ { "hch_sid_ticket_parse_failures": ctypes.long }]);
+ let SSL3StatisticsPtr = new ctypes.PointerType(SSL3Statistics);
+ let SSL_GetStatistics = null;
+ try {
+ SSL_GetStatistics = _getLibraryFunctionWithNoArguments("SSL_GetStatistics",
+ "ssl3",
+ SSL3StatisticsPtr);
+ } catch (e) {
+ // On Windows, this is actually in the nss3 library.
+ SSL_GetStatistics = _getLibraryFunctionWithNoArguments("SSL_GetStatistics",
+ "nss3",
+ SSL3StatisticsPtr);
+ }
+ if (!SSL_GetStatistics) {
+ throw new Error("Failed to get SSL statistics");
+ }
+ return SSL_GetStatistics();
+}
+
+// Set up a TLS testing environment that has a TLS server running and
+// ready to accept connections. This async function starts the server and
+// waits for the server to indicate that it is ready.
+//
+// Each test should have its own subdomain of example.com, for example
+// my-first-connection-test.example.com. The server can use the server
+// name (passed through the SNI TLS extension) to determine what behavior
+// the server side of the text should exhibit. See TLSServer.h for more
+// information on how to write the server side of tests.
+//
+// Create a new source file for your new server executable in
+// security/manager/ssl/tests/unit/tlsserver/cmd similar to the other ones in
+// that directory, and add a reference to it to the sources variable in that
+// directory's moz.build.
+//
+// Modify TEST_HARNESS_BINS in
+// testing/mochitest/Makefile.in and NO_PKG_FILES in
+// toolkit/mozapps/installer/packager.mk to make sure the new executable
+// gets included in the packages used for shipping the tests to the test
+// runners in our build/test farm. (Things will work fine locally without
+// these changes but will break on TBPL.)
+//
+// Your test script should look something like this:
+/*
+
+// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// <documentation on your test>
+
+function run_test() {
+ do_get_profile();
+ add_tls_server_setup("<test-server-name>", "<path-to-certificate-directory>");
+
+ add_connection_test("<test-name-1>.example.com",
+ SEC_ERROR_xxx,
+ function() { ... },
+ function(aTransportSecurityInfo) { ... },
+ function(aTransport) { ... });
+ [...]
+ add_connection_test("<test-name-n>.example.com", PRErrorCodeSuccess);
+
+ run_next_test();
+}
+*/
+
+function add_tls_server_setup(serverBinName, certsPath) {
+ add_test(function() {
+ _setupTLSServerTest(serverBinName, certsPath);
+ });
+}
+
+/**
+ * Add a TLS connection test case.
+ *
+ * @param {String} aHost
+ * The hostname to pass in the SNI TLS extension; this should unambiguously
+ * identify which test is being run.
+ * @param {PRErrorCode} aExpectedResult
+ * The expected result of the connection. If an error is not expected, pass
+ * in PRErrorCodeSuccess.
+ * @param {Function} aBeforeConnect
+ * A callback function that takes no arguments that will be called before the
+ * connection is attempted.
+ * @param {Function} aWithSecurityInfo
+ * A callback function that takes an nsITransportSecurityInfo, which is called
+ * after the TLS handshake succeeds.
+ * @param {Function} aAfterStreamOpen
+ * A callback function that is called with the nsISocketTransport once the
+ * output stream is ready.
+ * @param {OriginAttributes} aOriginAttributes (optional)
+ * The origin attributes that the socket transport will have. This parameter
+ * affects OCSP because OCSP cache is double-keyed by origin attributes' first
+ * party domain.
+ */
+function add_connection_test(aHost, aExpectedResult,
+ aBeforeConnect, aWithSecurityInfo,
+ aAfterStreamOpen,
+ /*optional*/ aOriginAttributes) {
+ const REMOTE_PORT = 8443;
+
+ function Connection(host) {
+ this.host = host;
+ let threadManager = Cc["@mozilla.org/thread-manager;1"]
+ .getService(Ci.nsIThreadManager);
+ this.thread = threadManager.currentThread;
+ this.defer = Promise.defer();
+ let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
+ .getService(Ci.nsISocketTransportService);
+ this.transport = sts.createTransport(["ssl"], 1, host, REMOTE_PORT, null);
+ // See bug 1129771 - attempting to connect to [::1] when the server is
+ // listening on 127.0.0.1 causes frequent failures on OS X 10.10.
+ this.transport.connectionFlags |= Ci.nsISocketTransport.DISABLE_IPV6;
+ this.transport.setEventSink(this, this.thread);
+ if (aOriginAttributes) {
+ this.transport.originAttributes = aOriginAttributes;
+ }
+ this.inputStream = null;
+ this.outputStream = null;
+ this.connected = false;
+ }
+
+ Connection.prototype = {
+ // nsITransportEventSink
+ onTransportStatus: function(aTransport, aStatus, aProgress, aProgressMax) {
+ if (!this.connected && aStatus == Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
+ this.connected = true;
+ this.outputStream.asyncWait(this, 0, 0, this.thread);
+ }
+ },
+
+ // nsIInputStreamCallback
+ onInputStreamReady: function(aStream) {
+ try {
+ // this will throw if the stream has been closed by an error
+ let str = NetUtil.readInputStreamToString(aStream, aStream.available());
+ Assert.equal(str, "0",
+ "Should have received ASCII '0' from server");
+ this.inputStream.close();
+ this.outputStream.close();
+ this.result = Cr.NS_OK;
+ } catch (e) {
+ this.result = e.result;
+ }
+ this.defer.resolve(this);
+ },
+
+ // nsIOutputStreamCallback
+ onOutputStreamReady: function(aStream) {
+ if (aAfterStreamOpen) {
+ aAfterStreamOpen(this.transport);
+ }
+ let sslSocketControl = this.transport.securityInfo
+ .QueryInterface(Ci.nsISSLSocketControl);
+ sslSocketControl.proxyStartSSL();
+ this.outputStream.write("0", 1);
+ let inStream = this.transport.openInputStream(0, 0, 0)
+ .QueryInterface(Ci.nsIAsyncInputStream);
+ this.inputStream = inStream;
+ this.inputStream.asyncWait(this, 0, 0, this.thread);
+ },
+
+ go: function() {
+ this.outputStream = this.transport.openOutputStream(0, 0, 0)
+ .QueryInterface(Ci.nsIAsyncOutputStream);
+ return this.defer.promise;
+ }
+ };
+
+ /* Returns a promise to connect to host that resolves to the result of that
+ * connection */
+ function connectTo(host) {
+ Services.prefs.setCharPref("network.dns.localDomains", host);
+ let connection = new Connection(host);
+ return connection.go();
+ }
+
+ add_test(function() {
+ if (aBeforeConnect) {
+ aBeforeConnect();
+ }
+ connectTo(aHost).then(function(conn) {
+ do_print("handling " + aHost);
+ let expectedNSResult = aExpectedResult == PRErrorCodeSuccess
+ ? Cr.NS_OK
+ : getXPCOMStatusFromNSS(aExpectedResult);
+ Assert.equal(conn.result, expectedNSResult,
+ "Actual and expected connection result should match");
+ if (aWithSecurityInfo) {
+ aWithSecurityInfo(conn.transport.securityInfo
+ .QueryInterface(Ci.nsITransportSecurityInfo));
+ }
+ run_next_test();
+ });
+ });
+}
+
+function _getBinaryUtil(binaryUtilName) {
+ let directoryService = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties);
+
+ let utilBin = directoryService.get("CurProcD", Ci.nsILocalFile);
+ utilBin.append(binaryUtilName + mozinfo.bin_suffix);
+ // If we're testing locally, the above works. If not, the server executable
+ // is in another location.
+ if (!utilBin.exists()) {
+ utilBin = directoryService.get("CurWorkD", Ci.nsILocalFile);
+ while (utilBin.path.indexOf("xpcshell") != -1) {
+ utilBin = utilBin.parent;
+ }
+ utilBin.append("bin");
+ utilBin.append(binaryUtilName + mozinfo.bin_suffix);
+ }
+ // But maybe we're on Android or B2G, where binaries are in /data/local/xpcb.
+ if (!utilBin.exists()) {
+ utilBin.initWithPath("/data/local/xpcb/");
+ utilBin.append(binaryUtilName);
+ }
+ Assert.ok(utilBin.exists(), `Binary util ${binaryUtilName} should exist`);
+ return utilBin;
+}
+
+// Do not call this directly; use add_tls_server_setup
+function _setupTLSServerTest(serverBinName, certsPath)
+{
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ // The trusted CA that is typically used for "good" certificates.
+ addCertFromFile(certdb, `${certsPath}/test-ca.pem`, "CTu,u,u");
+
+ const CALLBACK_PORT = 8444;
+
+ let directoryService = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties);
+ let envSvc = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
+ let greBinDir = directoryService.get("GreBinD", Ci.nsIFile);
+ envSvc.set("DYLD_LIBRARY_PATH", greBinDir.path);
+ // TODO(bug 1107794): Android libraries are in /data/local/xpcb, but "GreBinD"
+ // does not return this path on Android, so hard code it here.
+ envSvc.set("LD_LIBRARY_PATH", greBinDir.path + ":/data/local/xpcb");
+ envSvc.set("MOZ_TLS_SERVER_DEBUG_LEVEL", "3");
+ envSvc.set("MOZ_TLS_SERVER_CALLBACK_PORT", CALLBACK_PORT);
+
+ let httpServer = new HttpServer();
+ httpServer.registerPathHandler("/",
+ function handleServerCallback(aRequest, aResponse) {
+ aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
+ aResponse.setHeader("Content-Type", "text/plain");
+ let responseBody = "OK!";
+ aResponse.bodyOutputStream.write(responseBody, responseBody.length);
+ do_execute_soon(function() {
+ httpServer.stop(run_next_test);
+ });
+ });
+ httpServer.start(CALLBACK_PORT);
+
+ let serverBin = _getBinaryUtil(serverBinName);
+ let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(serverBin);
+ let certDir = directoryService.get("CurWorkD", Ci.nsILocalFile);
+ certDir.append(`${certsPath}`);
+ Assert.ok(certDir.exists(), `certificate folder (${certsPath}) should exist`);
+ // Using "sql:" causes the SQL DB to be used so we can run tests on Android.
+ process.run(false, [ "sql:" + certDir.path ], 1);
+
+ do_register_cleanup(function() {
+ process.kill();
+ });
+}
+
+// Returns an Array of OCSP responses for a given ocspRespArray and a location
+// for a nssDB where the certs and public keys are prepopulated.
+// ocspRespArray is an array of arrays like:
+// [ [typeOfResponse, certnick, extracertnick]...]
+function generateOCSPResponses(ocspRespArray, nssDBlocation)
+{
+ let utilBinName = "GenerateOCSPResponse";
+ let ocspGenBin = _getBinaryUtil(utilBinName);
+ let retArray = [];
+
+ for (let i = 0; i < ocspRespArray.length; i++) {
+ let argArray = [];
+ let ocspFilepre = do_get_file(i.toString() + ".ocsp", true);
+ let filename = ocspFilepre.path;
+ // Using "sql:" causes the SQL DB to be used so we can run tests on Android.
+ argArray.push("sql:" + nssDBlocation);
+ argArray.push(ocspRespArray[i][0]); // ocsRespType;
+ argArray.push(ocspRespArray[i][1]); // nick;
+ argArray.push(ocspRespArray[i][2]); // extranickname
+ argArray.push(filename);
+ do_print("argArray = " + argArray);
+
+ let process = Cc["@mozilla.org/process/util;1"]
+ .createInstance(Ci.nsIProcess);
+ process.init(ocspGenBin);
+ process.run(true, argArray, 5);
+ Assert.equal(0, process.exitValue, "Process exit value should be 0");
+ let ocspFile = do_get_file(i.toString() + ".ocsp", false);
+ retArray.push(readFile(ocspFile));
+ ocspFile.remove(false);
+ }
+ return retArray;
+}
+
+// Starts and returns an http responder that will cause a test failure if it is
+// queried. The server identities are given by a non-empty array
+// serverIdentities.
+function getFailingHttpServer(serverPort, serverIdentities) {
+ let httpServer = new HttpServer();
+ httpServer.registerPrefixHandler("/", function(request, response) {
+ Assert.ok(false, "HTTP responder should not have been queried");
+ });
+ httpServer.identity.setPrimary("http", serverIdentities.shift(), serverPort);
+ serverIdentities.forEach(function(identity) {
+ httpServer.identity.add("http", identity, serverPort);
+ });
+ httpServer.start(serverPort);
+ return httpServer;
+}
+
+// Starts an http OCSP responder that serves good OCSP responses and
+// returns an object with a method stop that should be called to stop
+// the http server.
+// NB: Because generating OCSP responses inside the HTTP request
+// handler can cause timeouts, the expected responses are pre-generated
+// all at once before starting the server. This means that their producedAt
+// times will all be the same. If a test depends on this not being the case,
+// perhaps calling startOCSPResponder twice (at different times) will be
+// necessary.
+//
+// serverPort is the port of the http OCSP responder
+// identity is the http hostname that will answer the OCSP requests
+// nssDBLocation is the location of the NSS database from where the OCSP
+// responses will be generated (assumes appropiate keys are present)
+// expectedCertNames is an array of nicks of the certs to be responsed
+// expectedBasePaths is an optional array that is used to indicate
+// what is the expected base path of the OCSP request.
+// expectedMethods is an optional array of methods ("GET" or "POST") indicating
+// by which HTTP method the server is expected to be queried.
+// expectedResponseTypes is an optional array of OCSP response types to use (see
+// GenerateOCSPResponse.cpp).
+function startOCSPResponder(serverPort, identity, nssDBLocation,
+ expectedCertNames, expectedBasePaths,
+ expectedMethods, expectedResponseTypes) {
+ let ocspResponseGenerationArgs = expectedCertNames.map(
+ function(expectedNick) {
+ let responseType = "good";
+ if (expectedResponseTypes && expectedResponseTypes.length >= 1) {
+ responseType = expectedResponseTypes.shift();
+ }
+ return [responseType, expectedNick, "unused"];
+ }
+ );
+ let ocspResponses = generateOCSPResponses(ocspResponseGenerationArgs,
+ nssDBLocation);
+ let httpServer = new HttpServer();
+ httpServer.registerPrefixHandler("/",
+ function handleServerCallback(aRequest, aResponse) {
+ do_print("got request for: " + aRequest.path);
+ let basePath = aRequest.path.slice(1).split("/")[0];
+ if (expectedBasePaths.length >= 1) {
+ Assert.equal(basePath, expectedBasePaths.shift(),
+ "Actual and expected base path should match");
+ }
+ Assert.ok(expectedCertNames.length >= 1,
+ "expectedCertNames should contain >= 1 entries");
+ if (expectedMethods && expectedMethods.length >= 1) {
+ Assert.equal(aRequest.method, expectedMethods.shift(),
+ "Actual and expected fetch method should match");
+ }
+ aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
+ aResponse.setHeader("Content-Type", "application/ocsp-response");
+ aResponse.write(ocspResponses.shift());
+ });
+ httpServer.identity.setPrimary("http", identity, serverPort);
+ httpServer.start(serverPort);
+ return {
+ stop: function(callback) {
+ // make sure we consumed each expected response
+ Assert.equal(ocspResponses.length, 0,
+ "Should have 0 remaining expected OCSP responses");
+ if (expectedMethods) {
+ Assert.equal(expectedMethods.length, 0,
+ "Should have 0 remaining expected fetch methods");
+ }
+ if (expectedBasePaths) {
+ Assert.equal(expectedBasePaths.length, 0,
+ "Should have 0 remaining expected base paths");
+ }
+ if (expectedResponseTypes) {
+ Assert.equal(expectedResponseTypes.length, 0,
+ "Should have 0 remaining expected response types");
+ }
+ httpServer.stop(callback);
+ }
+ };
+}
+
+// A prototype for a fake, error-free sslstatus
+var FakeSSLStatus = function(certificate) {
+ this.serverCert = certificate;
+};
+
+FakeSSLStatus.prototype = {
+ serverCert: null,
+ cipherName: null,
+ keyLength: 2048,
+ isDomainMismatch: false,
+ isNotValidAtThisTime: false,
+ isUntrusted: false,
+ isExtendedValidation: false,
+ getInterface: function(aIID) {
+ return this.QueryInterface(aIID);
+ },
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Ci.nsISSLStatus) ||
+ aIID.equals(Ci.nsISupports)) {
+ return this;
+ }
+ throw new Error(Cr.NS_ERROR_NO_INTERFACE);
+ },
+};
+
+// Utility functions for adding tests relating to certificate error overrides
+
+// Helper function for add_cert_override_test. Probably doesn't need to be
+// called directly.
+function add_cert_override(aHost, aExpectedBits, aExpectedErrorRegexp,
+ aSecurityInfo) {
+ if (aExpectedErrorRegexp) {
+ do_print(aSecurityInfo.errorMessage);
+ Assert.ok(aExpectedErrorRegexp.test(aSecurityInfo.errorMessage),
+ "Actual error message should match expected error regexp");
+ }
+ let sslstatus = aSecurityInfo.QueryInterface(Ci.nsISSLStatusProvider)
+ .SSLStatus;
+ let bits =
+ (sslstatus.isUntrusted ? Ci.nsICertOverrideService.ERROR_UNTRUSTED : 0) |
+ (sslstatus.isDomainMismatch ? Ci.nsICertOverrideService.ERROR_MISMATCH : 0) |
+ (sslstatus.isNotValidAtThisTime ? Ci.nsICertOverrideService.ERROR_TIME : 0);
+ Assert.equal(bits, aExpectedBits,
+ "Actual and expected override bits should match");
+ let cert = sslstatus.serverCert;
+ let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
+ .getService(Ci.nsICertOverrideService);
+ certOverrideService.rememberValidityOverride(aHost, 8443, cert, aExpectedBits,
+ true);
+}
+
+// Given a host, expected error bits (see nsICertOverrideService.idl), an
+// expected error code, and optionally a regular expression that the resulting
+// error message must match, tests that an initial connection to the host fails
+// with the expected errors and that adding an override results in a subsequent
+// connection succeeding.
+function add_cert_override_test(aHost, aExpectedBits, aExpectedError,
+ aExpectedErrorRegexp = undefined) {
+ add_connection_test(aHost, aExpectedError, null,
+ add_cert_override.bind(this, aHost, aExpectedBits,
+ aExpectedErrorRegexp));
+ add_connection_test(aHost, PRErrorCodeSuccess, null, aSecurityInfo => {
+ Assert.ok(aSecurityInfo.securityState &
+ Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN,
+ "Cert override flag should be set on the security state");
+ });
+}
+
+// Helper function for add_prevented_cert_override_test. This is much like
+// add_cert_override except it may not be the case that the connection has an
+// SSLStatus set on it. In this case, the error was not overridable anyway, so
+// we consider it a success.
+function attempt_adding_cert_override(aHost, aExpectedBits, aSecurityInfo) {
+ let sslstatus = aSecurityInfo.QueryInterface(Ci.nsISSLStatusProvider)
+ .SSLStatus;
+ if (sslstatus) {
+ let bits =
+ (sslstatus.isUntrusted ? Ci.nsICertOverrideService.ERROR_UNTRUSTED : 0) |
+ (sslstatus.isDomainMismatch ? Ci.nsICertOverrideService.ERROR_MISMATCH : 0) |
+ (sslstatus.isNotValidAtThisTime ? Ci.nsICertOverrideService.ERROR_TIME : 0);
+ Assert.equal(bits, aExpectedBits,
+ "Actual and expected override bits should match");
+ let cert = sslstatus.serverCert;
+ let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
+ .getService(Ci.nsICertOverrideService);
+ certOverrideService.rememberValidityOverride(aHost, 8443, cert, aExpectedBits,
+ true);
+ }
+}
+
+// Given a host, expected error bits (see nsICertOverrideService.idl), and
+// an expected error code, tests that an initial connection to the host fails
+// with the expected errors and that adding an override does not result in a
+// subsequent connection succeeding (i.e. the same error code is encountered).
+// The idea here is that for HSTS hosts or hosts with key pins, no error is
+// overridable, even if an entry is added to the override service.
+function add_prevented_cert_override_test(aHost, aExpectedBits, aExpectedError) {
+ add_connection_test(aHost, aExpectedError, null,
+ attempt_adding_cert_override.bind(this, aHost, aExpectedBits));
+ add_connection_test(aHost, aExpectedError);
+}
+
+function loginToDBWithDefaultPassword() {
+ let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+ .getService(Ci.nsIPK11TokenDB);
+ let token = tokenDB.getInternalKeyToken();
+ token.initPassword("");
+ token.login(/*force*/ false);
+}
+
+// Helper for asyncTestCertificateUsages.
+class CertVerificationResult {
+ constructor(certName, usageString, successExpected, resolve) {
+ this.certName = certName;
+ this.usageString = usageString;
+ this.successExpected = successExpected;
+ this.resolve = resolve;
+ }
+
+ verifyCertFinished(aPRErrorCode, aVerifiedChain, aHasEVPolicy) {
+ if (this.successExpected) {
+ equal(aPRErrorCode, PRErrorCodeSuccess,
+ `verifying ${this.certName} for ${this.usageString} should succeed`);
+ } else {
+ notEqual(aPRErrorCode, PRErrorCodeSuccess,
+ `verifying ${this.certName} for ${this.usageString} should fail`);
+ }
+ this.resolve();
+ }
+}
+
+/**
+ * Asynchronously attempts to verify the given certificate for all supported
+ * usages (see allCertificateUsages). Verifies that the results match the
+ * expected successful usages. Returns a promise that will resolve when all
+ * verifications have been performed.
+ * Verification happens "now" with no specified flags or hostname.
+ *
+ * @param {nsIX509CertDB} certdb
+ * The certificate database to use to verify the certificate.
+ * @param {nsIX509Cert} cert
+ * The certificate to be verified.
+ * @param {Number[]} expectedUsages
+ * A list of usages (as their integer values) that are expected to verify
+ * successfully.
+ * @return {Promise}
+ * A promise that will resolve with no value when all asynchronous operations
+ * have completed.
+ */
+function asyncTestCertificateUsages(certdb, cert, expectedUsages) {
+ let now = (new Date()).getTime() / 1000;
+ let promises = [];
+ Object.keys(allCertificateUsages).forEach(usageString => {
+ let promise = new Promise((resolve, reject) => {
+ let usage = allCertificateUsages[usageString];
+ let successExpected = expectedUsages.includes(usage);
+ let result = new CertVerificationResult(cert.commonName, usageString,
+ successExpected, resolve);
+ certdb.asyncVerifyCertAtTime(cert, usage, 0, null, now, result);
+ });
+ promises.push(promise);
+ });
+ return Promise.all(promises);
+}
+
+/**
+ * Loads the pkcs11testmodule.cpp test PKCS #11 module, and registers a cleanup
+ * function that unloads it once the calling test completes.
+ *
+ * @param {Boolean} expectModuleUnloadToFail
+ * Should be set to true for tests that manually unload the
+ * test module, so the attempt to auto unload the test module
+ * doesn't cause a test failure. Should be set to false
+ * otherwise, so failure to automatically unload the test
+ * module gets reported.
+ */
+function loadPKCS11TestModule(expectModuleUnloadToFail) {
+ let libraryFile = Services.dirsvc.get("CurWorkD", Ci.nsILocalFile);
+ libraryFile.append("pkcs11testmodule");
+ libraryFile.append(ctypes.libraryName("pkcs11testmodule"));
+ ok(libraryFile.exists(), "The pkcs11testmodule file should exist");
+
+ let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
+ do_register_cleanup(() => {
+ try {
+ pkcs11.deleteModule("PKCS11 Test Module");
+ } catch (e) {
+ Assert.ok(expectModuleUnloadToFail,
+ `Module unload should suceed only when expected: ${e}`);
+ }
+ });
+ pkcs11.addModule("PKCS11 Test Module", libraryFile.path, 0, 0);
+}
diff --git a/security/manager/ssl/tests/unit/moz.build b/security/manager/ssl/tests/unit/moz.build
new file mode 100644
index 000000000..8a97120c2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/moz.build
@@ -0,0 +1,37 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += ['tlsserver']
+
+if not CONFIG['MOZ_NO_SMART_CARDS']:
+ DIRS += ['pkcs11testmodule']
+
+TEST_DIRS += [
+ 'bad_certs',
+ 'ocsp_certs',
+ 'test_baseline_requirements',
+ 'test_cert_eku',
+ 'test_cert_embedded_null',
+ 'test_cert_keyUsage',
+ 'test_cert_sha1',
+ 'test_cert_signatures',
+ 'test_cert_trust',
+ 'test_cert_version',
+ 'test_certDB_import',
+ 'test_content_signing',
+ 'test_ev_certs',
+ 'test_getchain',
+ 'test_intermediate_basic_usage_constraints',
+ 'test_keysize',
+ 'test_keysize_ev',
+ 'test_name_constraints',
+ 'test_ocsp_fetch_method',
+ 'test_ocsp_url',
+ 'test_onecrl',
+ 'test_pinning_dynamic',
+ 'test_startcom_wosign',
+ 'test_validity',
+]
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/ca-used-as-end-entity.pem b/security/manager/ssl/tests/unit/ocsp_certs/ca-used-as-end-entity.pem
new file mode 100644
index 000000000..ae40112c3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/ca-used-as-end-entity.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAiugAwIBAgIUBUmy5jtGrDso26TeIelwmtF+KFAwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowLzEtMCsGA1UEAwwkVGVzdCBJbnRlcm1lZGlhdGUgdXNlZCBhcyBF
+bmQtRW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABo3IwcDAMBgNVHRMEBTADAQH/MDIGCCsGAQUFBwEBBCYw
+JDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzAsBgNVHREEJTAj
+giFjYS11c2VkLWFzLWVuZC1lbnRpdHkuZXhhbXBsZS5jb20wCwYJKoZIhvcNAQEL
+A4IBAQApr3pPS4uWz6oPEhrTO73K+JTP2VRTKgtbooPhOZ6tCRz75P729RzVOEZF
+Vf87VSFTTXUdG5Q6+SDNuCdDuyyPR4q38s+8jgv3OVfsEbhPuSx73pLAzYg727Ip
+U2ROGoVysc3JrUfwPZSvQ/i4iqdb2sVwtqR5LM1nApy5+p6Ef8cwjfm9qsdrHlnx
+3VdiioEOp+8SKH5rzfZe+1jepRODlqvFEO9gFbaqjHLzL005xAcfpsZPH5JzDhqD
+g4QiIFlm+wwQ9pTBpk1ZmbgDyk4frrxughFsbR4zDDTfJCREa5RlwH34xOkx/cTu
+ee/qZzerx61VI88GvLK87eX2ZiH1
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/ca-used-as-end-entity.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/ca-used-as-end-entity.pem.certspec
new file mode 100644
index 000000000..8e16705b5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/ca-used-as-end-entity.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Test Intermediate used as End-Entity
+extension:basicConstraints:cA,
+extension:authorityInformationAccess:http://localhost:8888/
+extension:subjectAlternativeName:ca-used-as-end-entity.example.com
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/default-ee.key b/security/manager/ssl/tests/unit/ocsp_certs/default-ee.key
new file mode 100644
index 000000000..8af23e068
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/default-ee.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAECggEBAJ7LzjhhpFTsseD+j4XdQ8kvWCXOLpl4hNDhqUnaosWs
+VZskBFDlrJ/gw+McDu+mUlpl8MIhlABO4atGPd6e6CKHzJPnRqkZKcXmrD2IdT9s
+JbpZeec+XY+yOREaPNq4pLDN9fnKsF8SM6ODNcZLVWBSXn47kq18dQTPHcfLAFeI
+r8vh6Pld90AqFRUw1YCDRoZOs3CqeZVqWHhiy1M3kTB/cNkcltItABppAJuSPGgz
+iMnzbLm16+ZDAgQceNkIIGuHAJy4yrrK09vbJ5L7kRss9NtmA1hb6a4Mo7jmQXqg
+SwbkcOoaO1gcoDpngckxW2KzDmAR8iRyWUbuxXxtlEECgYEA3W4dT//r9o2InE0R
+TNqqnKpjpZN0KGyKXCmnF7umA3VkTVyqZ0xLi8cyY1hkYiDkVQ12CKwn1Vttt0+N
+gSfvj6CQmLaRR94GVXNEfhg9Iv59iFrOtRPZWB3V4HwakPXOCHneExNx7O/JznLp
+xD3BJ9I4GQ3oEXc8pdGTAfSMdCsCgYEA16dz2evDgKdn0v7Ak0rU6LVmckB3Gs3r
+ta15b0eP7E1FmF77yVMpaCicjYkQL63yHzTi3UlA66jAnW0fFtzClyl3TEMnXpJR
+3b5JCeH9O/Hkvt9Go5uLODMo70rjuVuS8gcK8myefFybWH/t3gXo59hspXiG+xZY
+EKd7mEW8MScCgYEAlkcrQaYQwK3hryJmwWAONnE1W6QtS1oOtOnX6zWBQAul3RMs
+2xpekyjHu8C7sBVeoZKXLt+X0SdR2Pz2rlcqMLHqMJqHEt1OMyQdse5FX8CT9byb
+WS11bmYhR08ywHryL7J100B5KzK6JZC7smGu+5WiWO6lN2VTFb6cJNGRmS0CgYAo
+tFCnp1qFZBOyvab3pj49lk+57PUOOCPvbMjo+ibuQT+LnRIFVA8Su+egx2got7pl
+rYPMpND+KiIBFOGzXQPVqFv+Jwa9UPzmz83VcbRspiG47UfWBbvnZbCqSgZlrCU2
+TaIBVAMuEgS4VZ0+NPtbF3yaVv+TUQpaSmKHwVHeLQKBgCgGe5NVgB0u9S36ltit
+tYlnPPjuipxv9yruq+nva+WKT0q/BfeIlH3IUf2qNFQhR6caJGv7BU7naqNGq80m
+ks/J5ExR5vBpxzXgc7oBn2pyFJYckbJoccrqv48GRBigJpDjmo1f8wZ7fNt/ULH1
+NBinA5ZsT8d0v3QCr2xDJH9D
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/default-ee.key.keyspec b/security/manager/ssl/tests/unit/ocsp_certs/default-ee.key.keyspec
new file mode 100644
index 000000000..4ad96d515
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/default-ee.key.keyspec
@@ -0,0 +1 @@
+default
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/default-ee.pem b/security/manager/ssl/tests/unit/ocsp_certs/default-ee.pem
new file mode 100644
index 000000000..0a9eaebb5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/default-ee.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhTCCAm+gAwIBAgIUNRvpOhsDHEYbRf6bsiAPbvKe2VAwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowGjEYMBYGA1UEAwwPVGVzdCBFbmQtZW50aXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABo4HKMIHH
+MIGQBgNVHREEgYgwgYWCCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbYIVKi5waW5u
+aW5nLmV4YW1wbGUuY29tgigqLmluY2x1ZGUtc3ViZG9tYWlucy5waW5uaW5nLmV4
+YW1wbGUuY29tgigqLmV4Y2x1ZGUtc3ViZG9tYWlucy5waW5uaW5nLmV4YW1wbGUu
+Y29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9z
+dDo4ODg4LzALBgkqhkiG9w0BAQsDggEBAH6+Qe/y1TTCx2w6f31VWp5lcizPkS8s
+ODfbgT9pKYqqvYDeiDu3q8SLGHTTsHWWewBCu5Jd0mXPXfZ4FEHcwbVJZUZBvQVr
+1aNBCriuzhNUyfjkvfCgM4OuxgNwjbihGDE8VzfxTiz8mDN0AgACCZaUTQnybQc0
+SW+ldxspBgQJom0tkZ+TGi80L3/5P5J2+7AchxhAZzQmebDnxNYDZXCJH8w15was
+OzM5BrQzz3vuxupO7lsRzZIzAU+uQD4bjcMpz3oMdj3/0lb0HZGMdU22Ub36PvLC
+6mYbTtf0IS5TVyLnbCNeliE6zoPnQPBzAUfoOeD1Tn6HQUQUT8oTf2E=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/default-ee.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/default-ee.pem.certspec
new file mode 100644
index 000000000..554339ff5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/default-ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Test End-entity
+extension:subjectAlternativeName:localhost,*.example.com,*.pinning.example.com,*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/delegatedSHA1Signer.pem b/security/manager/ssl/tests/unit/ocsp_certs/delegatedSHA1Signer.pem
new file mode 100644
index 000000000..c002ab376
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/delegatedSHA1Signer.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3zCCAcmgAwIBAgIUIxRG1UWRha0HYTAhwhrKHkbqmyMwCwYJKoZIhvcNAQEF
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowKDEmMCQGA1UEAwwdVGVzdCBTSEExIERlbGVnYXRlZCBSZXNwb25k
+ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBdcZSZgmfdwgqZ5Hx
+uHbDf1zlOLBsSs0iscvUb6Za2irdQcjCSYrEo7PB9hSH9BtpiUG9gKUcPBICRMWE
+pMRIMwXlE4wBBs8IvpqGJ2C65qLo828jxdmDE7nfrzeDRdrOUdTW3NKmyzzHBuvN
+MHDsmMzkCqWR1ylaf3HFvmZpHSst/shJRFkLxaPqSf2TsddTQF8Xc3aZlYZmJUeX
+7UJpCIgIEUIgaZiKQ/7kjOaHgd0itqac0oN1Ex+TKxKM4ob6fSUcBirSfvAW8YfN
+1U6DKzW4kw90upCqi8dhZyQqsf1tYhQNGMTAuMaPw3SEVzJK196G5lUvHR4ZHXEh
+aNO7AgMBAAGjFzAVMBMGA1UdJQQMMAoGCCsGAQUFBwMJMAsGCSqGSIb3DQEBBQOC
+AQEANLgtJ15k2R80tTTbdC1m/ZASP24kA5t+lMUcZ2nBrIAKivNshI8oI3BVqq6a
+/SP+0D1A0OGkOy8NwwlXhTb5ZAJj8SJyMrfanuGzZQhzFrQc55KeETCm8nPyzGQ9
+bqQs1LETdVsdYXIsY+ODCIHHc3GrC7M4AcfeWobi+fANOYiTkohu+xMrwkNk0cpC
+7rGru+XJwmljnc0OwcMeClLOpqRGVXV7bVBQmM731dBSqQabDkOANqEzSD9R7cJN
+I/UXxZ24i80bErMcgYQIKA6JwS9deLrx1PVc5s5rsZjMtDT8vuDiRXNbjtbINYFw
+MncXL0zcoBe7IV3rdJwY+y3Snw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/delegatedSHA1Signer.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/delegatedSHA1Signer.pem.certspec
new file mode 100644
index 000000000..bdf3e2ee4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/delegatedSHA1Signer.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Test SHA1 Delegated Responder
+subjectKey:alternate
+signature:sha1WithRSAEncryption
+extension:extKeyUsage:OCSPSigning
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/delegatedSigner.pem b/security/manager/ssl/tests/unit/ocsp_certs/delegatedSigner.pem
new file mode 100644
index 000000000..a89c8d2f7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/delegatedSigner.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2jCCAcSgAwIBAgIUQXEL+8VLzS0MV1fxD5oqP+1e6jMwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowIzEhMB8GA1UEAwwYVGVzdCBEZWxlZ2F0ZWQgUmVzcG9uZGVyMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwXXGUmYJn3cIKmeR8bh2w39c
+5TiwbErNIrHL1G+mWtoq3UHIwkmKxKOzwfYUh/QbaYlBvYClHDwSAkTFhKTESDMF
+5ROMAQbPCL6ahidguuai6PNvI8XZgxO53683g0XazlHU1tzSpss8xwbrzTBw7JjM
+5AqlkdcpWn9xxb5maR0rLf7ISURZC8Wj6kn9k7HXU0BfF3N2mZWGZiVHl+1CaQiI
+CBFCIGmYikP+5Izmh4HdIramnNKDdRMfkysSjOKG+n0lHAYq0n7wFvGHzdVOgys1
+uJMPdLqQqovHYWckKrH9bWIUDRjEwLjGj8N0hFcyStfehuZVLx0eGR1xIWjTuwID
+AQABoxcwFTATBgNVHSUEDDAKBggrBgEFBQcDCTALBgkqhkiG9w0BAQsDggEBABNl
+rZcaJMbZvRzFDOZ7ZFjf/hqf/VxFBwiP7JOY3ZpvUTkvZkHdEQIaps9Lg0PRWsVj
+Q23PgVUJnsRL1qIFsYHDJ0NB3X+ly7IV2kjH0LBshN+8/xHgCzZy6FXtC5tNa3gT
+7GFQONTVRoVnnI8JlGMgFFrgY4H/Eyz9YlD6Sgf/zmouPCftajAyKLIrn0wDZXLv
+6Cla7n71vDVp8XsdyNZsDVa3x3eU83zzhvQkZz14ScoDzdC0S6Rk9fUTZIm4x/lJ
+LV93G6M7AyfnK51EKJR2woG/shfpLXV7Wvc/1122vTQaBqvXwervYKfndf3IRx6U
+JkHz9cSPh0zZyGpaY3Y=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/delegatedSigner.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/delegatedSigner.pem.certspec
new file mode 100644
index 000000000..19971eeb4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/delegatedSigner.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Test Delegated Responder
+subjectKey:alternate
+extension:extKeyUsage:OCSPSigning
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerFromIntermediate.pem b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerFromIntermediate.pem
new file mode 100644
index 000000000..ace363638
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerFromIntermediate.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/jCCAeigAwIBAgIUfRaj/hxb3Q6v50uP5RoPLfCSeqkwCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMD0xOzA5BgNVBAMMMlRlc3QgSW52YWxpZCBEZWxl
+Z2F0ZWQgUmVzcG9uZGVyIEZyb20gSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAwXXGUmYJn3cIKmeR8bh2w39c5TiwbErNIrHL1G+m
+Wtoq3UHIwkmKxKOzwfYUh/QbaYlBvYClHDwSAkTFhKTESDMF5ROMAQbPCL6ahidg
+uuai6PNvI8XZgxO53683g0XazlHU1tzSpss8xwbrzTBw7JjM5AqlkdcpWn9xxb5m
+aR0rLf7ISURZC8Wj6kn9k7HXU0BfF3N2mZWGZiVHl+1CaQiICBFCIGmYikP+5Izm
+h4HdIramnNKDdRMfkysSjOKG+n0lHAYq0n7wFvGHzdVOgys1uJMPdLqQqovHYWck
+KrH9bWIUDRjEwLjGj8N0hFcyStfehuZVLx0eGR1xIWjTuwIDAQABoxcwFTATBgNV
+HSUEDDAKBggrBgEFBQcDCTALBgkqhkiG9w0BAQsDggEBAJqijOH0m68uOc5OkrTx
+R4TW6UKEE4FluKJj4WmS5REzWs1IBn/9JYPJEVyvCfVAiEqlxJEaY0Rie+L57Sqt
+l57QSIprq2oAqjMHgmNljA7oXumsuGtIMn3E504jCjnejpIXjrLZYcfFTEub8c/A
+FF/6Vx7w3Lz9WUdSnC99k5Iu4sa/5OnwUP4/DqchHK3+hx3pOQCgRIBB0imcucjW
+XVJnJhI2S1Dny9bNRXm3uj4wk4QgbZPHEyAbTbqSQzBCtA2oir5dODffciqVa12C
+FfMjcYYGZI7gJ9BvT5zb2GFWIKOwcEBL/4lcm/NQToNF/0FFNAThlVLp6NEEYkIj
+QbE=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerFromIntermediate.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerFromIntermediate.pem.certspec
new file mode 100644
index 000000000..be0d3e9e5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerFromIntermediate.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test Intermediate
+subject:Test Invalid Delegated Responder From Intermediate
+subjectKey:alternate
+extension:extKeyUsage:OCSPSigning
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerKeyUsageCrlSigning.pem b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerKeyUsageCrlSigning.pem
new file mode 100644
index 000000000..e3ce67d25
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerKeyUsageCrlSigning.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7jCCAdigAwIBAgIUe3gW1PDzhB2nX+14539sWNQNpuQwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowPzE9MDsGA1UEAww0VGVzdCBJbnZhbGlkIERlbGVnYXRlZCBSZXNw
+b25kZXIga2V5VXNhZ2UgY3JsU2lnbmluZzCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9RvplraKt1ByMJJ
+isSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYnYLrmoujzbyPF
+2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+ZmkdKy3+yElE
+WQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM5oeB3SK2ppzS
+g3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2FnJCqx/W1iFA0Y
+xMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMPMA0wCwYDVR0PBAQDAgEC
+MAsGCSqGSIb3DQEBCwOCAQEAO0hG0xJvxlFc9STPEUfmQezbGJt242zAUVyDT0ZS
+K/gQhhWAjjnfVdUz0dWG/RyH9eaIg4SYc+8+igmKyZL+dvhiEgc0dEWk7nCj+G9/
+SomG+QanABPo7S63HnNjSHq0Z3+j1UNFi1Nu3Neeo3yRgwBwHUVerT/iEaKX6s6V
+vYaDvPYDK3F5jxE3IUi2zwCMWssm77qOfAMoHx9DZ4Y0Hy5YeYS17mhRpUhYo8Qu
+EoEnQVt5+bwBQOsHB86zpjN/8GX9iQGrh/F+31W3qgZYhNwT0dxBgZ8+1/hymzha
+rudGgX7xhPC/qaui7LejAFoJZXz7t2s8QP4oqp/gOZ0oyA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerKeyUsageCrlSigning.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerKeyUsageCrlSigning.pem.certspec
new file mode 100644
index 000000000..2833ed9b5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerKeyUsageCrlSigning.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Test Invalid Delegated Responder keyUsage crlSigning
+subjectKey:alternate
+extension:keyUsage:cRLSign
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerNoExtKeyUsage.pem b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerNoExtKeyUsage.pem
new file mode 100644
index 000000000..3f00a11b7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerNoExtKeyUsage.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2DCCAcKgAwIBAgIUeekP5v4eDV4Q3Mhxh7hyoRYhoYMwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowOjE4MDYGA1UEAwwvVGVzdCBJbnZhbGlkIERlbGVnYXRlZCBSZXNw
+b25kZXIgTm8gZXh0S2V5VXNhZ2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDBdcZSZgmfdwgqZ5HxuHbDf1zlOLBsSs0iscvUb6Za2irdQcjCSYrEo7PB
+9hSH9BtpiUG9gKUcPBICRMWEpMRIMwXlE4wBBs8IvpqGJ2C65qLo828jxdmDE7nf
+rzeDRdrOUdTW3NKmyzzHBuvNMHDsmMzkCqWR1ylaf3HFvmZpHSst/shJRFkLxaPq
+Sf2TsddTQF8Xc3aZlYZmJUeX7UJpCIgIEUIgaZiKQ/7kjOaHgd0itqac0oN1Ex+T
+KxKM4ob6fSUcBirSfvAW8YfN1U6DKzW4kw90upCqi8dhZyQqsf1tYhQNGMTAuMaP
+w3SEVzJK196G5lUvHR4ZHXEhaNO7AgMBAAEwCwYJKoZIhvcNAQELA4IBAQBgElte
++KdSalMaq0BsyEkiYRwnsC+LlVJCHffa8RdLZ6av4/k6VFBhP/ssQZOjefG6GAB4
+bNvP/Cll878+fq9whu/3X9ZznL1TLZA1Ej7clSbiCP3TfmPmUeXu6/KMD22o/k/0
+L2cZjABi+Uctu2XxvAn9yN0+I/yulmrVUPcJJLhcMA/L3Drud+ePzjztXpn9DEuO
+zJvbT69gWuj61XshHgolczSkALsavYOs9tF9XQYClOcNrr6SiiMBYcarHyB1H+6G
+lyd+acDokI0uMuYu+25ucTf0HX8qG6K83Dr6sTCraIKnq59/zbplMsgtocklddJn
+5sWaGwVtmt1twn2c
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerNoExtKeyUsage.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerNoExtKeyUsage.pem.certspec
new file mode 100644
index 000000000..92444c94a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerNoExtKeyUsage.pem.certspec
@@ -0,0 +1,3 @@
+issuer:Test CA
+subject:Test Invalid Delegated Responder No extKeyUsage
+subjectKey:alternate
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerWrongExtKeyUsage.pem b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerWrongExtKeyUsage.pem
new file mode 100644
index 000000000..b1a665aa9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerWrongExtKeyUsage.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC9DCCAd6gAwIBAgIUaaTPCaYAcxp4TZ4q8Wcjz6W7UW0wCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowPTE7MDkGA1UEAwwyVGVzdCBJbnZhbGlkIERlbGVnYXRlZCBSZXNw
+b25kZXIgV3JvbmcgZXh0S2V5VXNhZ2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDBdcZSZgmfdwgqZ5HxuHbDf1zlOLBsSs0iscvUb6Za2irdQcjCSYrE
+o7PB9hSH9BtpiUG9gKUcPBICRMWEpMRIMwXlE4wBBs8IvpqGJ2C65qLo828jxdmD
+E7nfrzeDRdrOUdTW3NKmyzzHBuvNMHDsmMzkCqWR1ylaf3HFvmZpHSst/shJRFkL
+xaPqSf2TsddTQF8Xc3aZlYZmJUeX7UJpCIgIEUIgaZiKQ/7kjOaHgd0itqac0oN1
+Ex+TKxKM4ob6fSUcBirSfvAW8YfN1U6DKzW4kw90upCqi8dhZyQqsf1tYhQNGMTA
+uMaPw3SEVzJK196G5lUvHR4ZHXEhaNO7AgMBAAGjFzAVMBMGA1UdJQQMMAoGCCsG
+AQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAq7dWVM5N/G6AfpGNEGjK0tGgCzZdcUtt
+669gV+c45zUlmBFhoQ7P8i/491qaSH5LOOQFzkEzJ0hseylLKZraSC+dxIdc5CA1
+b53vBmjHxhba44C8eEEipG8K/7dljQGprF/0RMNlG9XLaukzVb/QeUK7hJ2EpKeB
+rq49TBH0nOirVaPO3xSSwXxNxE0X25zgAl/7Qju2mjMAXzvayN3RYTo/OhAyKXr4
+y5SVoXgQ1ZtlArHFjGCD2vcwWSXJBrJCZaVV0x3EzwKRZA7lGm4F9q0ZGCrBwmBk
+rXbL0JlESZPbMxHbE2rcQ6iI3u2mLUJ7qamLjs1Gc6YGnCOc7z2wCg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerWrongExtKeyUsage.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerWrongExtKeyUsage.pem.certspec
new file mode 100644
index 000000000..bc704fbd4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/invalidDelegatedSignerWrongExtKeyUsage.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Test Invalid Delegated Responder Wrong extKeyUsage
+subjectKey:alternate
+extension:extKeyUsage:codeSigning
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/moz.build b/security/manager/ssl/tests/unit/ocsp_certs/moz.build
new file mode 100644
index 000000000..187518829
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/moz.build
@@ -0,0 +1,42 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca-used-as-end-entity.pem',
+# 'default-ee.pem',
+# 'delegatedSHA1Signer.pem',
+# 'delegatedSigner.pem',
+# 'invalidDelegatedSignerFromIntermediate.pem',
+# 'invalidDelegatedSignerKeyUsageCrlSigning.pem',
+# 'invalidDelegatedSignerNoExtKeyUsage.pem',
+# 'invalidDelegatedSignerWrongExtKeyUsage.pem',
+# 'multi-tls-feature-bad-ee.pem',
+# 'multi-tls-feature-good-ee.pem',
+# 'must-staple-ee.pem',
+# 'must-staple-ee-with-must-staple-int.pem',
+# 'must-staple-missing-ee.pem',
+# 'ocspEEWithIntermediate.pem',
+# 'ocspOtherEndEntity.pem',
+# 'other-test-ca.pem',
+# 'rsa-1016-keysizeDelegatedSigner.pem',
+# 'test-ca.pem',
+# 'test-int.pem',
+# 'test-multi-tls-feature-int.pem',
+# 'test-must-staple-int.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
+#
+#test_keys = (
+# 'default-ee.key',
+# 'other-test-ca.key',
+# 'rsa-1016-keysizeDelegatedSigner.key',
+#)
+#
+#for test_key in test_keys:
+# GeneratedTestKey(test_key)
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-bad-ee.pem b/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-bad-ee.pem
new file mode 100644
index 000000000..3590df90b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-bad-ee.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgqgAwIBAgIUAc3BKte7ynCOlcIdQ7skOfR97WUwCwYJKoZIhvcNAQEL
+MDcxNTAzBgNVBAMMLFRlc3QgSW50ZXJtZWRpYXRlIFdpdGggTXVsdGlwbGUgVExT
+IEZlYXR1cmVzMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMCwx
+KjAoBgNVBAMMIU11bHRpIFRMUyBGZWF0dXJlIFRlc3QgRW5kLUVudGl0eTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ
+6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUk
+nAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N
+/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAG
+JMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd
+7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEA
+AaMvMC0wGAYDVR0RBBEwD4INKi5leGFtcGxlLmNvbTARBggrBgEFBQcBGAQFMAMC
+AQUwCwYJKoZIhvcNAQELA4IBAQAcse6lHIyWBVFBP3H4s35RrYiYkmcOVHundfO8
+uvLU+eKh4fFHiBMIHgBrwMH5NWC+ahAe/rc5mcT4tCh95p9TOLYf4Hl7sAAQBBVY
+eoReFpIor30mitKZ9XS/nBh2WtNCY7UN9oNdgo+MwW15OXSya0ayAZob/hdJqttR
+6+8y63CzBDe/LnUzZcHn/ecQpzjfPAjeFdFrH1ubhSgO/z/E8XOWh0BzwB8dFIw8
+cKHXAFz8vpp/OI+4ZLsfd8edXaCfJ8ysyHhJn3hq8A0KJCxRxaaw4LV+SZlq8TDH
+7Auel4lK2LVRLt9px+FoVOp2ySAHQ+ZJXVm9kGgKchFjFTpT
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-bad-ee.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-bad-ee.pem.certspec
new file mode 100644
index 000000000..3fa2793b3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-bad-ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test Intermediate With Multiple TLS Features
+subject:Multi TLS Feature Test End-Entity
+extension:subjectAlternativeName:*.example.com
+extension:TLSFeature:OCSPMustStaple
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-good-ee.pem b/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-good-ee.pem
new file mode 100644
index 000000000..9902cf34e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-good-ee.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDIzCCAg2gAwIBAgIUTUm5ul0tN4EwdDlukUalvORwf9cwCwYJKoZIhvcNAQEL
+MDcxNTAzBgNVBAMMLFRlc3QgSW50ZXJtZWRpYXRlIFdpdGggTXVsdGlwbGUgVExT
+IEZlYXR1cmVzMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMCwx
+KjAoBgNVBAMMIU11bHRpIFRMUyBGZWF0dXJlIFRlc3QgRW5kLUVudGl0eTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ
+6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUk
+nAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N
+/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAG
+JMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd
+7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEA
+AaMyMDAwGAYDVR0RBBEwD4INKi5leGFtcGxlLmNvbTAUBggrBgEFBQcBGAQIMAYC
+AQUCAQYwCwYJKoZIhvcNAQELA4IBAQAQYR5dlm5vViftK6q+RRFU+SRr9UduirxU
+Kykrf1IhrnhnGs+XSf6awTrSWvPRZgnLgGOK+X8VTjTTFNPEHDBfXgSydj5hEEk2
+aqZThJYrtObYTLIOaFsfn72mitEhojFg1mUq3TvAVNQZrh1SKKEAH6fFTyTh7MG7
+JVkt44aU0KVXlvqr6wZ+lZ/C1rvUaVVVwanyd0OodvSjNT/3o/Y3F5MxNVH1JwE/
+MgixwIqBkxHva07XmpSCD+GoF2jnBd0kTJOiDd+hVbIqkDN1/b00zI8l9Gu5JIoh
+KDDIi2rkJ3khaGjHk934j8IHdGhq281/jTelNDak1FNcKZbhtIH6
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-good-ee.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-good-ee.pem.certspec
new file mode 100644
index 000000000..7a8dd223d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/multi-tls-feature-good-ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test Intermediate With Multiple TLS Features
+subject:Multi TLS Feature Test End-Entity
+extension:subjectAlternativeName:*.example.com
+extension:TLSFeature:OCSPMustStaple,6
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee-with-must-staple-int.pem b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee-with-must-staple-int.pem
new file mode 100644
index 000000000..f11b4b0cf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee-with-must-staple-int.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBDCCAe6gAwIBAgIUI5EYmGMBogOQ/tZl8X6zfFiEEzgwCwYJKoZIhvcNAQEL
+MC0xKzApBgNVBAMMIlRlc3QgSW50ZXJtZWRpYXRlIFdpdGggTXVzdC1TdGFwbGUw
+IhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowGjEYMBYGA1UEAwwP
+VGVzdCBFbmQtZW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+uohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGoby
+a+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWC
+D/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfT
+iEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXT
+Ce+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+
+SSP6clHEMdUDrNoYCjXtjQIDAQABoy8wLTAYBgNVHREEETAPgg0qLmV4YW1wbGUu
+Y29tMBEGCCsGAQUFBwEYBAUwAwIBBTALBgkqhkiG9w0BAQsDggEBADnrurEZfGFH
+wRvnU4iAJf3JOdzUIAB2vPZh1dE7lI1/uqkdoVU7yJJ8ATfH1enD30S1mYOMJM7K
+GpWZXRPMSu8VLTmSc5e55GIGXUw/TlNQQ9XL/P1DTFU73Q/AzbxNOR4KO1UOyZAk
+EOFvYaDsMnx7WOlqKcg8ad5pi3UWqW97kAPNaGwnd6PVoeF+SZSoMgNJdNeupjYf
+izckdD0iP7kFCjlJn+NJNkiwE1WNabqgiWAJUfgH7ck5CR98+1DlGqqZP4FuyQW3
+2AGZYrKC1LZR623le9TZjHsfAWFcBFhrf+QoqRVhBsBLKWWKrRqEo2Erpj8najTe
+Q756exgcc5o=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee-with-must-staple-int.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee-with-must-staple-int.pem.certspec
new file mode 100644
index 000000000..352a60675
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee-with-must-staple-int.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test Intermediate With Must-Staple
+subject:Test End-entity
+extension:subjectAlternativeName:*.example.com
+extension:TLSFeature:OCSPMustStaple
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee.pem b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee.pem
new file mode 100644
index 000000000..9ad410a12
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6TCCAdOgAwIBAgIUV0syO5TM/Hi/n/3k2+YYxrJdoUkwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowGjEYMBYGA1UEAwwPVGVzdCBFbmQtZW50aXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoy8wLTAY
+BgNVHREEETAPgg0qLmV4YW1wbGUuY29tMBEGCCsGAQUFBwEYBAUwAwIBBTALBgkq
+hkiG9w0BAQsDggEBAIUrl9TwMdyfzqh7QH65lQ84r/+fdhYZmTAQC+Rb43aZBwCR
+WlhmJdcNSq6vIGorap0dAPC9+COLcOA6L0YcqaGxIf1fJdiCPuOR1r6Gnns2DnLi
+NkxEF8BfKi3POeGK5oEgAbvdvnZgL/GMMST9508WHMY6StjbyGZCE9nQh1dcVme1
+sJ6681Q3CnPYN6D2C/D5mJi8sgdjCPRvntHjfE8uHfvJ7r5/FjsXmY0r056QFPb6
+pi7YhaJP179c5jxQEfakz8zwu4vxkdCwyuj+WK0AjmVTp0vghiX9mHXyXvqTEQuz
+tO9XdoIyDDbG7Ki0CFkAObPBnSyf1kWaAHrjmVs=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee.pem.certspec
new file mode 100644
index 000000000..2cda40dc0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Test End-entity
+extension:subjectAlternativeName:*.example.com
+extension:TLSFeature:OCSPMustStaple
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/must-staple-missing-ee.pem b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-missing-ee.pem
new file mode 100644
index 000000000..356235d2c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-missing-ee.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8TCCAdugAwIBAgIUV9dOwBwg2FhF47/4B7qXwQrm1WowCwYJKoZIhvcNAQEL
+MC0xKzApBgNVBAMMIlRlc3QgSW50ZXJtZWRpYXRlIFdpdGggTXVzdC1TdGFwbGUw
+IhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowGjEYMBYGA1UEAwwP
+VGVzdCBFbmQtZW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+uohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGoby
+a+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWC
+D/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfT
+iEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXT
+Ce+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+
+SSP6clHEMdUDrNoYCjXtjQIDAQABoxwwGjAYBgNVHREEETAPgg0qLmV4YW1wbGUu
+Y29tMAsGCSqGSIb3DQEBCwOCAQEAswPptGhoxspv+EZLQd99afqMGGOwoHVS3Chz
+HWRXD0CA41nqI+qjr6dAHPsCETwdmV/Mt0Nrm67p/LMQFRrlI8uXLu/l5dtbh4NT
+qBK3n8j/OTzdTxUh9YsXCa+k8sOQKTLnqgNQDJmrjQZ7L1i/N5xqc9LSG32e6wqr
+6gU3IKv5jWp7lhalkDg+z3VNyvkrPzh9VVWn5IhiHLb88eIEO8XCZ+4CdPR+m+6N
+x16VoWRDo0f2wp6vkQga/ow161mjNCXCaFrTOF7oR5qk+cJ6S46YFn3lS0qrmaee
+9kTQpvhsNpso1Oat9xPaaW7VUmREO8/X5YcFUPBXnkK023s33g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/must-staple-missing-ee.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-missing-ee.pem.certspec
new file mode 100644
index 000000000..8e4a6ac0c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/must-staple-missing-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:Test Intermediate With Must-Staple
+subject:Test End-entity
+extension:subjectAlternativeName:*.example.com
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/ocspEEWithIntermediate.pem b/security/manager/ssl/tests/unit/ocsp_certs/ocspEEWithIntermediate.pem
new file mode 100644
index 000000000..af8f05578
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/ocspEEWithIntermediate.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDMTCCAhugAwIBAgIUC5PMK/apYIhhJmSJ5REzi1z8GkwwCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMCwxKjAoBgNVBAMMIVRlc3QgRW5kLWVudGl0eSB3
+aXRoIEludGVybWVkaWF0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG
+8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0V
+gg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g3
+04hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l
+0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz
+/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaNbMFkwIwYDVR0RBBwwGoIJbG9jYWxob3N0
+gg0qLmV4YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0
+cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0BAQsDggEBAKQk077vTRXtYJIB
+DlyrzAF/hGVjs1dw5DHiExEBcNs5VRqhx419dX+UBbTOGVakWWNCY3JVkuEU19yf
+W2iAAHLuwxmBs+bAJ9N2NvKg8cFH9NNtMfRc0V/9sFscOtRcws9EPHWK4KwQ/86F
+EIsm/hkAysKMOaS7+hz/Wk8zS0hTMXQaAnUTGs680gD2SflZBjD17oHpYAJ98qsu
+pUWHWRGM6aqb3nExTbwWW0KA6KV6LgpLnTuRzINLIICsShD+ILNGn3dmxL4XqlSq
+Fyt1Z/xfs/bsdYnGT8Q/6+cBVEvUNhb2dL+ASVMHVC0eLlIzB/lqNt2T1X3J4jZE
+AYgJ+oM=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/ocspEEWithIntermediate.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/ocspEEWithIntermediate.pem.certspec
new file mode 100644
index 000000000..ae3a51565
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/ocspEEWithIntermediate.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test Intermediate
+subject:Test End-entity with Intermediate
+extension:subjectAlternativeName:localhost,*.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/ocspOtherEndEntity.pem b/security/manager/ssl/tests/unit/ocsp_certs/ocspOtherEndEntity.pem
new file mode 100644
index 000000000..0e9090fec
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/ocspOtherEndEntity.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDEDCCAfqgAwIBAgIUFUjNmE1SFk2rDh8tqRDSpaELFlMwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowFTETMBEGA1UEAwwKT3RoZXIgQ2VydDCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaNbMFkwIwYDVR0R
+BBwwGoIJbG9jYWxob3N0gg0qLmV4YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYwJDAi
+BggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0BAQsD
+ggEBALNTenHEPdfs+i78r4CBw+GMnpFXBXnMp1nqVwnZfVTCz/XtWjwJr3Oxw1ws
+aaypMgtUgkiXGzpdt+OxwdZqH+Z+uaO5EU1e3VzCYvWTUVJ9HLsL0VMsy4OQCX76
+QlvGNr4wIeXu4mOIQRkxPfQHs/SYNo21brxu4oTZ3XJELLvMxKNguX/+FtkzSl/o
+jilWj9Pc6gKSiaAbgc3lowS7NvkpxCsz9wTsi/66UhqDg7/dqaQEktApAZEFO6w7
+Mhbm2FGb4d/2t24SlrtETt15MoyKd2vvySzsLcQtRRAug8w2PDqyL5i/EoJhWC5q
+MziTfNeX4JKbaasP/25bscXYqng=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/ocspOtherEndEntity.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/ocspOtherEndEntity.pem.certspec
new file mode 100644
index 000000000..5756f6ab5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/ocspOtherEndEntity.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Other Cert
+extension:subjectAlternativeName:localhost,*.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.key b/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.key
new file mode 100644
index 000000000..6db74b5c5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBdcZSZgmfdwgq
+Z5HxuHbDf1zlOLBsSs0iscvUb6Za2irdQcjCSYrEo7PB9hSH9BtpiUG9gKUcPBIC
+RMWEpMRIMwXlE4wBBs8IvpqGJ2C65qLo828jxdmDE7nfrzeDRdrOUdTW3NKmyzzH
+BuvNMHDsmMzkCqWR1ylaf3HFvmZpHSst/shJRFkLxaPqSf2TsddTQF8Xc3aZlYZm
+JUeX7UJpCIgIEUIgaZiKQ/7kjOaHgd0itqac0oN1Ex+TKxKM4ob6fSUcBirSfvAW
+8YfN1U6DKzW4kw90upCqi8dhZyQqsf1tYhQNGMTAuMaPw3SEVzJK196G5lUvHR4Z
+HXEhaNO7AgMBAAECggEAfj9tfLg572auXX3ZL/VBC7NB3BRyjTkDRXDho3B5DzDw
+aBNV//QeKtTpqdn86/vRJ736uMAK/7Hzzqcyfq1HqhYh8qwe4UygLwSzsnhgF5gL
+GBpEnQOwPmnRErg1ceVUNPASBWV10oMu1nMdznmeN8g/bVHFWrcetYAVrwXhrxXH
+R2A+9/J9A6b/BJ2Wu/hUweTlDvWwWND7CBgOCsf3vo8v8Wc9l/yeVduoOAd7v4p8
+/ylihXeFJpzZ1brStXRp5K/NM8TKLS9pnxHnyPvc1ITwjY77ijy4qXLrJL7Zcu+q
+5LtxIJPkj+lKRutimodQeMQCGposk8mnA5Dp0KVEAQKBgQDmP8clprp2klp/+MtZ
+xPVt1+yD/oW/H1PhHKyagSWLz8CugZB3sPLRR3qvho3mqOy+r3uyKxlvKprYLTKG
+8NDMKd5xnl8r6OUJtyhNWWPt02L5J4h6TEqJeZ00DVGzAax2AasnF5Ak/KrdOL9l
+Iq9j6xZGHsAqfyewb+Cd3afAoQKBgQDXGLH+n4+Z8A6DKuH73G/iqyfzTgScSYAQ
++g63CEhSGCNGCDtclsPu5VksAUpBDGuTCxZcE7XCaqMurG58klqFUcJRNPL0pyxk
+IfGacxSKDt+rpdOmiIs1y6GMAP047lqvC1RXMdcgdhu8ze50SlLKQV6Y5N4Bzf52
+TBlns+jK2wKBgAHlrKJmyUqI0i4TwrkuokcRbGV6B2gXvf0w20s6nTCVuaS2dJZH
+4vhOenhPx4OLCMhZcc96A2+jDjuRw8TQ3yePgMG26FnYRWrbE33vqp8fCsW6yakY
+T9TqJ51yLqYm8WDXiq17yDhFzLKd8RXIP2G3YiuZvUOcYJtXkKY8WVGBAoGBAIDM
+RdENJITuDRKX/Ae/gLO+/0Yeon4fOPNxeJw69mtKDt0hksIneR208cd64ka/NC8x
+hWsPVlgbWKlbETHAxTltsqjDxvOeouM2vCBa5qKgs2hp/KmMu6czzwExmm+bsmt8
+oj0wF/xVHNjaiv3Rf2+i4w00hoeYHNYjTVcekLffAoGAb3fAwfKuesFpVhzKSZxS
+vfvgTN3M29wSrsWoVpHoWUt+4pkI8w57lqpiVLgO1K7sm5k3gr38ebadjVjGiHD6
+S+G8DDUnKIxcgrtK668V7f8RBAP8eOas5qgoJ79C8M+nUeUHZRxWONuTk90j3R9r
+KVFR3kS3f+Vaew3yceGaZcA=
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.key.keyspec b/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.key.keyspec
new file mode 100644
index 000000000..cbd5f309c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.key.keyspec
@@ -0,0 +1 @@
+alternate
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.pem b/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.pem
new file mode 100644
index 000000000..09bd4bb04
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAcWgAwIBAgIUexJUIJpq50jgqOwQluhVrAzTF74wCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNTAxMDEwMDAwMDBaGA8y
+MDI1MDEwMTAwMDAwMFowGDEWMBQGA1UEAwwNT3RoZXIgdGVzdCBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
+zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
+zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
+KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
+mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
+kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMd
+MBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQCL
+jKgNGmCVYhntJo024WL8bF6hekERMYQbu/CK9moz6wlOpRMOQX1x7U/ianPW9Whi
+yoMAgAgNhLr2+t4ewqU2xRxMY0DvMSOuF9l08mptCW5sd/ocrRZuv/RcBmLcRnJm
+Y+HuaVOvf1ac32pNN5HYagGQbvvpAaHB5/DyYcywqUM7SttK1QF+AOsGePZdYUK2
+Od5wJwB7yE1Fpgf6O4vZaE0JkTVh8GQipwoPms2GYk2E1sJXu9eUrLBfioVVN0TF
+QF4xJxSwyxY8ys5E4+ftIVixVdetrcotUdYR64x9Hd5OPr5Q7VaAvd85ZvuB7xeK
+eHxNGBjaJMf1tkamLr3p
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.pem.certspec
new file mode 100644
index 000000000..3bc975aa2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/other-test-ca.pem.certspec
@@ -0,0 +1,7 @@
+issuer:Other test CA
+subject:Other test CA
+issuerKey:alternate
+subjectKey:alternate
+validity:20150101-20250101
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.key b/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.key
new file mode 100644
index 000000000..d10324fb3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICcAIBADANBgkqhkiG9w0BAQEFAASCAlowggJWAgEAAoGAANKbsS+4T93NKbOl
+GctmxDuNj4vlRbp5OEzmY+0D33WZFgDrkgeQ0lMM7OVE25mnHwWJaj7SBxZVNKqZ
+BX5HxH47yBrab6HhLjcmi1BGpVJo+drXzLSF2BouGdUNTwtoVKyvbXvmnZoIMTbh
+WvqPU8HIyE/GB3J53Q5V1zaaW90CAwEAAQJ/PEllBwvzkMJR1aLFJ3xbX9C97oXK
+1/4rJ5grsoURSlBwBANq4c+K5Usl5Ns5IVq9fpA/YYwtiy8IzGzRLbzNciBeSUW2
+s984nl5D3goUi7LITiQx/b5ZILBEuycvRez/ByG337YDl/xhOp6jXCIwBTDK6PkV
+nFNN878JEJUZAQJAD58XWXyFuAUbnGmvtV71dsmW29CQR9DM3ludYOpcZ/5PrGe+
+gD9LasWj8FD3a5ZvsU9c8QV2HlrebdlgsYO6VQJADXtjcRLOYaVRaMD5yThvsnmr
+QMug1Ukza7plJ3JjqseCYRosgdm2Nc94xAAYhZ4BjF6QBtEuPS7m80bnn6QzaQJA
+Cf1smj6m6RrjIHD5/BwhD/k1L5e+XR7rlRuzloHp3FtnKlMiIbPYkAyanZm50KTh
+AtxFDKG4ewsTid5lFsCuDQJAAUG4MkkbfdSoMwiSACTHnK5kvUR9+IO7TFZyqWur
+SLcSOzTyYyRFLNzrF/IeVw40fL4v1MLY+ZEOrCy22JW4yQJABFjdau4YyIsvm4Hx
+vDB1riDcH5lz0gck8gsGBD1hR8h4nUoHroi8gshDjIk+AXsTlH9i4LGJWKMetmSx
+nmTT4A==
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.key.keyspec b/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.key.keyspec
new file mode 100644
index 000000000..21ed73d60
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.key.keyspec
@@ -0,0 +1 @@
+rsa1016
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.pem b/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.pem
new file mode 100644
index 000000000..a6951536f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICZzCCAVGgAwIBAgIUSX19XEIdc7camdQ5y1SkxOjYv7kwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowNTEzMDEGA1UEAwwqUlNBIDEwMTYgS2V5IFNpemUgVGVzdCBEZWxl
+Z2F0ZWQgUmVzcG9uZGVyMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgADSm7Ev
+uE/dzSmzpRnLZsQ7jY+L5UW6eThM5mPtA991mRYA65IHkNJTDOzlRNuZpx8FiWo+
+0gcWVTSqmQV+R8R+O8ga2m+h4S43JotQRqVSaPna18y0hdgaLhnVDU8LaFSsr217
+5p2aCDE24Vr6j1PByMhPxgdyed0OVdc2mlvdAgMBAAGjFzAVMBMGA1UdJQQMMAoG
+CCsGAQUFBwMJMAsGCSqGSIb3DQEBCwOCAQEAIsDgLYgpTge+vmb/dIvx4F+F5fZm
+N+WmVDn+f4JMHBEOxzWp67x19WkAbvVgj661qo53XtOjjVX80gDfur2fXDdqHF8G
+v2N+bKNxKJjxn8SojcXvy2unb3A7VbKcedMvwsesBHky/WPsBK9cQjNGxv4/jRfN
+/5q7AQeUaRlN97iEU0JGjIIta6qs/FCLobg5+bhmGdsP2HRacfeCbCkjfdA0QToz
+gyOM5g1rlDxXk8mdcnesQxLMi3cka/u8JqYiMjRb3khTjIlHtOcWuTFiPO8zKd/Y
+wvJ17FlqgdSHoCCpVP7kQk245umgsJZivphQ2RWKh1X4lhLZhzFP/5+rxw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.pem.certspec
new file mode 100644
index 000000000..05f73368a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/rsa-1016-keysizeDelegatedSigner.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:RSA 1016 Key Size Test Delegated Responder
+subjectKey:rsa1016
+extension:extKeyUsage:OCSPSigning
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/test-ca.pem b/security/manager/ssl/tests/unit/ocsp_certs/test-ca.pem
new file mode 100644
index 000000000..1d50176e4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/test-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbmgAwIBAgIUH9DaznYx1NE1Cu9I8cBqxV9VgF4wCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowEjEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUw
+AwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQA1o3GayNFRlVTrsoj2
+Ag06YatbGe94M/FT0MXngjlmrMkGZqHaDlrii7Jz+JP16CBjaIZ0ZP7I56Nn/l8y
+/kfe++zvr1uwRaKjtRGBiFpCjx10rI508wzSnOox3+bOtv9qjYaY7UjkBV3F40IS
+P8qKMtNspsR4tjS/D1jbculhngkPqhskefZFQQvcgG54L5j921GFKNeeX6i9QAzV
+jjM6i/iQYpAWCuh5+CetwUnfFuZCM80npp/qHMESkT3PyPpwqT9A5K+xQdVfpXq5
+SmVy5+QGWALuSV1sfIRXRwOh+2jCWwWPbyi9TlHrvlO5mL38qikdYBDPat3ve4cq
+5viq
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/test-ca.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/test-ca.pem.certspec
new file mode 100644
index 000000000..5d2435d7b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/test-ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Test CA
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/test-int.pem b/security/manager/ssl/tests/unit/ocsp_certs/test-int.pem
new file mode 100644
index 000000000..df9ad3ddb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/test-int.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2TCCAcOgAwIBAgIUBVio/iQ21GCi2iUven8oJ/gae74wCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTAxMDEwMDAwMDBaGA8yMDI1MDEw
+MTAwMDAwMFowHDEaMBgGA1UEAwwRVGVzdCBJbnRlcm1lZGlhdGUwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq0
+7PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D
+/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuw
+JJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyX
+rZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWd
+q5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAb
+MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAry6Z
+DoUhexYUJTzWwN1ZIwWeXW/QxJR5u4DvK6pBPInDdyfv20EuxXKODYWXXPGbOY8X
+5SEsUtS+1WUlMAXenmejPvDcjeEGLS8tfJQbgHtPrDhQR43fnYGZrA2pWVmxQ+TJ
+Lrg18uGIuMcfAr3RwMzeK+uj81bybeYZN5haISWa6bF2a81vMx/WDgyFSYYBOYph
+nCPWVSqPTK/6NwbyWZORs474Flx45uzo7g9mMCmbwz9IzdJYpVrViVAFTU1gSbNQ
+ED3LzwGkS7eO8Lqzk9a94uIGqhxtGDvxFe+6Be/Il3M/5d2WC2Jmqzv8cU/u4GLb
+dKrXnD3epofIjHnOUA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/test-int.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/test-int.pem.certspec
new file mode 100644
index 000000000..33b42c2f4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/test-int.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Test Intermediate
+validity:20150101-20250101
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/test-multi-tls-feature-int.pem b/security/manager/ssl/tests/unit/ocsp_certs/test-multi-tls-feature-int.pem
new file mode 100644
index 000000000..bed4aa01f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/test-multi-tls-feature-int.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCjCCAfSgAwIBAgIUF6PsbfnmMCcksq3bK0t3nzIF7tUwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowNzE1MDMGA1UEAwwsVGVzdCBJbnRlcm1lZGlhdGUgV2l0aCBNdWx0
+aXBsZSBUTFMgRmVhdHVyZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24a
+hvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7t
+FYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+o
+N9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0d
+JdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4
+s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjMzAxMAwGA1UdEwQFMAMBAf8wCwYDVR0P
+BAQDAgEGMBQGCCsGAQUFBwEYBAgwBgIBBQIBBjALBgkqhkiG9w0BAQsDggEBACXM
+X1+QvZrthE9BrtXJMI2wNwZTzvAiGIqcqxtD9a6oTP1OAM+U7+3iANV4BT+IOS1z
+9KhPBwzdFxQTxHO7mx34T+ImN5WeIn/Hhm1RrBe67Jqvi+Pu1bHparQCoQl1OjH8
+mtSaV+VA7pciTvyU9GwMMsCyiOMElt/j8GjtbyMAQmQ9+xbyVV30kQCEZaNgzgf6
+ilNPTtVtzofi6Y4gUZ3tGYVQaDvVJRhdS64w+A2rXSDREykU114P+qY9M6TkRYI7
+KPvPIVSUz0ry3RPazPdDYbyRAqHUi1e5yxBn/Lhx8bGSrnCe4Au2PNDnU7d8rzZl
+yaBFzeN4UoHzO47kZAw=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/test-multi-tls-feature-int.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/test-multi-tls-feature-int.pem.certspec
new file mode 100644
index 000000000..3f0e925aa
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/test-multi-tls-feature-int.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Test Intermediate With Multiple TLS Features
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:TLSFeature:OCSPMustStaple,6
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/test-must-staple-int.pem b/security/manager/ssl/tests/unit/ocsp_certs/test-must-staple-int.pem
new file mode 100644
index 000000000..d00c3d101
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/test-must-staple-int.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/TCCAeegAwIBAgIUexXLwzeuuZ7h9L7rPOqB8bmBqKswCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowLTErMCkGA1UEAwwiVGVzdCBJbnRlcm1lZGlhdGUgV2l0aCBNdXN0
+LVN0YXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbW
+Qf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pk
+cQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHT
+AjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3
+ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jh
+s3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHV
+A6zaGAo17Y0CAwEAAaMwMC4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwEQYI
+KwYBBQUHARgEBTADAgEFMAsGCSqGSIb3DQEBCwOCAQEAtJc7b/hr44cTKye9RzeU
+9HJmYyrdbTxVlQ2elV07NZ1i4K6HuCs4shQ997z+ALGOsSWny6MoP+C3u91rn90b
+QO5SpVCj4wMjB7Lao8XuO47OWqcdMzCqqA51+3pCF6qq8U2jBe/lbDZYvOyTwk/9
++PuasYUaXc5Lr/cdjMqJu1bBncdZny+cBqWqUJ3H4AFRSgZ4nbgkyksrgHiUW6aE
+VzejhDcE06cn3N7cp6VyA0mh1qH7cOSWGk8ORo8hzmoY6dKIBTkncYOu2psAnfkU
+99CODDCmfQd9uwp3bBX/MPPkxXjA72SVream3ULGa7o9gpoI5A6eOollJCox49DJ
+ow==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/ocsp_certs/test-must-staple-int.pem.certspec b/security/manager/ssl/tests/unit/ocsp_certs/test-must-staple-int.pem.certspec
new file mode 100644
index 000000000..7c29aa0ad
--- /dev/null
+++ b/security/manager/ssl/tests/unit/ocsp_certs/test-must-staple-int.pem.certspec
@@ -0,0 +1,5 @@
+issuer:Test CA
+subject:Test Intermediate With Must-Staple
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:TLSFeature:OCSPMustStaple
diff --git a/security/manager/ssl/tests/unit/pkcs11testmodule/moz.build b/security/manager/ssl/tests/unit/pkcs11testmodule/moz.build
new file mode 100644
index 000000000..4935c0781
--- /dev/null
+++ b/security/manager/ssl/tests/unit/pkcs11testmodule/moz.build
@@ -0,0 +1,18 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+FINAL_TARGET = '_tests/xpcshell/security/manager/ssl/tests/unit/pkcs11testmodule'
+
+UNIFIED_SOURCES += [
+ 'pkcs11testmodule.cpp',
+]
+
+SharedLibrary('pkcs11testmodule')
+
+# C_GetFunctionList needs to be exported. As it turns out, it's much easier to
+# just export all the symbols.
+NO_VISIBILITY_FLAGS = True
+SYMBOLS_FILE = 'pkcs11testmodule.symbols'
diff --git a/security/manager/ssl/tests/unit/pkcs11testmodule/pkcs11testmodule.cpp b/security/manager/ssl/tests/unit/pkcs11testmodule/pkcs11testmodule.cpp
new file mode 100644
index 000000000..531da1308
--- /dev/null
+++ b/security/manager/ssl/tests/unit/pkcs11testmodule/pkcs11testmodule.cpp
@@ -0,0 +1,633 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This is a testing PKCS #11 module that simulates a token being inserted and
+// removed from a slot every 50ms. This is achieved mainly in
+// Test_C_WaitForSlotEvent. The smartcard monitoring code essentially calls
+// this function in a tight loop. Each time, this module waits for 50ms and
+// returns, having changed its internal state to report that the token has
+// either been inserted or removed, as appropriate.
+// This module also provides an alternate token that is always present for tests
+// that don't want the cyclic behavior described above.
+
+#include <string.h>
+
+#if defined(WIN32)
+# include <windows.h> // for Sleep
+#else
+# include <unistd.h> // for usleep
+#endif
+
+#include "pkcs11.h"
+
+CK_RV Test_C_Initialize(CK_VOID_PTR)
+{
+ return CKR_OK;
+}
+
+CK_RV Test_C_Finalize(CK_VOID_PTR)
+{
+ return CKR_OK;
+}
+
+static const CK_VERSION CryptokiVersion = { 2, 2 };
+static const CK_VERSION TestLibraryVersion = { 0, 0 };
+static const char TestLibraryDescription[] = "Test PKCS11 Library";
+static const char TestManufacturerID[] = "Test PKCS11 Manufacturer ID";
+
+/* The dest buffer is one in the CK_INFO or CK_TOKEN_INFO structs.
+ * Those buffers are padded with spaces. DestSize corresponds to the declared
+ * size for those buffers (e.g. 32 for `char foo[32]`).
+ * The src buffer is a string literal. SrcSize includes the string
+ * termination character (e.g. 4 for `const char foo[] = "foo"` */
+template <size_t DestSize, size_t SrcSize>
+void CopyString(unsigned char (&dest)[DestSize], const char (&src)[SrcSize])
+{
+ static_assert(DestSize >= SrcSize - 1, "DestSize >= SrcSize - 1");
+ memcpy(dest, src, SrcSize - 1);
+ memset(dest + SrcSize - 1, ' ', DestSize - SrcSize + 1);
+}
+
+CK_RV Test_C_GetInfo(CK_INFO_PTR pInfo)
+{
+ if (!pInfo) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ pInfo->cryptokiVersion = CryptokiVersion;
+ CopyString(pInfo->manufacturerID, TestManufacturerID);
+ pInfo->flags = 0; // must be 0
+ CopyString(pInfo->libraryDescription, TestLibraryDescription);
+ pInfo->libraryVersion = TestLibraryVersion;
+ return CKR_OK;
+}
+
+CK_RV Test_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR)
+{
+ return CKR_OK;
+}
+
+static int tokenPresent = 0;
+
+CK_RV Test_C_GetSlotList(CK_BBOOL limitToTokensPresent,
+ CK_SLOT_ID_PTR pSlotList,
+ CK_ULONG_PTR pulCount)
+{
+ if (!pulCount) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ // Slot 2 is always present, while slot 1 may or may not be present.
+ CK_ULONG slotCount = (!limitToTokensPresent || tokenPresent ? 1 : 0) + 1;
+
+ if (pSlotList) {
+ if (*pulCount < slotCount) {
+ return CKR_BUFFER_TOO_SMALL;
+ }
+ // apparently CK_SLOT_IDs are integers [1,N] because
+ // who likes counting from 0 all the time?
+ if (slotCount == 1) {
+ pSlotList[0] = 2;
+ } else {
+ pSlotList[0] = 1;
+ pSlotList[1] = 2;
+ }
+ }
+
+ *pulCount = slotCount;
+ return CKR_OK;
+}
+
+static const char TestSlotDescription[] = "Test PKCS11 Slot";
+static const char TestSlot2Description[] = "Test PKCS11 Slot 二";
+
+CK_RV Test_C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
+{
+ if (!pInfo) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ switch (slotID) {
+ case 1:
+ CopyString(pInfo->slotDescription, TestSlotDescription);
+ pInfo->flags = (tokenPresent ? CKF_TOKEN_PRESENT : 0) |
+ CKF_REMOVABLE_DEVICE;
+ break;
+ case 2:
+ CopyString(pInfo->slotDescription, TestSlot2Description);
+ pInfo->flags = CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE;
+ break;
+ default:
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ CopyString(pInfo->manufacturerID, TestManufacturerID);
+ pInfo->hardwareVersion = TestLibraryVersion;
+ pInfo->firmwareVersion = TestLibraryVersion;
+ return CKR_OK;
+}
+
+// Deliberately include énye to ensure we're handling encoding correctly.
+// The PKCS #11 base specification v2.20 specifies that strings be encoded
+// as UTF-8.
+static const char TestTokenLabel[] = "Test PKCS11 Tokeñ Label";
+static const char TestToken2Label[] = "Test PKCS11 Tokeñ 2 Label";
+static const char TestTokenModel[] = "Test Model";
+
+CK_RV Test_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
+{
+ if (!pInfo) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ switch (slotID) {
+ case 1:
+ CopyString(pInfo->label, TestTokenLabel);
+ break;
+ case 2:
+ CopyString(pInfo->label, TestToken2Label);
+ break;
+ default:
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ CopyString(pInfo->manufacturerID, TestManufacturerID);
+ CopyString(pInfo->model, TestTokenModel);
+ memset(pInfo->serialNumber, 0, sizeof(pInfo->serialNumber));
+ pInfo->flags = CKF_TOKEN_INITIALIZED;
+ pInfo->ulMaxSessionCount = 1;
+ pInfo->ulSessionCount = 0;
+ pInfo->ulMaxRwSessionCount = 1;
+ pInfo->ulRwSessionCount = 0;
+ pInfo->ulMaxPinLen = 4;
+ pInfo->ulMinPinLen = 4;
+ pInfo->ulTotalPublicMemory = 1024;
+ pInfo->ulFreePublicMemory = 1024;
+ pInfo->ulTotalPrivateMemory = 1024;
+ pInfo->ulFreePrivateMemory = 1024;
+ pInfo->hardwareVersion = TestLibraryVersion;
+ pInfo->firmwareVersion = TestLibraryVersion;
+ memset(pInfo->utcTime, 0, sizeof(pInfo->utcTime));
+ return CKR_OK;
+}
+
+CK_RV Test_C_GetMechanismList(CK_SLOT_ID,
+ CK_MECHANISM_TYPE_PTR,
+ CK_ULONG_PTR pulCount)
+{
+ if (!pulCount) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ *pulCount = 0;
+ return CKR_OK;
+}
+
+CK_RV Test_C_GetMechanismInfo(CK_SLOT_ID, CK_MECHANISM_TYPE,
+ CK_MECHANISM_INFO_PTR)
+{
+ return CKR_OK;
+}
+
+CK_RV Test_C_InitToken(CK_SLOT_ID, CK_UTF8CHAR_PTR, CK_ULONG, CK_UTF8CHAR_PTR)
+{
+ return CKR_OK;
+}
+
+CK_RV Test_C_InitPIN(CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SetPIN(CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ULONG,
+ CK_UTF8CHAR_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS, CK_VOID_PTR, CK_NOTIFY,
+ CK_SESSION_HANDLE_PTR phSession)
+{
+ switch (slotID) {
+ case 1:
+ *phSession = 1;
+ break;
+ case 2:
+ *phSession = 2;
+ break;
+ default:
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ return CKR_OK;
+}
+
+CK_RV Test_C_CloseSession(CK_SESSION_HANDLE)
+{
+ return CKR_OK;
+}
+
+CK_RV Test_C_CloseAllSessions(CK_SLOT_ID)
+{
+ return CKR_OK;
+}
+
+CK_RV Test_C_GetSessionInfo(CK_SESSION_HANDLE hSession,
+ CK_SESSION_INFO_PTR pInfo)
+{
+ if (!pInfo) {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ switch (hSession) {
+ case 1:
+ pInfo->slotID = 1;
+ break;
+ case 2:
+ pInfo->slotID = 2;
+ break;
+ default:
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ pInfo->state = CKS_RO_PUBLIC_SESSION;
+ pInfo->flags = CKF_SERIAL_SESSION;
+ return CKR_OK;
+}
+
+CK_RV Test_C_GetOperationState(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SetOperationState(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_OBJECT_HANDLE, CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_Login(CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_Logout(CK_SESSION_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_CreateObject(CK_SESSION_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG,
+ CK_OBJECT_HANDLE_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_CopyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR,
+ CK_ULONG, CK_OBJECT_HANDLE_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DestroyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_GetObjectSize(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_GetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
+ CK_ATTRIBUTE_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
+ CK_ATTRIBUTE_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_FindObjectsInit(CK_SESSION_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG)
+{
+ return CKR_OK;
+}
+
+CK_RV Test_C_FindObjects(CK_SESSION_HANDLE, CK_OBJECT_HANDLE_PTR, CK_ULONG,
+ CK_ULONG_PTR pulObjectCount)
+{
+ *pulObjectCount = 0;
+ return CKR_OK;
+}
+
+CK_RV Test_C_FindObjectsFinal(CK_SESSION_HANDLE)
+{
+ return CKR_OK;
+}
+
+CK_RV Test_C_EncryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_Encrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
+ CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_EncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_EncryptFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DecryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_Decrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
+ CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DecryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DecryptFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DigestInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_Digest(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
+ CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DigestUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DigestKey(CK_SESSION_HANDLE, CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DigestFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SignInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_Sign(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
+ CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SignUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SignFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SignRecoverInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
+ CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SignRecover(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
+ CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_VerifyInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_Verify(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
+ CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_VerifyUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_VerifyFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_VerifyRecoverInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
+ CK_OBJECT_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_VerifyRecover(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DigestEncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DecryptDigestUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SignEncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DecryptVerifyUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_GenerateKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR,
+ CK_ULONG, CK_OBJECT_HANDLE_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_GenerateKeyPair(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
+ CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR,
+ CK_ULONG, CK_OBJECT_HANDLE_PTR,
+ CK_OBJECT_HANDLE_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_WrapKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
+ CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_UnwrapKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
+ CK_BYTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG,
+ CK_OBJECT_HANDLE_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_DeriveKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
+ CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_SeedRandom(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_GenerateRandom(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_GetFunctionStatus(CK_SESSION_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_CancelFunction(CK_SESSION_HANDLE)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV Test_C_WaitForSlotEvent(CK_FLAGS, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR)
+{
+#ifdef WIN32
+ Sleep(50); // Sleep takes the duration argument as milliseconds
+#else
+ usleep(50000); // usleep takes the duration argument as microseconds
+#endif
+ *pSlot = 1;
+ tokenPresent = !tokenPresent;
+ return CKR_OK;
+}
+
+static CK_FUNCTION_LIST FunctionList = {
+ { 2, 2 },
+ Test_C_Initialize,
+ Test_C_Finalize,
+ Test_C_GetInfo,
+ Test_C_GetFunctionList,
+ Test_C_GetSlotList,
+ Test_C_GetSlotInfo,
+ Test_C_GetTokenInfo,
+ Test_C_GetMechanismList,
+ Test_C_GetMechanismInfo,
+ Test_C_InitToken,
+ Test_C_InitPIN,
+ Test_C_SetPIN,
+ Test_C_OpenSession,
+ Test_C_CloseSession,
+ Test_C_CloseAllSessions,
+ Test_C_GetSessionInfo,
+ Test_C_GetOperationState,
+ Test_C_SetOperationState,
+ Test_C_Login,
+ Test_C_Logout,
+ Test_C_CreateObject,
+ Test_C_CopyObject,
+ Test_C_DestroyObject,
+ Test_C_GetObjectSize,
+ Test_C_GetAttributeValue,
+ Test_C_SetAttributeValue,
+ Test_C_FindObjectsInit,
+ Test_C_FindObjects,
+ Test_C_FindObjectsFinal,
+ Test_C_EncryptInit,
+ Test_C_Encrypt,
+ Test_C_EncryptUpdate,
+ Test_C_EncryptFinal,
+ Test_C_DecryptInit,
+ Test_C_Decrypt,
+ Test_C_DecryptUpdate,
+ Test_C_DecryptFinal,
+ Test_C_DigestInit,
+ Test_C_Digest,
+ Test_C_DigestUpdate,
+ Test_C_DigestKey,
+ Test_C_DigestFinal,
+ Test_C_SignInit,
+ Test_C_Sign,
+ Test_C_SignUpdate,
+ Test_C_SignFinal,
+ Test_C_SignRecoverInit,
+ Test_C_SignRecover,
+ Test_C_VerifyInit,
+ Test_C_Verify,
+ Test_C_VerifyUpdate,
+ Test_C_VerifyFinal,
+ Test_C_VerifyRecoverInit,
+ Test_C_VerifyRecover,
+ Test_C_DigestEncryptUpdate,
+ Test_C_DecryptDigestUpdate,
+ Test_C_SignEncryptUpdate,
+ Test_C_DecryptVerifyUpdate,
+ Test_C_GenerateKey,
+ Test_C_GenerateKeyPair,
+ Test_C_WrapKey,
+ Test_C_UnwrapKey,
+ Test_C_DeriveKey,
+ Test_C_SeedRandom,
+ Test_C_GenerateRandom,
+ Test_C_GetFunctionStatus,
+ Test_C_CancelFunction,
+ Test_C_WaitForSlotEvent
+};
+
+CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
+{
+ *ppFunctionList = &FunctionList;
+ return CKR_OK;
+}
diff --git a/security/manager/ssl/tests/unit/pkcs11testmodule/pkcs11testmodule.symbols b/security/manager/ssl/tests/unit/pkcs11testmodule/pkcs11testmodule.symbols
new file mode 100644
index 000000000..562ecea21
--- /dev/null
+++ b/security/manager/ssl/tests/unit/pkcs11testmodule/pkcs11testmodule.symbols
@@ -0,0 +1 @@
+C_GetFunctionList
diff --git a/security/manager/ssl/tests/unit/pycert.py b/security/manager/ssl/tests/unit/pycert.py
new file mode 100755
index 000000000..9c8efa915
--- /dev/null
+++ b/security/manager/ssl/tests/unit/pycert.py
@@ -0,0 +1,697 @@
+#!/usr/bin/env python
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+Reads a certificate specification from stdin or a file and outputs a
+signed x509 certificate with the desired properties.
+
+The input format is as follows:
+
+issuer:<issuer distinguished name specification>
+subject:<subject distinguished name specification>
+[version:{1,2,3,4}]
+[validity:<YYYYMMDD-YYYYMMDD|duration in days>]
+[issuerKey:<key specification>]
+[subjectKey:<key specification>]
+[signature:{sha256WithRSAEncryption,sha1WithRSAEncryption,
+ md5WithRSAEncryption,ecdsaWithSHA256}]
+[serialNumber:<integer in the interval [1, 127]>]
+[extension:<extension name:<extension-specific data>>]
+[...]
+
+Known extensions are:
+basicConstraints:[cA],[pathLenConstraint]
+keyUsage:[digitalSignature,nonRepudiation,keyEncipherment,
+ dataEncipherment,keyAgreement,keyCertSign,cRLSign]
+extKeyUsage:[serverAuth,clientAuth,codeSigning,emailProtection
+ nsSGC, # Netscape Server Gated Crypto
+ OCSPSigning,timeStamping]
+subjectAlternativeName:[<dNSName|directoryName>,...]
+authorityInformationAccess:<OCSP URI>
+certificatePolicies:[<policy OID>,...]
+nameConstraints:{permitted,excluded}:[<dNSName|directoryName>,...]
+nsCertType:sslServer
+TLSFeature:[<TLSFeature>,...]
+
+Where:
+ [] indicates an optional field or component of a field
+ <> indicates a required component of a field
+ {} indicates a choice of exactly one value among a set of values
+ [a,b,c] indicates a list of potential values, of which zero or more
+ may be used
+
+For instance, the version field is optional. However, if it is
+specified, it must have exactly one value from the set {1,2,3,4}.
+
+Most fields have reasonable default values. By default one shared RSA
+key is used for all signatures and subject public key information
+fields. Using "issuerKey:<key specification>" or
+"subjectKey:<key specification>" causes a different key be used for
+signing or as the subject public key information field, respectively.
+See pykey.py for the list of available specifications.
+The signature algorithm is sha256WithRSAEncryption by default.
+
+The validity period may be specified as either concrete notBefore and
+notAfter values or as a validity period centered around 'now'. For the
+latter, this will result in a notBefore of 'now' - duration/2 and a
+notAfter of 'now' + duration/2.
+
+Issuer and subject distinguished name specifications are of the form
+'[stringEncoding]/C=XX/O=Example/CN=example.com'. C (country name), ST
+(state or province name), L (locality name), O (organization name), OU
+(organizational unit name), CN (common name) and emailAddress (email
+address) are currently supported. The optional stringEncoding field may
+be 'utf8String' or 'printableString'. If the given string does not
+contain a '/', it is assumed to represent a common name. If an empty
+string is provided, then an empty distinguished name is returned.
+DirectoryNames also use this format. When specifying a directoryName in
+a nameConstraints extension, the implicit form may not be used.
+
+If an extension name has '[critical]' after it, it will be marked as
+critical. Otherwise (by default), it will not be marked as critical.
+
+TLSFeature values can either consist of a named value (currently only
+'OCSPMustStaple' which corresponds to status_request) or a numeric TLS
+feature value (see rfc7633 for more information).
+
+If a serial number is not explicitly specified, it is automatically
+generated based on the contents of the certificate.
+"""
+
+from pyasn1.codec.der import decoder
+from pyasn1.codec.der import encoder
+from pyasn1.type import constraint, namedtype, tag, univ, useful
+from pyasn1_modules import rfc2459
+import base64
+import datetime
+import hashlib
+import re
+import sys
+
+import pykey
+
+# The GeneralSubtree definition in pyasn1_modules.rfc2459 is incorrect.
+# Where this definition uses a DefaultedNamedType, pyasn1_modules uses
+# a NamedType, which results in the default value being explicitly
+# encoded, which is incorrect for DER.
+class GeneralSubtree(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('base', rfc2459.GeneralName()),
+ namedtype.DefaultedNamedType('minimum', rfc2459.BaseDistance(0).subtype(
+ implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
+ namedtype.OptionalNamedType('maximum', rfc2459.BaseDistance().subtype(
+ implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
+ )
+
+
+# The NameConstraints definition in pyasn1_modules.rfc2459 is incorrect.
+# excludedSubtrees has a tag value of 1, not 0.
+class NameConstraints(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.OptionalNamedType('permittedSubtrees', rfc2459.GeneralSubtrees().subtype(
+ implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
+ namedtype.OptionalNamedType('excludedSubtrees', rfc2459.GeneralSubtrees().subtype(
+ implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1)))
+ )
+
+
+class Error(Exception):
+ """Base class for exceptions in this module."""
+ pass
+
+
+class UnknownBaseError(Error):
+ """Base class for handling unexpected input in this module."""
+ def __init__(self, value):
+ super(UnknownBaseError, self).__init__()
+ self.value = value
+ self.category = 'input'
+
+ def __str__(self):
+ return 'Unknown %s type "%s"' % (self.category, repr(self.value))
+
+
+class UnknownAlgorithmTypeError(UnknownBaseError):
+ """Helper exception type to handle unknown algorithm types."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'algorithm'
+
+
+class UnknownParameterTypeError(UnknownBaseError):
+ """Helper exception type to handle unknown input parameters."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'parameter'
+
+
+class UnknownExtensionTypeError(UnknownBaseError):
+ """Helper exception type to handle unknown input extensions."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'extension'
+
+
+class UnknownKeyPurposeTypeError(UnknownBaseError):
+ """Helper exception type to handle unknown key purposes."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'keyPurpose'
+
+
+class UnknownKeyTargetError(UnknownBaseError):
+ """Helper exception type to handle unknown key targets."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'key target'
+
+
+class UnknownVersionError(UnknownBaseError):
+ """Helper exception type to handle unknown specified versions."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'version'
+
+
+class UnknownNameConstraintsSpecificationError(UnknownBaseError):
+ """Helper exception type to handle unknown specified
+ nameConstraints."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'nameConstraints specification'
+
+
+class UnknownDNTypeError(UnknownBaseError):
+ """Helper exception type to handle unknown DN types."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'DN'
+
+
+class UnknownNSCertTypeError(UnknownBaseError):
+ """Helper exception type to handle unknown nsCertType types."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'nsCertType'
+
+
+class UnknownTLSFeature(UnknownBaseError):
+ """Helper exception type to handle unknown TLS Features."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'TLSFeature'
+
+
+class InvalidSerialNumber(Error):
+ """Exception type to handle invalid serial numbers."""
+
+ def __init__(self, value):
+ super(InvalidSerialNumber, self).__init__()
+ self.value = value
+
+ def __str__(self):
+ return repr(self.value)
+
+
+def getASN1Tag(asn1Type):
+ """Helper function for returning the base tag value of a given
+ type from the pyasn1 package"""
+ return asn1Type.baseTagSet.getBaseTag().asTuple()[2]
+
+def stringToAccessDescription(string):
+ """Helper function that takes a string representing a URI
+ presumably identifying an OCSP authority information access
+ location. Returns an AccessDescription usable by pyasn1."""
+ accessMethod = rfc2459.id_ad_ocsp
+ accessLocation = rfc2459.GeneralName()
+ accessLocation.setComponentByName('uniformResourceIdentifier', string)
+ sequence = univ.Sequence()
+ sequence.setComponentByPosition(0, accessMethod)
+ sequence.setComponentByPosition(1, accessLocation)
+ return sequence
+
+def stringToDN(string, tag=None):
+ """Takes a string representing a distinguished name or directory
+ name and returns a Name for use by pyasn1. See the documentation
+ for the issuer and subject fields for more details. Takes an
+ optional implicit tag in cases where the Name needs to be tagged
+ differently."""
+ if string and '/' not in string:
+ string = '/CN=%s' % string
+ rdns = rfc2459.RDNSequence()
+ pattern = '/(C|ST|L|O|OU|CN|emailAddress)='
+ split = re.split(pattern, string)
+ # split should now be [[encoding], <type>, <value>, <type>, <value>, ...]
+ if split[0]:
+ encoding = split[0]
+ else:
+ encoding = 'utf8String'
+ for pos, (nameType, value) in enumerate(zip(split[1::2], split[2::2])):
+ ava = rfc2459.AttributeTypeAndValue()
+ if nameType == 'C':
+ ava.setComponentByName('type', rfc2459.id_at_countryName)
+ nameComponent = rfc2459.X520countryName(value)
+ elif nameType == 'ST':
+ ava.setComponentByName('type', rfc2459.id_at_stateOrProvinceName)
+ nameComponent = rfc2459.X520StateOrProvinceName()
+ elif nameType == 'L':
+ ava.setComponentByName('type', rfc2459.id_at_localityName)
+ nameComponent = rfc2459.X520LocalityName()
+ elif nameType == 'O':
+ ava.setComponentByName('type', rfc2459.id_at_organizationName)
+ nameComponent = rfc2459.X520OrganizationName()
+ elif nameType == 'OU':
+ ava.setComponentByName('type', rfc2459.id_at_organizationalUnitName)
+ nameComponent = rfc2459.X520OrganizationalUnitName()
+ elif nameType == 'CN':
+ ava.setComponentByName('type', rfc2459.id_at_commonName)
+ nameComponent = rfc2459.X520CommonName()
+ elif nameType == 'emailAddress':
+ ava.setComponentByName('type', rfc2459.emailAddress)
+ nameComponent = rfc2459.Pkcs9email(value)
+ else:
+ raise UnknownDNTypeError(nameType)
+ if not nameType == 'C' and not nameType == 'emailAddress':
+ # The value may have things like '\0' (i.e. a slash followed by
+ # the number zero) that have to be decoded into the resulting
+ # '\x00' (i.e. a byte with value zero).
+ nameComponent.setComponentByName(encoding, value.decode(encoding='string_escape'))
+ ava.setComponentByName('value', nameComponent)
+ rdn = rfc2459.RelativeDistinguishedName()
+ rdn.setComponentByPosition(0, ava)
+ rdns.setComponentByPosition(pos, rdn)
+ if tag:
+ name = rfc2459.Name().subtype(implicitTag=tag)
+ else:
+ name = rfc2459.Name()
+ name.setComponentByPosition(0, rdns)
+ return name
+
+def stringToAlgorithmIdentifiers(string):
+ """Helper function that converts a description of an algorithm
+ to a representation usable by the pyasn1 package and a hash
+ algorithm name for use by pykey."""
+ algorithmIdentifier = rfc2459.AlgorithmIdentifier()
+ algorithmName = None
+ algorithm = None
+ if string == 'sha1WithRSAEncryption':
+ algorithmName = 'SHA-1'
+ algorithm = rfc2459.sha1WithRSAEncryption
+ elif string == 'sha256WithRSAEncryption':
+ algorithmName = 'SHA-256'
+ algorithm = univ.ObjectIdentifier('1.2.840.113549.1.1.11')
+ elif string == 'md5WithRSAEncryption':
+ algorithmName = 'MD5'
+ algorithm = rfc2459.md5WithRSAEncryption
+ elif string == 'ecdsaWithSHA256':
+ algorithmName = 'sha256'
+ algorithm = univ.ObjectIdentifier('1.2.840.10045.4.3.2')
+ else:
+ raise UnknownAlgorithmTypeError(string)
+ algorithmIdentifier.setComponentByName('algorithm', algorithm)
+ return (algorithmIdentifier, algorithmName)
+
+def datetimeToTime(dt):
+ """Takes a datetime object and returns an rfc2459.Time object with
+ that time as its value as a GeneralizedTime"""
+ time = rfc2459.Time()
+ time.setComponentByName('generalTime', useful.GeneralizedTime(dt.strftime('%Y%m%d%H%M%SZ')))
+ return time
+
+def serialBytesToString(serialBytes):
+ """Takes a list of integers in the interval [0, 255] and returns
+ the corresponding serial number string."""
+ serialBytesLen = len(serialBytes)
+ if serialBytesLen > 127:
+ raise InvalidSerialNumber("{} bytes is too long".format(serialBytesLen))
+ # Prepend the ASN.1 INTEGER tag and length bytes.
+ stringBytes = [getASN1Tag(univ.Integer), serialBytesLen] + serialBytes
+ return ''.join(chr(b) for b in stringBytes)
+
+class Certificate(object):
+ """Utility class for reading a certificate specification and
+ generating a signed x509 certificate"""
+
+ def __init__(self, paramStream):
+ self.versionValue = 2 # a value of 2 is X509v3
+ self.signature = 'sha256WithRSAEncryption'
+ self.issuer = 'Default Issuer'
+ actualNow = datetime.datetime.utcnow()
+ self.now = datetime.datetime.strptime(str(actualNow.year), '%Y')
+ aYearAndAWhile = datetime.timedelta(days=400)
+ self.notBefore = self.now - aYearAndAWhile
+ self.notAfter = self.now + aYearAndAWhile
+ self.subject = 'Default Subject'
+ self.extensions = None
+ self.subjectKey = pykey.keyFromSpecification('default')
+ self.issuerKey = pykey.keyFromSpecification('default')
+ self.serialNumber = None
+ self.decodeParams(paramStream)
+ # If a serial number wasn't specified, generate one based on
+ # the certificate contents.
+ if not self.serialNumber:
+ self.serialNumber = self.generateSerialNumber()
+
+ def generateSerialNumber(self):
+ """Generates a serial number for this certificate based on its
+ contents. Intended to be reproducible for compatibility with
+ the build system on OS X (see the comment above main, later in
+ this file)."""
+ hasher = hashlib.sha256()
+ hasher.update(str(self.versionValue))
+ hasher.update(self.signature)
+ hasher.update(self.issuer)
+ hasher.update(str(self.notBefore))
+ hasher.update(str(self.notAfter))
+ hasher.update(self.subject)
+ if self.extensions:
+ for extension in self.extensions:
+ hasher.update(str(extension))
+ serialBytes = [ord(c) for c in hasher.digest()[:20]]
+ # Ensure that the most significant bit isn't set (which would
+ # indicate a negative number, which isn't valid for serial
+ # numbers).
+ serialBytes[0] &= 0x7f
+ # Also ensure that the least significant bit on the most
+ # significant byte is set (to prevent a leading zero byte,
+ # which also wouldn't be valid).
+ serialBytes[0] |= 0x01
+ return serialBytesToString(serialBytes)
+
+ def decodeParams(self, paramStream):
+ for line in paramStream.readlines():
+ self.decodeParam(line.strip())
+
+ def decodeParam(self, line):
+ param = line.split(':')[0]
+ value = ':'.join(line.split(':')[1:])
+ if param == 'version':
+ self.setVersion(value)
+ elif param == 'subject':
+ self.subject = value
+ elif param == 'issuer':
+ self.issuer = value
+ elif param == 'validity':
+ self.decodeValidity(value)
+ elif param == 'extension':
+ self.decodeExtension(value)
+ elif param == 'issuerKey':
+ self.setupKey('issuer', value)
+ elif param == 'subjectKey':
+ self.setupKey('subject', value)
+ elif param == 'signature':
+ self.signature = value
+ elif param == 'serialNumber':
+ serialNumber = int(value)
+ # Ensure only serial numbers that conform to the rules listed in
+ # generateSerialNumber() are permitted.
+ if serialNumber < 1 or serialNumber > 127:
+ raise InvalidSerialNumber(value)
+ self.serialNumber = serialBytesToString([serialNumber])
+ else:
+ raise UnknownParameterTypeError(param)
+
+ def setVersion(self, version):
+ intVersion = int(version)
+ if intVersion >= 1 and intVersion <= 4:
+ self.versionValue = intVersion - 1
+ else:
+ raise UnknownVersionError(version)
+
+ def decodeValidity(self, duration):
+ match = re.search('([0-9]{8})-([0-9]{8})', duration)
+ if match:
+ self.notBefore = datetime.datetime.strptime(match.group(1), '%Y%m%d')
+ self.notAfter = datetime.datetime.strptime(match.group(2), '%Y%m%d')
+ else:
+ delta = datetime.timedelta(days=(int(duration) / 2))
+ self.notBefore = self.now - delta
+ self.notAfter = self.now + delta
+
+ def decodeExtension(self, extension):
+ match = re.search(r'([a-zA-Z]+)(\[critical\])?:(.*)', extension)
+ if not match:
+ raise UnknownExtensionTypeError(extension)
+ extensionType = match.group(1)
+ critical = match.group(2)
+ value = match.group(3)
+ if extensionType == 'basicConstraints':
+ self.addBasicConstraints(value, critical)
+ elif extensionType == 'keyUsage':
+ self.addKeyUsage(value, critical)
+ elif extensionType == 'extKeyUsage':
+ self.addExtKeyUsage(value, critical)
+ elif extensionType == 'subjectAlternativeName':
+ self.addSubjectAlternativeName(value, critical)
+ elif extensionType == 'authorityInformationAccess':
+ self.addAuthorityInformationAccess(value, critical)
+ elif extensionType == 'certificatePolicies':
+ self.addCertificatePolicies(value, critical)
+ elif extensionType == 'nameConstraints':
+ self.addNameConstraints(value, critical)
+ elif extensionType == 'nsCertType':
+ self.addNSCertType(value, critical)
+ elif extensionType == 'TLSFeature':
+ self.addTLSFeature(value, critical)
+ else:
+ raise UnknownExtensionTypeError(extensionType)
+
+ def setupKey(self, subjectOrIssuer, value):
+ if subjectOrIssuer == 'subject':
+ self.subjectKey = pykey.keyFromSpecification(value)
+ elif subjectOrIssuer == 'issuer':
+ self.issuerKey = pykey.keyFromSpecification(value)
+ else:
+ raise UnknownKeyTargetError(subjectOrIssuer)
+
+ def addExtension(self, extensionType, extensionValue, critical):
+ if not self.extensions:
+ self.extensions = []
+ encapsulated = univ.OctetString(encoder.encode(extensionValue))
+ extension = rfc2459.Extension()
+ extension.setComponentByName('extnID', extensionType)
+ # critical is either the string '[critical]' or None.
+ # We only care whether or not it is truthy.
+ if critical:
+ extension.setComponentByName('critical', True)
+ extension.setComponentByName('extnValue', encapsulated)
+ self.extensions.append(extension)
+
+ def addBasicConstraints(self, basicConstraints, critical):
+ cA = basicConstraints.split(',')[0]
+ pathLenConstraint = basicConstraints.split(',')[1]
+ basicConstraintsExtension = rfc2459.BasicConstraints()
+ basicConstraintsExtension.setComponentByName('cA', cA == 'cA')
+ if pathLenConstraint:
+ pathLenConstraintValue = \
+ univ.Integer(int(pathLenConstraint)).subtype(
+ subtypeSpec=constraint.ValueRangeConstraint(0, 64))
+ basicConstraintsExtension.setComponentByName('pathLenConstraint',
+ pathLenConstraintValue)
+ self.addExtension(rfc2459.id_ce_basicConstraints, basicConstraintsExtension, critical)
+
+ def addKeyUsage(self, keyUsage, critical):
+ keyUsageExtension = rfc2459.KeyUsage(keyUsage)
+ self.addExtension(rfc2459.id_ce_keyUsage, keyUsageExtension, critical)
+
+ def keyPurposeToOID(self, keyPurpose):
+ if keyPurpose == 'serverAuth':
+ # the OID for id_kp_serverAuth is incorrect in the
+ # pyasn1-modules implementation
+ return univ.ObjectIdentifier('1.3.6.1.5.5.7.3.1')
+ if keyPurpose == 'clientAuth':
+ return rfc2459.id_kp_clientAuth
+ if keyPurpose == 'codeSigning':
+ return rfc2459.id_kp_codeSigning
+ if keyPurpose == 'emailProtection':
+ return rfc2459.id_kp_emailProtection
+ if keyPurpose == 'nsSGC':
+ return univ.ObjectIdentifier('2.16.840.1.113730.4.1')
+ if keyPurpose == 'OCSPSigning':
+ return univ.ObjectIdentifier('1.3.6.1.5.5.7.3.9')
+ if keyPurpose == 'timeStamping':
+ return rfc2459.id_kp_timeStamping
+ raise UnknownKeyPurposeTypeError(keyPurpose)
+
+ def addExtKeyUsage(self, extKeyUsage, critical):
+ extKeyUsageExtension = rfc2459.ExtKeyUsageSyntax()
+ for count, keyPurpose in enumerate(extKeyUsage.split(',')):
+ extKeyUsageExtension.setComponentByPosition(count, self.keyPurposeToOID(keyPurpose))
+ self.addExtension(rfc2459.id_ce_extKeyUsage, extKeyUsageExtension, critical)
+
+ def addSubjectAlternativeName(self, names, critical):
+ subjectAlternativeName = rfc2459.SubjectAltName()
+ for count, name in enumerate(names.split(',')):
+ generalName = rfc2459.GeneralName()
+ if '/' in name:
+ directoryName = stringToDN(name,
+ tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))
+ generalName.setComponentByName('directoryName', directoryName)
+ else:
+ # The string may have things like '\0' (i.e. a slash
+ # followed by the number zero) that have to be decoded into
+ # the resulting '\x00' (i.e. a byte with value zero).
+ generalName.setComponentByName('dNSName', name.decode(encoding='string_escape'))
+ subjectAlternativeName.setComponentByPosition(count, generalName)
+ self.addExtension(rfc2459.id_ce_subjectAltName, subjectAlternativeName, critical)
+
+ def addAuthorityInformationAccess(self, ocspURI, critical):
+ sequence = univ.Sequence()
+ accessDescription = stringToAccessDescription(ocspURI)
+ sequence.setComponentByPosition(0, accessDescription)
+ self.addExtension(rfc2459.id_pe_authorityInfoAccess, sequence, critical)
+
+ def addCertificatePolicies(self, policyOIDs, critical):
+ policies = rfc2459.CertificatePolicies()
+ for pos, policyOID in enumerate(policyOIDs.split(',')):
+ if policyOID == 'any':
+ policyOID = '2.5.29.32.0'
+ policy = rfc2459.PolicyInformation()
+ policyIdentifier = rfc2459.CertPolicyId(policyOID)
+ policy.setComponentByName('policyIdentifier', policyIdentifier)
+ policies.setComponentByPosition(pos, policy)
+ self.addExtension(rfc2459.id_ce_certificatePolicies, policies, critical)
+
+ def addNameConstraints(self, constraints, critical):
+ nameConstraints = NameConstraints()
+ if constraints.startswith('permitted:'):
+ (subtreesType, subtreesTag) = ('permittedSubtrees', 0)
+ elif constraints.startswith('excluded:'):
+ (subtreesType, subtreesTag) = ('excludedSubtrees', 1)
+ else:
+ raise UnknownNameConstraintsSpecificationError(constraints)
+ generalSubtrees = rfc2459.GeneralSubtrees().subtype(
+ implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, subtreesTag))
+ subtrees = constraints[(constraints.find(':') + 1):]
+ for pos, name in enumerate(subtrees.split(',')):
+ generalName = rfc2459.GeneralName()
+ if '/' in name:
+ directoryName = stringToDN(name,
+ tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))
+ generalName.setComponentByName('directoryName', directoryName)
+ else:
+ generalName.setComponentByName('dNSName', name)
+ generalSubtree = GeneralSubtree()
+ generalSubtree.setComponentByName('base', generalName)
+ generalSubtrees.setComponentByPosition(pos, generalSubtree)
+ nameConstraints.setComponentByName(subtreesType, generalSubtrees)
+ self.addExtension(rfc2459.id_ce_nameConstraints, nameConstraints, critical)
+
+ def addNSCertType(self, certType, critical):
+ if certType != 'sslServer':
+ raise UnknownNSCertTypeError(certType)
+ self.addExtension(univ.ObjectIdentifier('2.16.840.1.113730.1.1'), univ.BitString("'01'B"),
+ critical)
+
+ def addTLSFeature(self, features, critical):
+ namedFeatures = {'OCSPMustStaple': 5}
+ featureList = [f.strip() for f in features.split(',')]
+ sequence = univ.Sequence()
+ for feature in featureList:
+ featureValue = 0
+ try:
+ featureValue = int(feature)
+ except ValueError:
+ try:
+ featureValue = namedFeatures[feature]
+ except:
+ raise UnknownTLSFeature(feature)
+ sequence.setComponentByPosition(len(sequence),
+ univ.Integer(featureValue))
+ self.addExtension(univ.ObjectIdentifier('1.3.6.1.5.5.7.1.24'), sequence,
+ critical)
+
+ def getVersion(self):
+ return rfc2459.Version(self.versionValue).subtype(
+ explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))
+
+ def getSerialNumber(self):
+ return decoder.decode(self.serialNumber)[0]
+
+ def getIssuer(self):
+ return stringToDN(self.issuer)
+
+ def getValidity(self):
+ validity = rfc2459.Validity()
+ validity.setComponentByName('notBefore', self.getNotBefore())
+ validity.setComponentByName('notAfter', self.getNotAfter())
+ return validity
+
+ def getNotBefore(self):
+ return datetimeToTime(self.notBefore)
+
+ def getNotAfter(self):
+ return datetimeToTime(self.notAfter)
+
+ def getSubject(self):
+ return stringToDN(self.subject)
+
+ def toDER(self):
+ (signatureOID, hashName) = stringToAlgorithmIdentifiers(self.signature)
+ tbsCertificate = rfc2459.TBSCertificate()
+ tbsCertificate.setComponentByName('version', self.getVersion())
+ tbsCertificate.setComponentByName('serialNumber', self.getSerialNumber())
+ tbsCertificate.setComponentByName('signature', signatureOID)
+ tbsCertificate.setComponentByName('issuer', self.getIssuer())
+ tbsCertificate.setComponentByName('validity', self.getValidity())
+ tbsCertificate.setComponentByName('subject', self.getSubject())
+ tbsCertificate.setComponentByName('subjectPublicKeyInfo',
+ self.subjectKey.asSubjectPublicKeyInfo())
+ if self.extensions:
+ extensions = rfc2459.Extensions().subtype(
+ explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))
+ for count, extension in enumerate(self.extensions):
+ extensions.setComponentByPosition(count, extension)
+ tbsCertificate.setComponentByName('extensions', extensions)
+ certificate = rfc2459.Certificate()
+ certificate.setComponentByName('tbsCertificate', tbsCertificate)
+ certificate.setComponentByName('signatureAlgorithm', signatureOID)
+ tbsDER = encoder.encode(tbsCertificate)
+ certificate.setComponentByName('signatureValue', self.issuerKey.sign(tbsDER, hashName))
+ return encoder.encode(certificate)
+
+ def toPEM(self):
+ output = '-----BEGIN CERTIFICATE-----'
+ der = self.toDER()
+ b64 = base64.b64encode(der)
+ while b64:
+ output += '\n' + b64[:64]
+ b64 = b64[64:]
+ output += '\n-----END CERTIFICATE-----'
+ return output
+
+
+# The build harness will call this function with an output
+# file-like object and a path to a file containing a
+# specification. This will read the specification and output
+# the certificate as PEM.
+# This utility tries as hard as possible to ensure that two
+# runs with the same input will have the same output. This is
+# particularly important when building on OS X, where we
+# generate everything twice for unified builds. During the
+# unification step, if any pair of input files differ, the build
+# system throws an error.
+# The one concrete failure mode is if one run happens before
+# midnight on New Year's Eve and the next run happens after
+# midnight.
+def main(output, inputPath):
+ with open(inputPath) as configStream:
+ output.write(Certificate(configStream).toPEM())
+
+# When run as a standalone program, this will read a specification from
+# stdin and output the certificate as PEM to stdout.
+if __name__ == '__main__':
+ print Certificate(sys.stdin).toPEM()
diff --git a/security/manager/ssl/tests/unit/pykey.py b/security/manager/ssl/tests/unit/pykey.py
new file mode 100755
index 000000000..d3c43deb4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/pykey.py
@@ -0,0 +1,706 @@
+#!/usr/bin/env python
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+Reads a key specification from stdin or a file and outputs a
+PKCS #8 file representing the (private) key. Also provides
+methods for signing data and representing the key as a subject
+public key info for use with pyasn1.
+
+The key specification format is as follows:
+
+default: a 2048-bit RSA key
+alternate: a different 2048-bit RSA key
+ev: a 2048-bit RSA key that, when combined with the right pycert
+ specification, results in a certificate that is enabled for
+ extended validation in debug Firefox (see ExtendedValidation.cpp).
+evRSA2040: a 2040-bit RSA key that, when combined with the right pycert
+ specification, results in a certificate that is enabled for
+ extended validation in debug Firefox.
+rsa2040: a 2040-bit RSA key
+rsa1024: a 1024-bit RSA key
+rsa1016: a 1016-bit RSA key
+secp256k1: an ECC key on the curve secp256k1
+secp244r1: an ECC key on the curve secp244r1
+secp256r1: an ECC key on the curve secp256r1
+secp384r1: an ECC key on the curve secp384r1
+secp521r1: an ECC key on the curve secp521r1
+"""
+
+from pyasn1.codec.der import encoder
+from pyasn1.type import univ, namedtype
+from pyasn1_modules import rfc2459
+from ecc import encoding
+from ecc import Key
+import base64
+import binascii
+import mock
+import rsa
+import sys
+
+def byteStringToHexifiedBitString(string):
+ """Takes a string of bytes and returns a hex string representing
+ those bytes for use with pyasn1.type.univ.BitString. It must be of
+ the form "'<hex bytes>'H", where the trailing 'H' indicates to
+ pyasn1 that the input is a hex string."""
+ return "'%s'H" % binascii.hexlify(string)
+
+class UnknownBaseError(Exception):
+ """Base class for handling unexpected input in this module."""
+ def __init__(self, value):
+ super(UnknownBaseError, self).__init__()
+ self.value = value
+ self.category = 'input'
+
+ def __str__(self):
+ return 'Unknown %s type "%s"' % (self.category, repr(self.value))
+
+
+class UnknownKeySpecificationError(UnknownBaseError):
+ """Helper exception type to handle unknown key specifications."""
+
+ def __init__(self, value):
+ UnknownBaseError.__init__(self, value)
+ self.category = 'key specification'
+
+class RSAPublicKey(univ.Sequence):
+ """Helper type for encoding an RSA public key"""
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('N', univ.Integer()),
+ namedtype.NamedType('E', univ.Integer()))
+
+
+class RSAPrivateKey(univ.Sequence):
+ """Helper type for encoding an RSA private key"""
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('version', univ.Integer()),
+ namedtype.NamedType('modulus', univ.Integer()),
+ namedtype.NamedType('publicExponent', univ.Integer()),
+ namedtype.NamedType('privateExponent', univ.Integer()),
+ namedtype.NamedType('prime1', univ.Integer()),
+ namedtype.NamedType('prime2', univ.Integer()),
+ namedtype.NamedType('exponent1', univ.Integer()),
+ namedtype.NamedType('exponent2', univ.Integer()),
+ namedtype.NamedType('coefficient', univ.Integer()),
+ )
+
+
+class ECPoint(univ.Sequence):
+ """Helper type for encoding a EC point"""
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('x', univ.Integer()),
+ namedtype.NamedType('y', univ.Integer())
+ )
+
+
+class PrivateKeyInfo(univ.Sequence):
+ """Helper type for encoding a PKCS #8 private key info"""
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('version', univ.Integer()),
+ namedtype.NamedType('privateKeyAlgorithm', rfc2459.AlgorithmIdentifier()),
+ namedtype.NamedType('privateKey', univ.OctetString())
+ )
+
+
+class RSAKey(object):
+ # For reference, when encoded as a subject public key info, the
+ # base64-encoded sha-256 hash of this key is
+ # VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=
+ sharedRSA_N = long(
+ '00ba8851a8448e16d641fd6eb6880636103d3c13d9eae4354ab4ecf56857'
+ '6c247bc1c725a8e0d81fbdb19c069b6e1a86f26be2af5a756b6a6471087a'
+ 'a55aa74587f71cd5249c027ecd43fc1e69d038202993ab20c349e4dbb94c'
+ 'c26b6c0eed15820ff17ead691ab1d3023a8b2a41eea770e00f0d8dfd660b'
+ '2bb02492a47db988617990b157903dd23bc5e0b8481fa837d38843ef2716'
+ 'd855b7665aaa7e02902f3a7b10800624cc1c6c97ad96615bb7e29612c075'
+ '31a30c91ddb4caf7fcad1d25d309efb9170ea768e1b37b2f226f69e3b48a'
+ '95611dee26d6259dab91084e36cb1c24042cbf168b2fe5f18f991731b8b3'
+ 'fe4923fa7251c431d503acda180a35ed8d', 16)
+ sharedRSA_E = 65537L
+ sharedRSA_D = long(
+ '009ecbce3861a454ecb1e0fe8f85dd43c92f5825ce2e997884d0e1a949da'
+ 'a2c5ac559b240450e5ac9fe0c3e31c0eefa6525a65f0c22194004ee1ab46'
+ '3dde9ee82287cc93e746a91929c5e6ac3d88753f6c25ba5979e73e5d8fb2'
+ '39111a3cdab8a4b0cdf5f9cab05f1233a38335c64b5560525e7e3b92ad7c'
+ '7504cf1dc7cb005788afcbe1e8f95df7402a151530d5808346864eb370aa'
+ '79956a587862cb533791307f70d91c96d22d001a69009b923c683388c9f3'
+ '6cb9b5ebe64302041c78d908206b87009cb8cabacad3dbdb2792fb911b2c'
+ 'f4db6603585be9ae0ca3b8e6417aa04b06e470ea1a3b581ca03a6781c931'
+ '5b62b30e6011f224725946eec57c6d9441', 16)
+ sharedRSA_P = long(
+ '00dd6e1d4fffebf68d889c4d114cdaaa9caa63a59374286c8a5c29a717bb'
+ 'a60375644d5caa674c4b8bc7326358646220e4550d7608ac27d55b6db74f'
+ '8d8127ef8fa09098b69147de065573447e183d22fe7d885aceb513d9581d'
+ 'd5e07c1a90f5ce0879de131371ecefc9ce72e9c43dc127d238190de81177'
+ '3ca5d19301f48c742b', 16)
+ sharedRSA_Q = long(
+ '00d7a773d9ebc380a767d2fec0934ad4e8b5667240771acdebb5ad796f47'
+ '8fec4d45985efbc9532968289c8d89102fadf21f34e2dd4940eba8c09d6d'
+ '1f16dcc29729774c43275e9251ddbe4909e1fd3bf1e4bedf46a39b8b3833'
+ '28ef4ae3b95b92f2070af26c9e7c5c9b587fedde05e8e7d86ca57886fb16'
+ '5810a77b9845bc3127', 16)
+ sharedRSA_exp1 = long(
+ '0096472b41a610c0ade1af2266c1600e3671355ba42d4b5a0eb4e9d7eb35'
+ '81400ba5dd132cdb1a5e9328c7bbc0bbb0155ea192972edf97d12751d8fc'
+ 'f6ae572a30b1ea309a8712dd4e33241db1ee455fc093f5bc9b592d756e66'
+ '21474f32c07af22fb275d340792b32ba2590bbb261aefb95a258eea53765'
+ '5315be9c24d191992d', 16)
+ sharedRSA_exp2 = long(
+ '28b450a7a75a856413b2bda6f7a63e3d964fb9ecf50e3823ef6cc8e8fa26'
+ 'ee413f8b9d1205540f12bbe7a0c76828b7ba65ad83cca4d0fe2a220114e1'
+ 'b35d03d5a85bfe2706bd50fce6cfcdd571b46ca621b8ed47d605bbe765b0'
+ 'aa4a0665ac25364da20154032e1204b8559d3e34fb5b177c9a56ff93510a'
+ '5a4a6287c151de2d', 16)
+ sharedRSA_coef = long(
+ '28067b9355801d2ef52dfa96d8adb589673cf8ee8a9c6ff72aeeabe9ef6b'
+ 'e58a4f4abf05f788947dc851fdaa34542147a71a246bfb054ee76aa346ab'
+ 'cd2692cfc9e44c51e6f069c735e073ba019f6a7214961c91b26871caeabf'
+ '8f064418a02690e39a8d5ff3067b7cdb7f50b1f53418a703966c4fc774bf'
+ '7402af6c43247f43', 16)
+
+ # For reference, when encoded as a subject public key info, the
+ # base64-encoded sha-256 hash of this key is
+ # MQj2tt1yGAfwFpWETYUCVrZxk2CD2705NKBQUlAaKJI=
+ alternateRSA_N = long(
+ '00c175c65266099f77082a6791f1b876c37f5ce538b06c4acd22b1cbd46f'
+ 'a65ada2add41c8c2498ac4a3b3c1f61487f41b698941bd80a51c3c120244'
+ 'c584a4c4483305e5138c0106cf08be9a862760bae6a2e8f36f23c5d98313'
+ 'b9dfaf378345dace51d4d6dcd2a6cb3cc706ebcd3070ec98cce40aa591d7'
+ '295a7f71c5be66691d2b2dfec84944590bc5a3ea49fd93b1d753405f1773'
+ '7699958666254797ed426908880811422069988a43fee48ce68781dd22b6'
+ 'a69cd28375131f932b128ce286fa7d251c062ad27ef016f187cdd54e832b'
+ '35b8930f74ba90aa8bc76167242ab1fd6d62140d18c4c0b8c68fc3748457'
+ '324ad7de86e6552f1d1e191d712168d3bb', 16)
+ alternateRSA_E = 65537L
+ alternateRSA_D = long(
+ '7e3f6d7cb839ef66ae5d7dd92ff5410bb341dc14728d39034570e1a37079'
+ '0f30f0681355fff41e2ad4e9a9d9fcebfbd127bdfab8c00affb1f3cea732'
+ '7ead47aa1621f2ac1ee14ca02f04b3b2786017980b181a449d03b03e69d1'
+ '12b83571e55434f012056575d2832ed6731dce799e37c83f6d51c55ab71e'
+ 'b58015af05e1af15c747603ef7f27d03a6ff049d96bbf854c1e4e50ef5b0'
+ '58d0fb08180e0ac7f7be8f2ff1673d97fc9e55dba838077bbf8a7cff2962'
+ '857785269cd9d5bad2b57469e4afcd33c4ca2d2f699f11e7c8fbdcd484f0'
+ '8d8efb8a3cb8a972eb24bed972efaae4bb712093e48fe94a46eb629a8750'
+ '78c4021a9a2c93c9a70390e9d0a54401', 16)
+ alternateRSA_P = long(
+ '00e63fc725a6ba76925a7ff8cb59c4f56dd7ec83fe85bf1f53e11cac9a81'
+ '258bcfc0ae819077b0f2d1477aaf868de6a8ecbeaf7bb22b196f2a9ad82d'
+ '3286f0d0cc29de719e5f2be8e509b7284d5963edd362f927887a4c4a8979'
+ '9d340d51b301ac7601ab27179024fcaadd38bf6522af63eb16461ec02a7f'
+ '27b06fe09ddda7c0a1', 16)
+ alternateRSA_Q = long(
+ '00d718b1fe9f8f99f00e832ae1fbdc6fe2ab27f34e049c498010fa0eb708'
+ '4852182346083b5c96c3eee5592c014a410c6b930b165c13b5c26aa32eac'
+ '6e7c925a8551c25134f2f4a72c6421f19a73148a0edfaba5d3a6888b35cb'
+ 'a18c00fd38ee5aaf0b545731d720761bbccdee744a52ca415e98e4de01cd'
+ 'fe764c1967b3e8cadb', 16)
+ alternateRSA_exp1 = long(
+ '01e5aca266c94a88d22e13c2b92ea247116c657a076817bdfd30db4b3a9d'
+ '3095b9a4b6749647e2f84e7a784fc7838b08c85971cf7a036fa30e3b91c3'
+ 'c4d0df278f80c1b6e859d8456adb137defaa9f1f0ac5bac9a9184fd4ea27'
+ '9d722ea626f160d78aad7bc83845ccb29df115c83f61b7622b99bd439c60'
+ '9b5790a63c595181', 16)
+ alternateRSA_exp2 = long(
+ '0080cc45d10d2484ee0d1297fc07bf80b3beff461ea27e1f38f371789c3a'
+ 'f66b4a0edd2192c227791db4f1c77ae246bf342f31856b0f56581b58a95b'
+ '1131c0c5396db2a8c3c6f39ea2e336bc205ae6a2a0b36869fca98cbba733'
+ 'cf01319a6f9bb26b7ca23d3017fc551cd8da8afdd17f6fa2e30d34868798'
+ '1cd6234d571e90b7df', 16)
+ alternateRSA_coef = long(
+ '6f77c0c1f2ae7ac169561cca499c52bdfbe04cddccdbdc12aec5a85691e8'
+ '594b7ee29908f30e7b96aa6254b80ed4aeec9b993782bdfc79b69d8d58c6'
+ '8870fa4be1bc0c3527288c5c82bb4aebaf15edff110403fc78e6ace6a828'
+ '27bf42f0cfa751e507651c5638db9393dd23dd1f6b295151de44b77fe55a'
+ '7b0df271e19a65c0', 16)
+
+ evRSA_N = long(
+ '00b549895c9d00108d11a1f99f87a9e3d1a5db5dfaecf188da57bf641368'
+ '8f2ce4722cff109038c17402c93a2a473dbd286aed3fdcd363cf5a291477'
+ '01bdd818d7615bf9356bd5d3c8336aaa8c0971368a06c3cd4461b93e5142'
+ '4e1744bb2eaad46aab38ce196821961f87714a1663693f09761cdf4d6ba1'
+ '25eacec7be270d388f789f6cdf78ae3144ed28c45e79293863a7a22a4898'
+ '0a36a40e72d579c9b925dff8c793362ffd6897a7c1754c5e97c967c3eadd'
+ '1aae8aa2ccce348a0169b80e28a2d70c1a960c6f335f2da09b9b643f5abf'
+ 'ba49e8aaa981e960e27d87480bdd55dd9417fa18509fbb554ccf81a4397e'
+ '8ba8128a34bdf27865c189e5734fb22905', 16)
+ evRSA_E = 65537L
+ evRSA_D = long(
+ '00983d54f94d6f4c76eb23d6f93d78523530cf73b0d16254c6e781768d45'
+ 'f55681d1d02fb2bd2aac6abc1c389860935c52a0d8f41482010394778314'
+ '1d864bff30803638a5c0152570ae9d18f3d8ca163efb475b0dddf32e7e16'
+ 'ec7565e6bb5e025c41c5c66e57a03cede554221f83045347a2c4c451c3dc'
+ 'e476b787ce0c057244be9e04ef13118dbbb3d5e0a6cc87029eafd4a69ed9'
+ 'b14759b15e39d8a9884e56f54d2f9ab013f0d15f318a9ab6b2f73d1ec3c9'
+ 'fe274ae89431a10640be7899b0011c5e5093a1834708689de100634dabde'
+ '60fbd6aaefa3a33df34a1f36f60c043036b748d1c9ee98c4031a0afec60e'
+ 'fda0a990be524f5614eac4fdb34a52f951', 16)
+ evRSA_P = long(
+ '00eadc2cb33e5ff1ca376bbd95bd6a1777d2cf4fac47545e92d11a6209b9'
+ 'd5e4ded47834581c169b3c884742a09ea187505c1ca55414d8d25b497632'
+ 'd5ec2aaa05233430fad49892777a7d68e038f561a3b8969e60b0a263defb'
+ 'fda48a9b0ff39d95bc88b15267c8ade97b5107948e41e433249d87f7db10'
+ '9d5d74584d86bcc1d7', 16)
+ evRSA_Q = long(
+ '00c59ae576a216470248d944a55b9e9bf93299da341ec56e558eba821abc'
+ 'e1bf57b79cf411d2904c774f9dba1f15185f607b0574a08205d6ec28b66a'
+ '36d634232eaaf2fea37561abaf9d644b68db38c9964cb8c96ec0ac61eba6'
+ '4d05b446542f423976f5acde4ecc95536d2df578954f93f0cfd9c58fb78b'
+ 'a2a76dd5ac284dc883', 16)
+ evRSA_exp1 = long(
+ '00c1d2ef3906331c52aca64811f9fe425beb2898322fb3db51032ce8d7e9'
+ 'fc32240be92019cf2480fcd5e329837127118b2a59a1bfe06c883e3a4447'
+ 'f3f031cd9aebd0b8d368fc79740d2cce8eadb324df7f091eafe1564361d5'
+ '4920b01b0471230e5e47d93f8ed33963c517bc4fc78f6d8b1f9eba85bcce'
+ 'db7033026508db6285', 16)
+ evRSA_exp2 = long(
+ '008521b8db5694dfbe804a315f9efc9b65275c5490acf2a3456d65e6e610'
+ 'bf9f647fc67501d4f5772f232ac70ccdef9fc2a6dfa415c7c41b6afc7af9'
+ 'd07c3ca03f7ed93c09f0b99f2c304434322f1071709bbc1baa4c91575fa6'
+ 'a959e07d4996956d95e22b57938b6e47c8d51ffedfc9bf888ce0d1a3e42b'
+ '65a89bed4b91d3e5f5', 16)
+ evRSA_coef = long(
+ '00dc497b06b920c8be0b0077b798e977eef744a90ec2c5d7e6cbb22448fa'
+ 'c72da81a33180e0d8a02e831460c7fc7fd3a612f7b9930b61b799f8e908e'
+ '632e9ba0409b6aa70b03a3ba787426263b5bd5843df8476edb5d14f6a861'
+ '3ebaf5b9cd5ca42f5fbd2802e08e4e49e5709f5151510caa5ab2c1c6eb3e'
+ 'fe9295d16e8c25c916', 16)
+
+ evRSA2040_N = long(
+ '00ca7020dc215f57914d343fae4a015111697af997a5ece91866499fc23f'
+ '1b88a118cbd30b10d91c7b9a0d4ee8972fcae56caf57f25fc1275a2a4dbc'
+ 'b982428c32ef587bf2387410330a0ffb16b8029bd783969ef675f6de38c1'
+ '8f67193cb6c072f8b23d0b3374112627a57b90055771d9e62603f53788d7'
+ 'f63afa724f5d108096df31f89f26b1eb5f7c4357980e008fcd55d827dd26'
+ '2395ca2f526a07897cc40c593b38716ebc0caa596719c6f29ac9b73a7a94'
+ '4748a3aa3e09e9eb4d461ea0027e540926614728b9d243975cf9a0541bef'
+ 'd25e76b51f951110b0e7644fc7e38441791b6d2227384cb8004e23342372'
+ 'b1cf5cc3e73e31b7bbefa160e6862ebb', 16)
+ evRSA2040_E = 65537L
+ evRSA2040_D = long(
+ '00b2db74bce92362abf72955a638ae8720ba3033bb7f971caf39188d7542'
+ 'eaa1c1abb5d205b1e2111f4791c08911a2e141e8cfd7054702d23100b564'
+ '2c06e1a31b118afd1f9a2f396cced425c501d91435ca8656766ced2b93bb'
+ 'b8669fce9bacd727d1dacb3dafabc3293e35389eef8ea0b58e1aeb1a20e6'
+ 'a61f9fcd453f7567fe31d123b616a26fef4df1d6c9f7490111d028eefd1d'
+ '972045b1a242273dd7a67ebf111db2741a5a93c7b2289cc4a236f5a99a6e'
+ 'c7a8206fdae1c1d04bdbb1980d4a298c5a17dae4186474a5f7835d882bce'
+ 'f24aef4ed6f149f94d96c9f7d78e647fc778a9017ff208d3b4a1768b1821'
+ '62102cdab032fabbab38d5200a324649', 16)
+ evRSA2040_P = long(
+ '0f3844d0d4d4d6a21acd76a6fc370b8550e1d7ec5a6234172e790f0029ae'
+ '651f6d5c59330ab19802b9d7a207de7a1fb778e3774fdbdc411750633d8d'
+ '1b3fe075006ffcfd1d10e763c7a9227d2d5f0c2dade1c9e659c350a159d3'
+ '6bb986f12636d4f9942b288bc0fe21da8799477173144249ca2e389e6c5c'
+ '25aa78c8cad7d4df', 16)
+ evRSA2040_Q = long(
+ '0d4d0bedd1962f07a1ead6b23a4ed67aeaf1270f052a6d29ba074945c636'
+ '1a5c4f8f07bf859e067aed3f4e6e323ef2aa8a6acd340b0bdc7cfe4fd329'
+ 'e3c97f870c7f7735792c6aa9d0f7e7542a28ed6f01b0e55a2b8d9c24a65c'
+ '6da314c95484f5c7c3954a81bb016b07ed17ee9b06039695bca059a79f8d'
+ 'c2423d328d5265a5', 16)
+ evRSA2040_exp1 = long(
+ '09f29a2ff05be8a96d614ba31b08935420a86c6bc42b99a6692ea0da5763'
+ 'f01e596959b7ddce73ef9c2e4f6e5b40710887500d44ba0c3cd3132cba27'
+ '475f39c2df7552e2d123a2497a4f97064028769a48a3624657f72bf539f3'
+ 'd0de234feccd3be8a0aa90c6bf6e9b0bed43070a24d061ff3ed1751a3ef2'
+ 'ff7f6b90b9dbd5fb', 16)
+ evRSA2040_exp2 = long(
+ '01a659e170cac120a03be1cf8f9df1caa353b03593bd7476e5853bd874c2'
+ '87388601c6c341ce9d1d284a5eef1a3a669d32b816a5eaecd8b7844fe070'
+ '64b9bca0c2b318d540277b3f7f1510d386bb36e03b04771e5d229e88893e'
+ '13b753bfb94518bb638e2404bd6e6a993c1668d93fc0b82ff08aaf34347d'
+ '3fe8397108c87ca5', 16)
+ evRSA2040_coef = long(
+ '040257c0d4a21c0b9843297c65652db66304fb263773d728b6abfa06d37a'
+ 'c0ca62c628023e09e37dc0a901e4ce1224180e2582a3aa4b6a1a7b98e2bd'
+ '70077aec14ac8ab66a755c71e0fc102471f9bbc1b46a95aa0b645f2c38e7'
+ '6450289619ea3f5e8ae61037bffcf8249f22aa4e76e2a01909f3feb290ce'
+ '93edf57b10ebe796', 16)
+
+ rsa2040_N = long(
+ '00bac0652fdfbc0055882ffbaeaceec88fa2d083c297dd5d40664dd3d90f'
+ '52f9aa02bd8a50fba16e0fd991878ef475f9b350d9f8e3eb2abd717ce327'
+ 'b09788531f13df8e3e4e3b9d616bb8a41e5306eed2472163161051180127'
+ '6a4eb66f07331b5cbc8bcae7016a8f9b3d4f2ac4553c624cf5263bcb348e'
+ '8840de6612870960a792191b138fb217f765cec7bff8e94f16b39419bf75'
+ '04c59a7e4f79bd6d173e9c7bf3d9d2a4e73cc180b0590a73d584fb7fc9b5'
+ '4fa544607e53fc685c7a55fd44a81d4142b6af51ea6fa6cea52965a2e8c5'
+ 'd84f3ca024d6fbb9b005b9651ce5d9f2ecf40ed404981a9ffc02636e311b'
+ '095c6332a0c87dc39271b5551481774b', 16)
+ rsa2040_E = 65537L
+ rsa2040_D = long(
+ '603db267df97555cbed86b8df355034af28f1eb7f3e7829d239bcc273a7c'
+ '7a69a10be8f21f1b6c4b02c6bae3731c3158b5bbff4605f57ab7b7b2a0cb'
+ 'a2ec005a2db5b1ea6e0aceea5bc745dcd2d0e9d6b80d7eb0ea2bc08127bc'
+ 'e35fa50c42cc411871ba591e23ba6a38484a33eff1347f907ee9a5a92a23'
+ '11bb0b435510020f78e3bb00099db4d1182928096505fcba84f3ca1238fd'
+ '1eba5eea1f391bbbcc5424b168063fc17e1ca6e1912ccba44f9d0292308a'
+ '1fedb80612529b39f59d0a3f8180b5ba201132197f93a5815ded938df8e7'
+ 'd93c9b15766588f339bb59100afda494a7e452d7dd4c9a19ce2ec3a33a18'
+ 'b20f0b4dade172bee19f26f0dcbe41', 16)
+ rsa2040_P = long(
+ '0ec3869cb92d406caddf7a319ab29448bc505a05913707873361fc5b986a'
+ '499fb65eeb815a7e37687d19f128087289d9bb8818e7bcca502c4900ad9a'
+ 'ece1179be12ff3e467d606fc820ea8f07ac9ebffe2236e38168412028822'
+ '3e42dbe68dfd972a85a6447e51695f234da7911c67c9ab9531f33df3b994'
+ '32d4ee88c9a4efbb', 16)
+ rsa2040_Q = long(
+ '0ca63934549e85feac8e0f5604303fd1849fe88af4b7f7e1213283bbc7a2'
+ 'c2a509f9273c428c68de3db93e6145f1b400bd6d4a262614e9043ad362d4'
+ 'eba4a6b995399c8934a399912199e841d8e8dbff0489f69e663796730b29'
+ '80530b31cb70695a21625ea2adccc09d930516fa872211a91e22dd89fd9e'
+ 'b7da8574b72235b1', 16)
+ rsa2040_exp1 = long(
+ '0d7d3a75e17f65f8a658a485c4095c10a4f66979e2b73bca9cf8ef21253e'
+ '1facac6d4791f58392ce8656f88f1240cc90c29653e3100c6d7a38ed44b1'
+ '63b339e5f3b6e38912126c69b3ceff2e5192426d9649b6ffca1abb75d2ba'
+ '2ed6d9a26aa383c5973d56216ff2edb90ccf887742a0f183ac92c94cf187'
+ '657645c7772d9ad7', 16)
+ rsa2040_exp2 = long(
+ '03f550194c117f24bea285b209058032f42985ff55acebe88b16df9a3752'
+ '7b4e61dc91a68dbc9a645134528ce5f248bda2893c96cb7be79ee73996c7'
+ 'c22577f6c2f790406f3472adb3b211b7e94494f32c5c6fcc0978839fe472'
+ '4c31b06318a2489567b4fca0337acb1b841227aaa5f6c74800a2306929f0'
+ '2ce038bad943df41', 16)
+ rsa2040_coef = long(
+ '080a7dbfa8c2584814c71664c56eb62ce4caf16afe88d4499159d674774a'
+ '3a3ecddf1256c02fc91525c527692422d0aba94e5c41ee12dc71bb66f867'
+ '9fa17e096f28080851ba046eb31885c1414e8985ade599d907af17453d1c'
+ 'caea2c0d06443f8367a6be154b125e390ee0d90f746f08801dd3f5367f59'
+ 'fba2e5a67c05f375', 16)
+
+ rsa1024_N = long(
+ '00d3a97440101eba8c5df9503e6f935eb52ffeb3ebe9d0dc5cace26f973c'
+ 'a94cbc0d9c31d66c0c013bce9c82d0d480328df05fb6bcd7990a5312ddae'
+ '6152ad6ee61c8c1bdd8663c68bd36224a9882ae78e89f556dfdbe6f51da6'
+ '112cbfc27c8a49336b41afdb75321b52b24a7344d1348e646351a551c757'
+ '1ccda0b8fe35f61a75', 16)
+ rsa1024_E = 65537L
+ rsa1024_D = long(
+ '5b6708e185548fc07ff062dba3792363e106ff9177d60ee3227162391024'
+ '1813f958a318f26db8b6a801646863ebbc69190d6c2f5e7723433e99666d'
+ '76b3987892cd568f1f18451e8dc05477c0607ee348380ebb7f4c98d0c036'
+ 'a0260bc67b2dab46cbaa4ce87636d839d8fddcbae2da3e02e8009a21225d'
+ 'd7e47aff2f82699d', 16)
+ rsa1024_P = long(
+ '00fcdee570323e8fc399dbfc63d8c1569546fb3cd6886c628668ab1e1d0f'
+ 'ca71058febdf76d702970ad6579d80ac2f9521075e40ef8f3f39983bd819'
+ '07e898bad3', 16)
+ rsa1024_Q = long(
+ '00d64801c955b4eb75fbae230faa8b28c9cc5e258be63747ff5ac8d2af25'
+ '3e9f6d6ce03ea2eb13ae0eb32572feb848c32ca00743635374338fedacd8'
+ 'c5885f7897', 16)
+ rsa1024_exp1 = long(
+ '76c0526d5b1b28368a75d5d42a01b9a086e20b9310241e2cd2d0b166a278'
+ 'c694ff1e9d25d9193d47789b52bb0fa194de1af0b77c09007f12afdfeef9'
+ '58d108c3', 16)
+ rsa1024_exp2 = long(
+ '008a41898d8b14217c4d782cbd15ef95d0a660f45ed09a4884f4e170367b'
+ '946d2f20398b907896890e88fe17b54bd7febe133ebc7720c86fe0649cca'
+ '7ca121e05f', 16)
+ rsa1024_coef = long(
+ '22db133445f7442ea2a0f582031ee214ff5f661972986f172651d8d6b4ec'
+ '3163e99bff1c82fe58ec3d075c6d8f26f277020edb77c3ba821b9ba3ae18'
+ 'ff8cb2cb', 16)
+
+ rsa1016_N = long(
+ '00d29bb12fb84fddcd29b3a519cb66c43b8d8f8be545ba79384ce663ed03'
+ 'df75991600eb920790d2530cece544db99a71f05896a3ed207165534aa99'
+ '057e47c47e3bc81ada6fa1e12e37268b5046a55268f9dad7ccb485d81a2e'
+ '19d50d4f0b6854acaf6d7be69d9a083136e15afa8f53c1c8c84fc6077279'
+ 'dd0e55d7369a5bdd', 16)
+ rsa1016_E = 65537L
+ rsa1016_D = long(
+ '3c4965070bf390c251d5a2c5277c5b5fd0bdee85cad7fe2b27982bb28511'
+ '4a507004036ae1cf8ae54b25e4db39215abd7e903f618c2d8b2f08cc6cd1'
+ '2dbccd72205e4945b6b3df389e5e43de0a148bb2c84e2431fdbe5920b044'
+ 'bb272f45ecff0721b7dfb60397fc613a9ea35c22300530cae8f9159c534d'
+ 'f3bf0910951901', 16)
+ rsa1016_P = long(
+ '0f9f17597c85b8051b9c69afb55ef576c996dbd09047d0ccde5b9d60ea5c'
+ '67fe4fac67be803f4b6ac5a3f050f76b966fb14f5cf105761e5ade6dd960'
+ 'b183ba55', 16)
+ rsa1016_Q = long(
+ '0d7b637112ce61a55168c0f9c9386fb279ab40cba0d549336bba65277263'
+ 'aac782611a2c81d9b635cf78c40018859e018c5e9006d12e3d2ee6f346e7'
+ '9fa43369', 16)
+ rsa1016_exp1 = long(
+ '09fd6c9a3ea6e91ae32070f9fc1c210ff9352f97be5d1eeb951bb39681e9'
+ 'dc5b672a532221b3d8900c9a9d99b9d0a4e102dc450ca1b87b0b1389de65'
+ '16c0ae0d', 16)
+ rsa1016_exp2 = long(
+ '0141b832491b7dd4a83308920024c79cae64bd447df883bb4c5672a96bab'
+ '48b7123b34f26324452cdceb17f21e570e347cbe2fd4c2d8f9910eac2cb6'
+ 'd895b8c9', 16)
+ rsa1016_coef = long(
+ '0458dd6aee18c88b2f9b81f1bc3075ae20dc1f9973d20724f20b06043d61'
+ '47c8789d4a07ae88bc82c8438c893e017b13947f62e0b18958a31eb664b1'
+ '9e64d3e0', 16)
+
+ def __init__(self, specification):
+ if specification == 'default':
+ self.RSA_N = self.sharedRSA_N
+ self.RSA_E = self.sharedRSA_E
+ self.RSA_D = self.sharedRSA_D
+ self.RSA_P = self.sharedRSA_P
+ self.RSA_Q = self.sharedRSA_Q
+ self.RSA_exp1 = self.sharedRSA_exp1
+ self.RSA_exp2 = self.sharedRSA_exp2
+ self.RSA_coef = self.sharedRSA_coef
+ elif specification == 'alternate':
+ self.RSA_N = self.alternateRSA_N
+ self.RSA_E = self.alternateRSA_E
+ self.RSA_D = self.alternateRSA_D
+ self.RSA_P = self.alternateRSA_P
+ self.RSA_Q = self.alternateRSA_Q
+ self.RSA_exp1 = self.alternateRSA_exp1
+ self.RSA_exp2 = self.alternateRSA_exp2
+ self.RSA_coef = self.alternateRSA_coef
+ elif specification == 'ev':
+ self.RSA_N = self.evRSA_N
+ self.RSA_E = self.evRSA_E
+ self.RSA_D = self.evRSA_D
+ self.RSA_P = self.evRSA_P
+ self.RSA_Q = self.evRSA_Q
+ self.RSA_exp1 = self.evRSA_exp1
+ self.RSA_exp2 = self.evRSA_exp2
+ self.RSA_coef = self.evRSA_coef
+ elif specification == 'evRSA2040':
+ self.RSA_N = self.evRSA2040_N
+ self.RSA_E = self.evRSA2040_E
+ self.RSA_D = self.evRSA2040_D
+ self.RSA_P = self.evRSA2040_P
+ self.RSA_Q = self.evRSA2040_Q
+ self.RSA_exp1 = self.evRSA2040_exp1
+ self.RSA_exp2 = self.evRSA2040_exp2
+ self.RSA_coef = self.evRSA2040_coef
+ elif specification == 'rsa2040':
+ self.RSA_N = self.rsa2040_N
+ self.RSA_E = self.rsa2040_E
+ self.RSA_D = self.rsa2040_D
+ self.RSA_P = self.rsa2040_P
+ self.RSA_Q = self.rsa2040_Q
+ self.RSA_exp1 = self.rsa2040_exp1
+ self.RSA_exp2 = self.rsa2040_exp2
+ self.RSA_coef = self.rsa2040_coef
+ elif specification == 'rsa1024':
+ self.RSA_N = self.rsa1024_N
+ self.RSA_E = self.rsa1024_E
+ self.RSA_D = self.rsa1024_D
+ self.RSA_P = self.rsa1024_P
+ self.RSA_Q = self.rsa1024_Q
+ self.RSA_exp1 = self.rsa1024_exp1
+ self.RSA_exp2 = self.rsa1024_exp2
+ self.RSA_coef = self.rsa1024_coef
+ elif specification == 'rsa1016':
+ self.RSA_N = self.rsa1016_N
+ self.RSA_E = self.rsa1016_E
+ self.RSA_D = self.rsa1016_D
+ self.RSA_P = self.rsa1016_P
+ self.RSA_Q = self.rsa1016_Q
+ self.RSA_exp1 = self.rsa1016_exp1
+ self.RSA_exp2 = self.rsa1016_exp2
+ self.RSA_coef = self.rsa1016_coef
+ else:
+ raise UnknownKeySpecificationError(specification)
+
+ def toDER(self):
+ privateKeyInfo = PrivateKeyInfo()
+ privateKeyInfo.setComponentByName('version', 0)
+ algorithmIdentifier = rfc2459.AlgorithmIdentifier()
+ algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
+ algorithmIdentifier.setComponentByName('parameters', univ.Null())
+ privateKeyInfo.setComponentByName('privateKeyAlgorithm', algorithmIdentifier)
+ rsaPrivateKey = RSAPrivateKey()
+ rsaPrivateKey.setComponentByName('version', 0)
+ rsaPrivateKey.setComponentByName('modulus', self.RSA_N)
+ rsaPrivateKey.setComponentByName('publicExponent', self.RSA_E)
+ rsaPrivateKey.setComponentByName('privateExponent', self.RSA_D)
+ rsaPrivateKey.setComponentByName('prime1', self.RSA_P)
+ rsaPrivateKey.setComponentByName('prime2', self.RSA_Q)
+ rsaPrivateKey.setComponentByName('exponent1', self.RSA_exp1)
+ rsaPrivateKey.setComponentByName('exponent2', self.RSA_exp2)
+ rsaPrivateKey.setComponentByName('coefficient', self.RSA_coef)
+ rsaPrivateKeyEncoded = encoder.encode(rsaPrivateKey)
+ privateKeyInfo.setComponentByName('privateKey', univ.OctetString(rsaPrivateKeyEncoded))
+ return encoder.encode(privateKeyInfo)
+
+ def toPEM(self):
+ output = '-----BEGIN PRIVATE KEY-----'
+ der = self.toDER()
+ b64 = base64.b64encode(der)
+ while b64:
+ output += '\n' + b64[:64]
+ b64 = b64[64:]
+ output += '\n-----END PRIVATE KEY-----'
+ return output
+
+ def asSubjectPublicKeyInfo(self):
+ """Returns a subject public key info representing
+ this key for use by pyasn1."""
+ algorithmIdentifier = rfc2459.AlgorithmIdentifier()
+ algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
+ algorithmIdentifier.setComponentByName('parameters', univ.Null())
+ spki = rfc2459.SubjectPublicKeyInfo()
+ spki.setComponentByName('algorithm', algorithmIdentifier)
+ rsaKey = RSAPublicKey()
+ rsaKey.setComponentByName('N', univ.Integer(self.RSA_N))
+ rsaKey.setComponentByName('E', univ.Integer(self.RSA_E))
+ subjectPublicKey = univ.BitString(byteStringToHexifiedBitString(encoder.encode(rsaKey)))
+ spki.setComponentByName('subjectPublicKey', subjectPublicKey)
+ return spki
+
+ def sign(self, data, hashAlgorithmName):
+ """Returns a hexified bit string representing a
+ signature by this key over the specified data.
+ Intended for use with pyasn1.type.univ.BitString"""
+ rsaPrivateKey = rsa.PrivateKey(self.RSA_N, self.RSA_E, self.RSA_D, self.RSA_P, self.RSA_Q)
+ signature = rsa.sign(data, rsaPrivateKey, hashAlgorithmName)
+ return byteStringToHexifiedBitString(signature)
+
+
+ecPublicKey = univ.ObjectIdentifier('1.2.840.10045.2.1')
+secp256k1 = univ.ObjectIdentifier('1.3.132.0.10')
+secp224r1 = univ.ObjectIdentifier('1.3.132.0.33')
+secp256r1 = univ.ObjectIdentifier('1.2.840.10045.3.1.7')
+secp384r1 = univ.ObjectIdentifier('1.3.132.0.34')
+secp521r1 = univ.ObjectIdentifier('1.3.132.0.35')
+
+# ecc.curves.DOMAINS uses a 5-tuple to define curves.
+# The first number is p where F_p is the finite field of the curve.
+# The second number is the order n of the base point G.
+# The third number is the parameter b of the definition of the curve
+# E: y^2 = x^3 + ax + b (a in this case is 0)
+# The fourth and fifth numbers constitute the base point G.
+secp256k1Params = (long('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16),
+ long('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16),
+ 7,
+ long('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16),
+ long('483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', 16))
+
+def longToEvenLengthHexString(val):
+ h = format(val, 'x')
+ if not len(h) % 2 == 0:
+ h = '0' + h
+ return h
+
+def notRandom(n):
+ return n * '\x04'
+
+class ECCKey(object):
+ secp256k1Encoded = str('08fd87b04fba98090100004035ee7c7289d8fef7a8'
+ '6afe5da66d8bc2ebb6a8543fd2fead089f45ce7acd0fa64382a9500c41dad'
+ '770ffd4b511bf4b492eb1238800c32c4f76c73a3f3294e7c5002067cebc20'
+ '8a5fa3df16ec2bb34acc59a42ab4abb0538575ca99b92b6a2149a04f')
+
+ secp224r1Encoded = str('0ee5587c4d18526f00e00038668d72cca6fd6a1b35'
+ '57b5366104d84408ecb637f08e8c86bbff82cc00e88f0066d7af63c3298ba'
+ '377348a1202b03b37fd6b1ff415aa311e001c04389459926c3296c242b83e'
+ '10a6cd2011c8fe2dae1b772ea5b21067')
+
+ secp256r1Encoded = str('cb872ac99cd31827010000404fbfbbbb61e0f8f9b1'
+ 'a60a59ac8704e2ec050b423e3cf72e923f2c4f794b455c2a69d233456c36c'
+ '4119d0706e00eedc8d19390d7991b7b2d07a304eaa04aa6c000202191403d'
+ '5710bf15a265818cd42ed6fedf09add92d78b18e7a1e9feb95524702')
+
+ secp384r1Encoded = str('d3103f5ac81741e801800060a1687243362b5c7b18'
+ '89f379154615a1c73fb48dee863e022915db608e252de4b7132da8ce98e83'
+ '1534e6a9c0c0b09c8d639ade83206e5ba813473a11fa330e05da8c96e4383'
+ 'fe27873da97103be2888cff002f05af71a1fddcc8374aa6ea9ce0030035c7'
+ 'a1b10d9fafe837b64ad92f22f5ced0789186538669b5c6d872cec3d926122'
+ 'b393772b57602ff31365efe1393246')
+
+ secp521r1Encoded = str('77f4b0ac81948ddc02090084014cdc9cacc4794109'
+ '6bc9cc66752ec27f597734fa66c62b792f88c519d6d37f0d16ea1c483a182'
+ '7a010b9128e3a08070ca33ef5f57835b7c1ba251f6cc3521dc42b01065345'
+ '1981b445d343eed3782a35d6cff0ff484f5a883d209f1b9042b726703568b'
+ '2f326e18b833bdd8aa0734392bcd19501e10d698a79f53e11e0a22bdd2aad'
+ '900042014f3284fa698dd9fe1118dd331851cdfaac5a3829278eb8994839d'
+ 'e9471c940b858c69d2d05e8c01788a7d0b6e235aa5e783fc1bee807dcc386'
+ '5f920e12cf8f2d29')
+
+ def __init__(self, specification=None):
+ if specification == 'secp256k1':
+ self.key = Key.Key.decode(binascii.unhexlify(self.secp256k1Encoded))
+ self.keyOID = secp256k1
+ elif specification == 'secp224r1':
+ self.key = Key.Key.decode(binascii.unhexlify(self.secp224r1Encoded))
+ self.keyOID = secp224r1
+ elif specification == 'secp256r1':
+ self.key = Key.Key.decode(binascii.unhexlify(self.secp256r1Encoded))
+ self.keyOID = secp256r1
+ elif specification == 'secp384r1':
+ self.key = Key.Key.decode(binascii.unhexlify(self.secp384r1Encoded))
+ self.keyOID = secp384r1
+ elif specification == 'secp521r1':
+ self.key = Key.Key.decode(binascii.unhexlify(self.secp521r1Encoded))
+ self.keyOID = secp521r1
+ else:
+ raise UnknownKeySpecificationError(specification)
+
+ def asSubjectPublicKeyInfo(self):
+ """Returns a subject public key info representing
+ this key for use by pyasn1."""
+ algorithmIdentifier = rfc2459.AlgorithmIdentifier()
+ algorithmIdentifier.setComponentByName('algorithm', ecPublicKey)
+ algorithmIdentifier.setComponentByName('parameters', self.keyOID)
+ spki = rfc2459.SubjectPublicKeyInfo()
+ spki.setComponentByName('algorithm', algorithmIdentifier)
+ # We need to extract the point that represents this key.
+ # The library encoding of the key is an 8-byte id, followed by 2
+ # bytes for the key length in bits, followed by the point on the
+ # curve (represented by two python longs). There appear to also
+ # be 2 bytes indicating the length of the point as encoded, but
+ # Decoder takes care of that.
+ encoded = self.key.encode()
+ _, _, points = encoding.Decoder(encoded).int(8).int(2).point(2).out()
+ # '04' indicates that the points are in uncompressed form.
+ hexifiedBitString = "'%s%s%s'H" % ('04', longToEvenLengthHexString(points[0]),
+ longToEvenLengthHexString(points[1]))
+ subjectPublicKey = univ.BitString(hexifiedBitString)
+ spki.setComponentByName('subjectPublicKey', subjectPublicKey)
+ return spki
+
+ def sign(self, data, hashAlgorithmName):
+ """Returns a hexified bit string representing a
+ signature by this key over the specified data.
+ Intended for use with pyasn1.type.univ.BitString"""
+ # There is some non-determinism in ECDSA signatures. Work around
+ # this by patching ecc.ecdsa.urandom to not be random.
+ with mock.patch('ecc.ecdsa.urandom', side_effect=notRandom):
+ # For some reason Key.sign returns an encoded point.
+ # Decode it so we can encode it as a BITSTRING consisting
+ # of a SEQUENCE of two INTEGERs.
+ # Also patch in secp256k1 if applicable.
+ if self.keyOID == secp256k1:
+ with mock.patch('ecc.curves.DOMAINS', {256: secp256k1Params}):
+ x, y = encoding.dec_point(self.key.sign(data, hashAlgorithmName))
+ else:
+ x, y = encoding.dec_point(self.key.sign(data, hashAlgorithmName))
+ point = ECPoint()
+ point.setComponentByName('x', x)
+ point.setComponentByName('y', y)
+ return byteStringToHexifiedBitString(encoder.encode(point))
+
+
+def keyFromSpecification(specification):
+ """Pass in a specification, get the appropriate key back."""
+ if specification.startswith('secp'):
+ return ECCKey(specification)
+ else:
+ return RSAKey(specification)
+
+# The build harness will call this function with an output file-like
+# object and a path to a file containing a specification. This will
+# read the specification and output the key as ASCII-encoded PKCS #8.
+def main(output, inputPath):
+ with open(inputPath) as configStream:
+ output.write(keyFromSpecification(configStream.read().strip()).toPEM())
+
+# When run as a standalone program, this will read a specification from
+# stdin and output the certificate as PEM to stdout.
+if __name__ == '__main__':
+ print keyFromSpecification(sys.stdin.read()).toPEM()
diff --git a/security/manager/ssl/tests/unit/sss_readstate_child_worker.js b/security/manager/ssl/tests/unit/sss_readstate_child_worker.js
new file mode 100644
index 000000000..166ab9ed3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/sss_readstate_child_worker.js
@@ -0,0 +1,25 @@
+/* import-globals-from head_psm.js */
+"use strict";
+
+function run_test() {
+ let SSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "expired.example.com", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "notexpired.example.com", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.includesubdomains.preloaded.test", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "incsubdomain.example.com", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.incsubdomain.example.com", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains2.preloaded.test", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.includesubdomains2.preloaded.test", 0));
+ do_test_finished();
+}
diff --git a/security/manager/ssl/tests/unit/test_add_preexisting_cert.js b/security/manager/ssl/tests/unit/test_add_preexisting_cert.js
new file mode 100644
index 000000000..2b07828c8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_add_preexisting_cert.js
@@ -0,0 +1,45 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// Tests that adding a certificate already present in the certificate database
+// with different trust bits than those stored in the database does not result
+// in the new trust bits being ignored.
+
+do_get_profile();
+var certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function load_cert(cert, trust) {
+ let file = "test_intermediate_basic_usage_constraints/" + cert + ".pem";
+ addCertFromFile(certDB, file, trust);
+}
+
+function getDERString(cert) {
+ let derString = "";
+ for (let rawByte of cert.getRawDER({})) {
+ derString += String.fromCharCode(rawByte);
+ }
+ return derString;
+}
+
+function run_test() {
+ load_cert("ca", "CTu,CTu,CTu");
+ load_cert("int-limited-depth", "CTu,CTu,CTu");
+ let file = "test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem";
+ let cert_pem = readFile(do_get_file(file));
+ let ee = certDB.constructX509FromBase64(pemToBase64(cert_pem));
+ checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
+ certificateUsageSSLServer);
+ // Change the already existing intermediate certificate's trust using
+ // addCertFromBase64(). We use findCertByNickname first to ensure that the
+ // certificate already exists.
+ let int_cert = certDB.findCertByNickname("int-limited-depth");
+ notEqual(int_cert, null, "Intermediate cert should be in the cert DB");
+ let base64_cert = btoa(getDERString(int_cert));
+ certDB.addCertFromBase64(base64_cert, "p,p,p", "ignored_argument");
+ checkCertErrorGeneric(certDB, ee, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageSSLServer);
+}
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem b/security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem
new file mode 100644
index 000000000..1a18e2bf0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUL5zykZEc2ro5d6th43aWGfm735cwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
+DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHPYBjNnv//Ssc8Elepb8SWIXRdahKbL
+/dcPoMR+7yhJVaelUaxdwUytJWJAGdkkuv+P+G4b82RVYEXT+9k1S/aAfByFyR9q
+vS7POfdy/ZPfGTXltlnmYX/84a6QeYQa4Nl4JpIOXBCesLxmErBhczka6D26iqsz
+GeseKRSjVPgF3mXc2CRGZnTDRhUmd7wOABLmj7GtuFvOm96363M3IUByMohvoj1G
+dic3s5D0seXwTKnEc5B27lJt7Q0oIXEldL+UW8Mo1hfGWQeXzqTZbpOVLnVWvHBH
+H8yYs5hyH01qFJZbztJ1JJ3F2NpYLlr4P5I6fW2e9w5MG/VMQRU3wzQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem.certspec b/security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem.certspec
new file mode 100644
index 000000000..6660f5d47
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/moz.build b/security/manager/ssl/tests/unit/test_baseline_requirements/moz.build
new file mode 100644
index 000000000..b911380a4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/moz.build
@@ -0,0 +1,19 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca.pem',
+# 'no-san-old.pem',
+# 'no-san-older.pem',
+# 'no-san-recent.pem',
+# 'san-contains-no-hostnames-old.pem',
+# 'san-contains-no-hostnames-older.pem',
+# 'san-contains-no-hostnames-recent.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-old.pem b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-old.pem
new file mode 100644
index 000000000..4a0032f43
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-old.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUS00fexo4Y4FagP1oiKQiGCJKd/swCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTYwNzI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEAnooFCIG4D5EQxpe6EcB3gXE2Cj5kMBvO5H+OobaVRd4kIxET+MChwsN2nuwy
+xooA/P2M+9W/S3KP/K8L1tlyf/8J2xlr349MhULhCKG7XxpEQZl6sVjaeDLwWrEK
+2Ts1jPgCTufdfPYBcO3rb4HSdHNfFlhB98dfgSakXqXzUZ9sz2VxmAeL6tLvspG9
+tH5viWFc+lv1J3/Jtzk79hleDsiIdcjTjC/bM/Y49jkNOBxru4Qrw5AZuveoVy/G
+2axz89wBpjLYjI0KtVxCf8dutcVW7UwFKQywmo7QDqha61f0f8I6oCYXsDPK9FPf
+WLIrK1TT3YxdhN7QIRu6J8ttBQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-old.pem.certspec b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-old.pem.certspec
new file mode 100644
index 000000000..7a34d0758
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-old.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:example.com
+validity:20160724-20160924
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-older.pem b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-older.pem
new file mode 100644
index 000000000..370cafc8f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-older.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUZ3gdKZRvWFYArMRStT2zAGE6JDQwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUwNzI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEAn81HiHxHv7Mhq16XWoD6ttEu9sllOHssw452wRdIieM2XcMIi5DPI81XDhqk
+5Zw/pUDfWxNFLq92JM2UArF7RtWICBYqi4UJcdnrMb84rwOVdgt9sDQYdamqj5qF
+90XpTOIA+ZyfAMXxJpJTEC9WN1rc3cK6Epv0+7KqE6FBa5aH8uAYXAb/+eKmtwY/
+ELQWT2jsoplihEw8aJsXTR9M9y2UudxPhqgA7lPpstbOMNuw2xg8oWBnqgZGRGvH
+7Afu2CoxEmYbxXnO6cJ30/pAuVLnVpmJg1n7DLT8is+2fUiOMyuve7KAjxuAo3KT
+XEiTdgDBOOO+gIY532x/jErbRA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-older.pem.certspec b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-older.pem.certspec
new file mode 100644
index 000000000..aa682a7af
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-older.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:example.com
+validity:20150724-20160924
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-recent.pem b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-recent.pem
new file mode 100644
index 000000000..f901f613b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-recent.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUWxGwhSb8roUQoLNpJajl0X8jk10wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTYwODI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEADs0POeb1wJthEcg1nRYRcPgcNHsV1yVCkHMyfmssA1rgWXsp93PRVaCyZYgI
+Dq+8QJtAYpdcChFcEYeGjcjLv49Dh+yiiZPPbRWKJB0y3v+13A74M1q+IQFoQWAh
+L5GzAEjApsB1j/csRfDNjIwcP1WApN1iZ2NPxFU+PAIFhcmm+uD2doDtQfpMN9vi
+HEg5H1x7JOufOZlN+zbnPK+Ob7N13pFd/P/IO8XhA/X8by4G45oh0deyELf9zVcW
+4flslHPYthp4LDEyPvTP52jHn/yTO/m8cxKmCZOuwiw4DWfSVUy6irUs8W5SlfS8
+gI2Ctb+G5YvSffsPYwkUg3Hg7g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-recent.pem.certspec b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-recent.pem.certspec
new file mode 100644
index 000000000..e38478165
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/no-san-recent.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:example.com
+validity:20160824-20160924
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-old.pem b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-old.pem
new file mode 100644
index 000000000..2d6821a7c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-old.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4TCCAcugAwIBAgIUL/Gibj3iILbh9idTh3u9XTSwzqIwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTYwNzI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozAwLjAsBgNVHREEJTAj
+pCEwHzEdMBsGA1UECgwURXhhbXBsZSBPcmdhbml6YXRpb24wCwYJKoZIhvcNAQEL
+A4IBAQAtCjzHSdXdAyaC5Qyw77gFwQKECHDAimgze1Nvgkyiv4LJLSuFZ84jnLIL
+PM+iRxrxeBOdNy8PNIaDadFb5NoovmdLTG08ZjNjJoXOt5JufIHQrUzrcZy1aP7z
+rWXED1QcwyKkoOAOqr5hOZ3pmu67a1vJgjZ8H4dVhfFkmSVGPG/6mTvn9H4N/AEo
+K+M7BW1WMnNexsV5mMvlUUdfZP0J3o9oI9msH6uH92xU6jIHpgcm6plXfpOBGQfB
+g6EUGD4znDe24ljbaohFATWw5c09kkOQNg/H6DQpb1Vi6k+X62Zgj5UR79zx53e+
+3Wo3Iu+hJUfNwyNk7KVF+r1wsUdA
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-old.pem.certspec b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-old.pem.certspec
new file mode 100644
index 000000000..41817bde7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-old.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:example.com
+validity:20160724-20160924
+extension:subjectAlternativeName:/O=Example Organization
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-older.pem b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-older.pem
new file mode 100644
index 000000000..0465f5da5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-older.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4TCCAcugAwIBAgIUTePOoF7EmrE46xg5zgyv8RLxEhYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUwNzI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozAwLjAsBgNVHREEJTAj
+pCEwHzEdMBsGA1UECgwURXhhbXBsZSBPcmdhbml6YXRpb24wCwYJKoZIhvcNAQEL
+A4IBAQCdicLQK5tTHkNs58IySxDedV+BqQYxvNZN3cfrqzFdehS4OzVe8hQkwKhJ
+5PpOfkh86KxoBActVL8AtP+mIBZ765qEFPhGEFMfEhqattsO6BluMNTB7ZP8HeDm
+/oCI7Ae5u+Yr5IvjBNSv5fpY7sfDiM4oqXBolJYkR+YTu+GSKYhLZTtiHhG1/Jgw
+yzBzWkfYxIW7EOe2t99krNWpPaf1MyUXO3Pj/7qfURMDeocaAvPGw7tqCZ0nsbOe
+rJvNVZDMaPbOVQKsSSyIrEDfBlQViG10eQIUaURuAY4hJs6AoLvS5b3EaxAQAWtJ
+okbLuSVbj7giOF84hkcFM3hE1FTs
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-older.pem.certspec b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-older.pem.certspec
new file mode 100644
index 000000000..65acf0b02
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-older.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:example.com
+validity:20150724-20160924
+extension:subjectAlternativeName:/O=Example Organization
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-recent.pem b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-recent.pem
new file mode 100644
index 000000000..fc8b5b48a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-recent.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4TCCAcugAwIBAgIUUwz+d++GVy8L6Lxi9GVnzG6yUCEwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTYwODI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozAwLjAsBgNVHREEJTAj
+pCEwHzEdMBsGA1UECgwURXhhbXBsZSBPcmdhbml6YXRpb24wCwYJKoZIhvcNAQEL
+A4IBAQCdKXA+1XhcpKdyjeJjEEUm9ptoS8tKJt/vdGUPCByzlD71OJGsiXorTcGY
+V2sgbGCmxA8dnxG8bPQMFdAZ2hRjWjZ/Hs18SDbMAONjzgiPlwUWRZldb2Th7WX3
+7a+1uMsT1rEsgmip7FuJjqW0qEyuHFRTt47aK0GJRX42VC5kJVMX8ujl8ucqSSNa
+PRh6IPQgIxSchu79weP+YIxMz3GDvNuu6z4QWdkzQrnYqSJpLgNGPAdAxFCgsok3
+5rFNhadGNv6RqrG00HmXPBTTq6T8rQEsbQZQZ4eensb0HxdiQyX4XGnMeEpElTwO
+LHziGIW2jBA9v5FJVBCC9QQysNby
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-recent.pem.certspec b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-recent.pem.certspec
new file mode 100644
index 000000000..140c20143
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements/san-contains-no-hostnames-recent.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:example.com
+validity:20160824-20160924
+extension:subjectAlternativeName:/O=Example Organization
diff --git a/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js
new file mode 100644
index 000000000..8917671b8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_baseline_requirements_subject_common_name.js
@@ -0,0 +1,188 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// The preference security.pki.name_matching_mode controls whether or not
+// mozilla::pkix will fall back to using a certificate's subject common name
+// during name matching. If the Baseline Requirements are followed, fallback
+// should not be necessary (because any name information in the subject common
+// name should be present in the subject alternative name extension). Due to
+// compatibility concerns, the platform can be configured to fall back for
+// certificates that are valid before 23 August 2016. Note that for certificates
+// issued by an imported root, the platform will fall back if necessary,
+// regardless of the value of the preference.
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function certFromFile(certName) {
+ return constructCertFromFile(`test_baseline_requirements/${certName}.pem`);
+}
+
+function loadCertWithTrust(certName, trustString) {
+ addCertFromFile(gCertDB, `test_baseline_requirements/${certName}.pem`,
+ trustString);
+}
+
+function checkCertOn25August2016(cert, expectedResult) {
+ // (new Date("2016-08-25T00:00:00Z")).getTime() / 1000
+ const VALIDATION_TIME = 1472083200;
+ checkCertErrorGenericAtTime(gCertDB, cert, expectedResult,
+ certificateUsageSSLServer, VALIDATION_TIME, {},
+ "example.com");
+}
+
+function run_test() {
+ do_register_cleanup(() => {
+ Services.prefs.clearUserPref("security.pki.name_matching_mode");
+ Services.prefs.clearUserPref("security.test.built_in_root_hash");
+ });
+
+ loadCertWithTrust("ca", "CTu,,");
+
+ // When verifying a certificate, if the trust anchor is not a built-in root,
+ // name matching will fall back to using the subject common name if necessary
+ // (i.e. if there is no subject alternative name extension or it does not
+ // contain any dNSName or iPAddress entries). Thus, since imported roots are
+ // not in general treated as built-ins, these should all successfully verify
+ // regardless of the value of the pref.
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 0);
+ do_print("current mode: always fall back, root not built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-older"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+ PRErrorCodeSuccess);
+
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 1);
+ do_print("current mode: fall back for notBefore < August 23, 2016, root " +
+ "not built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-older"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+ PRErrorCodeSuccess);
+
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
+ do_print("current mode: fall back for notBefore < August 23, 2015, root " +
+ "not built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-older"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+ PRErrorCodeSuccess);
+
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 3);
+ do_print("current mode: never fall back, root not built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-older"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+ PRErrorCodeSuccess);
+
+ // In debug builds, we can treat an imported root as a built-in, and thus we
+ // can actually test the different values of the pref.
+ if (isDebugBuild) {
+ let root = certFromFile("ca");
+ Services.prefs.setCharPref("security.test.built_in_root_hash",
+ root.sha256Fingerprint);
+
+ // Always fall back if necessary.
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 0);
+ do_print("current mode: always fall back, root built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-older"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+ PRErrorCodeSuccess);
+
+ // Only fall back if notBefore < 23 August 2016
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 1);
+ do_print("current mode: fall back for notBefore < August 23, 2016, root " +
+ "built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("no-san-older"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+ PRErrorCodeSuccess);
+
+ // Only fall back if notBefore < 23 August 2015
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 2);
+ do_print("current mode: fall back for notBefore < August 23, 2015, root " +
+ "built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("no-san-older"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+ PRErrorCodeSuccess);
+
+ // Never fall back.
+ Services.prefs.setIntPref("security.pki.name_matching_mode", 3);
+ do_print("current mode: never fall back, root built-in");
+ checkCertOn25August2016(certFromFile("no-san-recent"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("no-san-old"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("no-san-older"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-recent"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-old"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ checkCertOn25August2016(certFromFile("san-contains-no-hostnames-older"),
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ }
+}
diff --git a/security/manager/ssl/tests/unit/test_certDB_import.js b/security/manager/ssl/tests/unit/test_certDB_import.js
new file mode 100644
index 000000000..f53fbf0ef
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import.js
@@ -0,0 +1,118 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests the various nsIX509CertDB import methods.
+
+do_get_profile();
+
+const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+const CA_CERT_COMMON_NAME = "importedCA";
+const TEST_EMAIL_ADDRESS = "test@example.com";
+
+let gCACertImportDialogCount = 0;
+
+// Mock implementation of nsICertificateDialogs.
+const gCertificateDialogs = {
+ confirmDownloadCACert: (ctx, cert, trust) => {
+ gCACertImportDialogCount++;
+ equal(cert.commonName, CA_CERT_COMMON_NAME,
+ "CA cert to import should have the correct CN");
+ trust.value = Ci.nsIX509CertDB.TRUSTED_EMAIL;
+ return true;
+ },
+ setPKCS12FilePassword: (ctx, password) => {
+ // This is only relevant to exporting.
+ ok(false, "setPKCS12FilePassword() should not have been called");
+ },
+ getPKCS12FilePassword: (ctx, password) => {
+ // We don't test anything that calls this method yet.
+ ok(false, "getPKCS12FilePassword() should not have been called");
+ },
+ viewCert: (ctx, cert) => {
+ // This shouldn't be called for import methods.
+ ok(false, "viewCert() should not have been called");
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs])
+};
+
+// Implements nsIInterfaceRequestor. Mostly serves to mock nsIPrompt.
+const gInterfaceRequestor = {
+ alert: (title, text) => {
+ // We don't test anything that calls this method yet.
+ ok(false, `alert() should not have been called: ${text}`);
+ },
+
+ getInterface: iid => {
+ if (iid.equals(Ci.nsIPrompt)) {
+ return this;
+ }
+
+ throw new Error(Cr.NS_ERROR_NO_INTERFACE);
+ }
+};
+
+function getCertAsByteArray(certPath) {
+ let certFile = do_get_file(certPath, false);
+ let certBytes = readFile(certFile);
+
+ let byteArray = [];
+ for (let i = 0; i < certBytes.length; i++) {
+ byteArray.push(certBytes.charCodeAt(i));
+ }
+
+ return byteArray;
+}
+
+function testImportCACert() {
+ // Sanity check the CA cert is missing.
+ throws(() => gCertDB.findCertByNickname(CA_CERT_COMMON_NAME),
+ /NS_ERROR_FAILURE/,
+ "CA cert should not be in the database before import");
+
+ // Import and check for success.
+ let caArray = getCertAsByteArray("test_certDB_import/importedCA.pem");
+ gCertDB.importCertificates(caArray, caArray.length, Ci.nsIX509Cert.CA_CERT,
+ gInterfaceRequestor);
+ equal(gCACertImportDialogCount, 1,
+ "Confirmation dialog for the CA cert should only be shown once");
+
+ let caCert = gCertDB.findCertByNickname(CA_CERT_COMMON_NAME);
+ notEqual(caCert, null, "CA cert should now be found in the database");
+ ok(gCertDB.isCertTrusted(caCert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_EMAIL),
+ "CA cert should be trusted for e-mail");
+}
+
+function run_test() {
+ // We have to set a password and login before we attempt to import anything.
+ // In particular, the SQL NSS DB requires the user to be authenticated to set
+ // certificate trust settings, which we do when we import CA certs.
+ loginToDBWithDefaultPassword();
+
+ let certificateDialogsCID =
+ MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1",
+ gCertificateDialogs);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(certificateDialogsCID);
+ });
+
+ // Sanity check the e-mail cert is missing.
+ throws(() => gCertDB.findCertByEmailAddress(TEST_EMAIL_ADDRESS),
+ /NS_ERROR_FAILURE/,
+ "E-mail cert should not be in the database before import");
+
+ // Import the CA cert so that the e-mail import succeeds.
+ testImportCACert();
+
+ // Import the e-mail cert and check for success.
+ let emailArray = getCertAsByteArray("test_certDB_import/emailEE.pem");
+ gCertDB.importEmailCertificate(emailArray, emailArray.length,
+ gInterfaceRequestor);
+ notEqual(gCertDB.findCertByEmailAddress(TEST_EMAIL_ADDRESS), null,
+ "E-mail cert should now be found in the database");
+}
diff --git a/security/manager/ssl/tests/unit/test_certDB_import/cert_from_windows.pfx b/security/manager/ssl/tests/unit/test_certDB_import/cert_from_windows.pfx
new file mode 100644
index 000000000..e969d672d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/cert_from_windows.pfx
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem b/security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem
new file mode 100644
index 000000000..72b6371e2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUKTBs2ocwnIM+g29rcb+FMc8RTWswCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCmltcG9ydGVkQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowITEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAATALBgkqhkiG9w0BAQsDggEBAFbtBnvVJEYh/Zq1mZuQXasaqD0Xp0s3hxEr
+hDkrSh2uQ/lm3lvHuDLodI2cSYJz9A/ona2QHt9Rb9X7CmWFQ8DJtF1aiWLFlqgd
+muaib0gSusRZr2cC+N7N35tmVO/gLlESlhQh40ORgSgMg+K8Vj3QwML5NSc91B7I
+dCxZx5sZFl2HacOlQ0BFHqyk4tyPXxFLm5Ky56e2g52pCbWRkUbD2ScuxpoAd79E
+n3FQYSZFn/AdrbSoko/+3AzNvHNCtqs8XAC4rE2dEuRYBjTF+ge4hGJqMFCRiCzN
+2thjCmenbilKlLWL5fqNdaJqrMKD0Yp9AQhkICoIKXIJFquf9eQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem.certspec b/security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem.certspec
new file mode 100644
index 000000000..0528bc624
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/emailEE.pem.certspec
@@ -0,0 +1,2 @@
+issuer:importedCA
+subject:/emailAddress=test@example.com
diff --git a/security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem b/security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem
new file mode 100644
index 000000000..77ec4cbac
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyDCCAbKgAwIBAgIUe4uNcR4KmHzd+jhffWz/NeLVWEUwCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCmltcG9ydGVkQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowFTETMBEGA1UEAwwKaW1wb3J0ZWRDQTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhX
+bCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQ
+OCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9
+uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFb
+t+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhO
+NsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMQMA4wDAYD
+VR0TBAUwAwEB/zALBgkqhkiG9w0BAQsDggEBAKENtK8hNu6JqM9B5OZWOrS8HT+j
+ij9DiGh/rY9vf+2RywnR3RKq7yUO/GalAVbPP6OQBF+6qUJ4kQ6DO6XX7hKiB46n
+XeVsxE9PawM/tsZszu/u2f3252AhDKgiy+doqtx4dbjBlCZxjtNEAu6EVHbseyBT
+0C7+ILcmWXw6ZR4m9u7KoeHc2PMbYtj0YLveWgCXm7vIGw0Tl3eMZqsY1dG4LC3z
+7vbr9HcLCpxOiUVfmLKs0l6nhbdoedNZ8zQDPFAI4ME3Em+7MNf+SRL0L45J0Sok
+CqDbTn2fPlwEVsZqhq2475CXIzRpHxeF4Z0bB0vtXWH2oq+T3x7xqGxEmDU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem.certspec b/security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem.certspec
new file mode 100644
index 000000000..b16825354
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/importedCA.pem.certspec
@@ -0,0 +1,3 @@
+issuer:importedCA
+subject:importedCA
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_certDB_import/moz.build b/security/manager/ssl/tests/unit/test_certDB_import/moz.build
new file mode 100644
index 000000000..0c973c9e8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See Bug 1256495.
+#test_certificates = (
+# 'emailEE.pem',
+# 'importedCA.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js b/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js
new file mode 100644
index 000000000..56e17855a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js
@@ -0,0 +1,92 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests import PKCS12 file by nsIX509CertDB.
+
+do_get_profile();
+
+const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+const CERT_COMMON_NAME = "test_cert_from_windows";
+const TEST_CERT_PASSWORD = "黒い";
+
+let gGetPKCS12Password = false;
+
+// Mock implementation of nsICertificateDialogs.
+const gCertificateDialogs = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs]),
+
+ getPKCS12FilePassword: (ctx, password) => {
+ ok(!gGetPKCS12Password,
+ "getPKCS12FilePassword should be called only once.");
+
+ password.value = TEST_CERT_PASSWORD;
+ do_print("getPKCS12FilePassword() is called");
+ gGetPKCS12Password = true;
+ return true;
+ },
+};
+
+const gPrompt = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]),
+ alert: (title, text) => {
+ do_print("alert('" + text + "')");
+ },
+};
+
+const gPromptFactory = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptFactory]),
+ getPrompt: (aWindow, aIID) => gPrompt,
+};
+
+function doesCertExist(commonName) {
+ let allCerts = gCertDB.getCerts();
+ let enumerator = allCerts.getEnumerator();
+ while (enumerator.hasMoreElements()) {
+ let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
+ if (cert.isBuiltInRoot) {
+ continue;
+ }
+ if (cert.commonName == commonName) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function testImportPKCS12Cert() {
+ ok(!doesCertExist(CERT_COMMON_NAME),
+ "Cert should not be in the database before import");
+
+ // Import and check for success.
+ let certFile = do_get_file("test_certDB_import/cert_from_windows.pfx");
+ gCertDB.importPKCS12File(null, certFile);
+
+ ok(gGetPKCS12Password, "PKCS12 password should be asked");
+
+ ok(doesCertExist(CERT_COMMON_NAME),
+ "Cert should now be found in the database");
+}
+
+function run_test() {
+ // We have to set a password and login before we attempt to import anything.
+ loginToDBWithDefaultPassword();
+
+ let certificateDialogsCID =
+ MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1",
+ gCertificateDialogs);
+ let promptFactoryCID =
+ MockRegistrar.register("@mozilla.org/prompter;1", gPromptFactory);
+
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(certificateDialogsCID);
+ MockRegistrar.unregister(promptFactoryCID);
+ });
+
+ // Import PKCS12 file with utf-8 password
+ testImportPKCS12Cert();
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_blocklist.js b/security/manager/ssl/tests/unit/test_cert_blocklist.js
new file mode 100644
index 000000000..75688b58a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_blocklist.js
@@ -0,0 +1,362 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// This test checks a number of things:
+// * it ensures that data loaded from revocations.txt on startup is present
+// * it ensures that certItems in blocklist.xml are persisted correctly
+// * it ensures that items in the CertBlocklist are seen as revoked by the
+// cert verifier
+// * it does a sanity check to ensure other cert verifier behavior is
+// unmodified
+
+// First, we need to setup appInfo for the blocklist service to work
+var id = "xpcshell@tests.mozilla.org";
+var appName = "XPCShell";
+var version = "1";
+var platformVersion = "1.9.2";
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+/*global updateAppInfo:false*/ // Imported via AppInfo.jsm.
+updateAppInfo({
+ name: appName,
+ ID: id,
+ version: version,
+ platformVersion: platformVersion ? platformVersion : "1.0",
+ crashReporter: true,
+});
+
+// we need to ensure we setup revocation data before certDB, or we'll start with
+// no revocation.txt in the profile
+var gProfile = do_get_profile();
+
+// Write out an empty blocklist.xml file to the profile to ensure nothing
+// is blocklisted by default
+var blockFile = gProfile.clone();
+blockFile.append("blocklist.xml");
+var stream = Cc["@mozilla.org/network/file-output-stream;1"]
+ .createInstance(Ci.nsIFileOutputStream);
+stream.init(blockFile,
+ FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
+ FileUtils.PERMS_FILE, 0);
+
+var data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">\n" +
+ "</blocklist>\n";
+stream.write(data, data.length);
+stream.close();
+
+const PREF_BLOCKLIST_UPDATE_ENABLED = "services.blocklist.update_enabled";
+const PREF_ONECRL_VIA_AMO = "security.onecrl.via.amo";
+
+var gRevocations = gProfile.clone();
+gRevocations.append("revocations.txt");
+if (!gRevocations.exists()) {
+ let existing = do_get_file("test_onecrl/sample_revocations.txt", false);
+ existing.copyTo(gProfile, "revocations.txt");
+}
+
+var certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+// set up a test server to serve the blocklist.xml
+var testserver = new HttpServer();
+
+var initialBlocklist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
+ // test with some bad data ...
+ "<certItems><certItem issuerName='Some nonsense in issuer'>" +
+ "<serialNumber>AkHVNA==</serialNumber>" +
+ "</certItem><certItem issuerName='MA0xCzAJBgNVBAMMAmNh'>" +
+ "<serialNumber>some nonsense in serial</serialNumber>" +
+ "</certItem><certItem issuerName='some nonsense in both issuer'>" +
+ "<serialNumber>and serial</serialNumber></certItem>" +
+ // some mixed
+ // In this case, the issuer name and the valid serialNumber correspond
+ // to test-int.pem in bad_certs/
+ "<certItem issuerName='MBIxEDAOBgNVBAMMB1Rlc3QgQ0E='>" +
+ "<serialNumber>oops! more nonsense.</serialNumber>" +
+ "<serialNumber>BVio/iQ21GCi2iUven8oJ/gae74=</serialNumber></certItem>" +
+ // ... and some good
+ // In this case, the issuer name and the valid serialNumber correspond
+ // to other-test-ca.pem in bad_certs/ (for testing root revocation)
+ "<certItem issuerName='MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E='>" +
+ "<serialNumber>exJUIJpq50jgqOwQluhVrAzTF74=</serialNumber></certItem>" +
+ // This item corresponds to an entry in sample_revocations.txt where:
+ // isser name is "another imaginary issuer" base-64 encoded, and
+ // serialNumbers are:
+ // "serial2." base-64 encoded, and
+ // "another serial." base-64 encoded
+ // We need this to ensure that existing items are retained if they're
+ // also in the blocklist
+ "<certItem issuerName='YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy'>" +
+ "<serialNumber>c2VyaWFsMi4=</serialNumber>" +
+ "<serialNumber>YW5vdGhlciBzZXJpYWwu</serialNumber></certItem>" +
+ // This item revokes same-issuer-ee.pem by subject and pubKeyHash.
+ "<certItem subject='MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5'" +
+ " pubKeyHash='VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8='>" +
+ "</certItem></certItems></blocklist>";
+
+var updatedBlocklist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">" +
+ "<certItems>" +
+ "<certItem issuerName='something new in both the issuer'>" +
+ "<serialNumber>and the serial number</serialNumber></certItem>" +
+ "</certItems></blocklist>";
+
+
+var blocklists = {
+ "/initialBlocklist/": initialBlocklist,
+ "/updatedBlocklist/": updatedBlocklist
+};
+
+function serveResponse(request, response) {
+ do_print("Serving for path " + request.path + "\n");
+ response.write(blocklists[request.path]);
+}
+
+for (var path in blocklists) {
+ testserver.registerPathHandler(path, serveResponse);
+}
+
+// start the test server
+testserver.start(-1);
+var port = testserver.identity.primaryPort;
+
+// Setup the addonManager
+var addonManager = Cc["@mozilla.org/addons/integration;1"]
+ .getService(Ci.nsIObserver)
+ .QueryInterface(Ci.nsITimerCallback);
+addonManager.observe(null, "addons-startup", null);
+
+var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+ .createInstance(Ci.nsIScriptableUnicodeConverter);
+converter.charset = "UTF-8";
+
+function verify_cert(file, expectedError) {
+ let ee = constructCertFromFile(file);
+ checkCertErrorGeneric(certDB, ee, expectedError, certificateUsageSSLServer);
+}
+
+// The certificate blocklist currently only applies to TLS server certificates.
+function verify_non_tls_usage_succeeds(file) {
+ let ee = constructCertFromFile(file);
+ checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
+ certificateUsageSSLClient);
+ checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
+ certificateUsageEmailSigner);
+ checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
+ certificateUsageEmailRecipient);
+}
+
+function load_cert(cert, trust) {
+ let file = "bad_certs/" + cert + ".pem";
+ addCertFromFile(certDB, file, trust);
+}
+
+function test_is_revoked(certList, issuerString, serialString, subjectString,
+ pubKeyString) {
+ let issuer = converter.convertToByteArray(issuerString ? issuerString : '',
+ {});
+
+ let serial = converter.convertToByteArray(serialString ? serialString : '',
+ {});
+
+ let subject = converter.convertToByteArray(subjectString ? subjectString : '',
+ {});
+
+ let pubKey = converter.convertToByteArray(pubKeyString ? pubKeyString : '',
+ {});
+
+ return certList.isCertRevoked(issuer,
+ issuerString ? issuerString.length : 0,
+ serial,
+ serialString ? serialString.length : 0,
+ subject,
+ subjectString ? subjectString.length : 0,
+ pubKey,
+ pubKeyString ? pubKeyString.length : 0);
+}
+
+function fetch_blocklist(blocklistPath) {
+ do_print("path is " + blocklistPath + "\n");
+ let certblockObserver = {
+ observe: function(aSubject, aTopic, aData) {
+ Services.obs.removeObserver(this, "blocklist-updated");
+ run_next_test();
+ }
+ };
+
+ Services.obs.addObserver(certblockObserver, "blocklist-updated", false);
+ Services.prefs.setCharPref("extensions.blocklist.url",
+ `http://localhost:${port}/${blocklistPath}`);
+ let blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
+ .getService(Ci.nsITimerCallback);
+ blocklist.notify(null);
+}
+
+function check_revocations_txt_contents(expected) {
+ let profile = do_get_profile();
+ let revocations = profile.clone();
+ revocations.append("revocations.txt");
+ ok(revocations.exists(), "the revocations file should exist");
+ let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Ci.nsIFileInputStream);
+ inputStream.init(revocations, -1, -1, 0);
+ inputStream.QueryInterface(Ci.nsILineInputStream);
+ let contents = "";
+ let hasmore = false;
+ do {
+ let line = {};
+ hasmore = inputStream.readLine(line);
+ contents += (contents.length == 0 ? "" : "\n") + line.value;
+ } while (hasmore);
+ equal(contents, expected, "revocations.txt should be as expected");
+}
+
+function run_test() {
+ // import the certificates we need
+ load_cert("test-ca", "CTu,CTu,CTu");
+ load_cert("test-int", ",,");
+ load_cert("other-test-ca", "CTu,CTu,CTu");
+
+ let certList = Cc["@mozilla.org/security/certblocklist;1"]
+ .getService(Ci.nsICertBlocklist);
+
+ let expected = "# Auto generated contents. Do not edit.\n" +
+ "MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5\n" +
+ "\tVCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=\n" +
+ "MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=\n" +
+ " BVio/iQ21GCi2iUven8oJ/gae74=\n" +
+ "MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E=\n" +
+ " exJUIJpq50jgqOwQluhVrAzTF74=\n" +
+ "YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy\n" +
+ " YW5vdGhlciBzZXJpYWwu\n" +
+ " c2VyaWFsMi4=";
+
+ // This test assumes OneCRL updates via AMO
+ Services.prefs.setBoolPref(PREF_BLOCKLIST_UPDATE_ENABLED, false);
+ Services.prefs.setBoolPref(PREF_ONECRL_VIA_AMO, true);
+
+ add_test(function () {
+ // check some existing items in revocations.txt are blocked. Since the
+ // CertBlocklistItems don't know about the data they contain, we can use
+ // arbitrary data (not necessarily DER) to test if items are revoked or not.
+ // This test corresponds to:
+ // issuer: c29tZSBpbWFnaW5hcnkgaXNzdWVy
+ // serial: c2VyaWFsLg==
+ ok(test_is_revoked(certList, "some imaginary issuer", "serial."),
+ "issuer / serial pair should be blocked");
+
+ // This test corresponds to:
+ // issuer: YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy
+ // serial: c2VyaWFsLg==
+ ok(test_is_revoked(certList, "another imaginary issuer", "serial."),
+ "issuer / serial pair should be blocked");
+
+ // And this test corresponds to:
+ // issuer: YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy
+ // serial: c2VyaWFsMi4=
+ // (we test this issuer twice to ensure we can read multiple serials)
+ ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
+ "issuer / serial pair should be blocked");
+
+ // Soon we'll load a blocklist which revokes test-int.pem, which issued
+ // test-int-ee.pem.
+ // Check the cert validates before we load the blocklist
+ let file = "test_onecrl/test-int-ee.pem";
+ verify_cert(file, PRErrorCodeSuccess);
+
+ // The blocklist also revokes other-test-ca.pem, which issued
+ // other-ca-ee.pem. Check the cert validates before we load the blocklist
+ file = "bad_certs/other-issuer-ee.pem";
+ verify_cert(file, PRErrorCodeSuccess);
+
+ // The blocklist will revoke same-issuer-ee.pem via subject / pubKeyHash.
+ // Check the cert validates before we load the blocklist
+ file = "test_onecrl/same-issuer-ee.pem";
+ verify_cert(file, PRErrorCodeSuccess);
+
+ run_next_test();
+ });
+
+ // blocklist load is async so we must use add_test from here
+ add_test(function() {
+ fetch_blocklist("initialBlocklist/");
+ });
+
+ add_test(function() {
+ // The blocklist will be loaded now. Let's check the data is sane.
+ // In particular, we should still have the revoked issuer / serial pair
+ // that was in both revocations.txt and the blocklist.xml
+ ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
+ "issuer / serial pair should be blocked");
+
+ // Check that both serials in the certItem with multiple serials were read
+ // properly
+ ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
+ "issuer / serial pair should be blocked");
+ ok(test_is_revoked(certList, "another imaginary issuer", "another serial."),
+ "issuer / serial pair should be blocked");
+
+ // test a subject / pubKey revocation
+ ok(test_is_revoked(certList, "nonsense", "more nonsense",
+ "some imaginary subject", "some imaginary pubkey"),
+ "issuer / serial pair should be blocked");
+
+ // Check the blocklist entry has been persisted properly to the backing
+ // file
+ check_revocations_txt_contents(expected);
+
+ // Check the blocklisted intermediate now causes a failure
+ let file = "test_onecrl/test-int-ee.pem";
+ verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
+ verify_non_tls_usage_succeeds(file);
+
+ // Check the ee with the blocklisted root also causes a failure
+ file = "bad_certs/other-issuer-ee.pem";
+ verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
+ verify_non_tls_usage_succeeds(file);
+
+ // Check the ee blocked by subject / pubKey causes a failure
+ file = "test_onecrl/same-issuer-ee.pem";
+ verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
+ verify_non_tls_usage_succeeds(file);
+
+ // Check a non-blocklisted chain still validates OK
+ file = "bad_certs/default-ee.pem";
+ verify_cert(file, PRErrorCodeSuccess);
+
+ // Check a bad cert is still bad (unknown issuer)
+ file = "bad_certs/unknownissuer.pem";
+ verify_cert(file, SEC_ERROR_UNKNOWN_ISSUER);
+
+ // check that save with no further update is a no-op
+ let lastModified = gRevocations.lastModifiedTime;
+ // add an already existing entry
+ certList.revokeCertByIssuerAndSerial("YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy",
+ "c2VyaWFsMi4=");
+ certList.saveEntries();
+ let newModified = gRevocations.lastModifiedTime;
+ equal(lastModified, newModified,
+ "saveEntries with no modifications should not update the backing file");
+
+ run_next_test();
+ });
+
+ // disable AMO cert blocklist - and check blocklist.xml changes do not
+ // affect the data stored.
+ add_test(function() {
+ Services.prefs.setBoolPref("security.onecrl.via.amo", false);
+ fetch_blocklist("updatedBlocklist/");
+ });
+
+ add_test(function() {
+ // Check the blocklist entry has not changed
+ check_revocations_txt_contents(expected);
+ run_next_test();
+ });
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_chains.js b/security/manager/ssl/tests/unit/test_cert_chains.js
new file mode 100644
index 000000000..8abcb4e65
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_chains.js
@@ -0,0 +1,134 @@
+// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+function build_cert_chain(certNames) {
+ let certList = Cc["@mozilla.org/security/x509certlist;1"]
+ .createInstance(Ci.nsIX509CertList);
+ certNames.forEach(function(certName) {
+ let cert = constructCertFromFile("bad_certs/" + certName + ".pem");
+ certList.addCert(cert);
+ });
+ return certList;
+}
+
+function test_cert_equals() {
+ let certA = constructCertFromFile("bad_certs/default-ee.pem");
+ let certB = constructCertFromFile("bad_certs/default-ee.pem");
+ let certC = constructCertFromFile("bad_certs/expired-ee.pem");
+
+ ok(certA != certB,
+ "Cert objects constructed from the same file should not be equal" +
+ " according to the equality operators");
+ ok(certA.equals(certB),
+ "equals() on cert objects constructed from the same cert file should" +
+ " return true");
+ ok(!certA.equals(certC),
+ "equals() on cert objects constructed from files for different certs" +
+ " should return false");
+}
+
+function test_cert_list_serialization() {
+ let certList = build_cert_chain(['default-ee', 'expired-ee']);
+
+ // Serialize the cert list to a string
+ let serHelper = Cc["@mozilla.org/network/serialization-helper;1"]
+ .getService(Ci.nsISerializationHelper);
+ certList.QueryInterface(Ci.nsISerializable);
+ let serialized = serHelper.serializeToString(certList);
+
+ // Deserialize from the string and compare to the original object
+ let deserialized = serHelper.deserializeObject(serialized);
+ deserialized.QueryInterface(Ci.nsIX509CertList);
+ ok(certList.equals(deserialized),
+ "Deserialized cert list should equal the original");
+}
+
+function test_security_info_serialization(securityInfo, expectedErrorCode) {
+ // Serialize the securityInfo to a string
+ let serHelper = Cc["@mozilla.org/network/serialization-helper;1"]
+ .getService(Ci.nsISerializationHelper);
+ let serialized = serHelper.serializeToString(securityInfo);
+
+ // Deserialize from the string and compare to the original object
+ let deserialized = serHelper.deserializeObject(serialized);
+ deserialized.QueryInterface(Ci.nsITransportSecurityInfo);
+ equal(securityInfo.securityState, deserialized.securityState,
+ "Original and deserialized security state should match");
+ equal(securityInfo.errorMessage, deserialized.errorMessage,
+ "Original and deserialized error message should match");
+ equal(securityInfo.errorCode, expectedErrorCode,
+ "Original and expected error code should match");
+ equal(deserialized.errorCode, expectedErrorCode,
+ "Deserialized and expected error code should match");
+}
+
+function run_test() {
+ do_get_profile();
+ add_tls_server_setup("BadCertServer", "bad_certs");
+
+ // Test nsIX509Cert.equals
+ add_test(function() {
+ test_cert_equals();
+ run_next_test();
+ });
+
+ // Test serialization of nsIX509CertList
+ add_test(function() {
+ test_cert_list_serialization();
+ run_next_test();
+ });
+
+ // Test successful connection (failedCertChain should be null)
+ add_connection_test(
+ // re-use pinning certs (keeler)
+ "good.include-subdomains.pinning.example.com", PRErrorCodeSuccess, null,
+ function withSecurityInfo(aTransportSecurityInfo) {
+ aTransportSecurityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
+ test_security_info_serialization(aTransportSecurityInfo, 0);
+ equal(aTransportSecurityInfo.failedCertChain, null,
+ "failedCertChain for a successful connection should be null");
+ }
+ );
+
+ // Test overrideable connection failure (failedCertChain should be non-null)
+ add_connection_test(
+ "expired.example.com",
+ SEC_ERROR_EXPIRED_CERTIFICATE,
+ null,
+ function withSecurityInfo(securityInfo) {
+ securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
+ test_security_info_serialization(securityInfo, SEC_ERROR_EXPIRED_CERTIFICATE);
+ notEqual(securityInfo.failedCertChain, null,
+ "failedCertChain should not be null for an overrideable" +
+ " connection failure");
+ let originalCertChain = build_cert_chain(["expired-ee", "test-ca"]);
+ ok(originalCertChain.equals(securityInfo.failedCertChain),
+ "failedCertChain should equal the original cert chain for an" +
+ " overrideable connection failure");
+ }
+ );
+
+ // Test non-overrideable error (failedCertChain should be non-null)
+ add_connection_test(
+ "inadequatekeyusage.example.com",
+ SEC_ERROR_INADEQUATE_KEY_USAGE,
+ null,
+ function withSecurityInfo(securityInfo) {
+ securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
+ test_security_info_serialization(securityInfo, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ notEqual(securityInfo.failedCertChain, null,
+ "failedCertChain should not be null for a non-overrideable" +
+ " connection failure");
+ let originalCertChain = build_cert_chain(["inadequatekeyusage-ee", "test-ca"]);
+ ok(originalCertChain.equals(securityInfo.failedCertChain),
+ "failedCertChain should equal the original cert chain for a" +
+ " non-overrideable connection failure");
+ }
+ );
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_dbKey.js b/security/manager/ssl/tests/unit/test_cert_dbKey.js
new file mode 100644
index 000000000..ca47a4997
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_dbKey.js
@@ -0,0 +1,146 @@
+// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+// This test tests that the nsIX509Cert.dbKey and nsIX509CertDB.findCertByDBKey
+// APIs work as expected. That is, getting a certificate's dbKey and using it
+// in findCertByDBKey should return the same certificate. Also, for backwards
+// compatibility, findCertByDBKey should ignore any whitespace in its input
+// (even though now nsIX509Cert.dbKey will never have whitespace in it).
+
+function hexStringToBytes(hex) {
+ let bytes = [];
+ for (let hexByteStr of hex.split(":")) {
+ bytes.push(parseInt(hexByteStr, 16));
+ }
+ return bytes;
+}
+
+function encodeCommonNameAsBytes(commonName) {
+ // The encoding will look something like this (in hex):
+ // 30 (SEQUENCE) <length of contents>
+ // 31 (SET) <length of contents>
+ // 30 (SEQUENCE) <length of contents>
+ // 06 (OID) 03 (length)
+ // 55 04 03 (id-at-commonName)
+ // 0C (UTF8String) <length of common name>
+ // <common name bytes>
+ // To make things simple, it would be nice to have the length of each
+ // component be less than 128 bytes (so we can have single-byte lengths).
+ // For this to hold, the maximum length of the contents of the outermost
+ // SEQUENCE must be 127. Everything not in the contents of the common name
+ // will take up 11 bytes, so the value of the common name itself can be at
+ // most 116 bytes.
+ ok(commonName.length <= 116,
+ "test assumption: common name can't be longer than 116 bytes (makes " +
+ "DER encoding easier)");
+ let commonNameOIDBytes = [ 0x06, 0x03, 0x55, 0x04, 0x03 ];
+ let commonNameBytes = [ 0x0C, commonName.length ];
+ for (let i = 0; i < commonName.length; i++) {
+ commonNameBytes.push(commonName.charCodeAt(i));
+ }
+ let bytes = commonNameOIDBytes.concat(commonNameBytes);
+ bytes.unshift(bytes.length);
+ bytes.unshift(0x30); // SEQUENCE
+ bytes.unshift(bytes.length);
+ bytes.unshift(0x31); // SET
+ bytes.unshift(bytes.length);
+ bytes.unshift(0x30); // SEQUENCE
+ return bytes;
+}
+
+function testInvalidDBKey(certDB, dbKey) {
+ throws(() => certDB.findCertByDBKey(dbKey), /NS_ERROR_ILLEGAL_INPUT/,
+ `findCertByDBKey(${dbKey}) should raise NS_ERROR_ILLEGAL_INPUT`);
+}
+
+function testDBKeyForNonexistentCert(certDB, dbKey) {
+ let cert = certDB.findCertByDBKey(dbKey);
+ ok(!cert, "shouldn't find cert for given dbKey");
+}
+
+function byteArrayToByteString(bytes) {
+ let byteString = "";
+ for (let b of bytes) {
+ byteString += String.fromCharCode(b);
+ }
+ return byteString;
+}
+
+function run_test() {
+ do_get_profile();
+ let certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ let cert = constructCertFromFile("bad_certs/test-ca.pem");
+ equal(cert.issuerName, "CN=" + cert.issuerCommonName,
+ "test assumption: this certificate's issuer distinguished name " +
+ "consists only of a common name");
+ let issuerBytes = encodeCommonNameAsBytes(cert.issuerCommonName);
+ ok(issuerBytes.length < 256,
+ "test assumption: length of encoded issuer is less than 256 bytes");
+ let serialNumberBytes = hexStringToBytes(cert.serialNumber);
+ ok(serialNumberBytes.length < 256,
+ "test assumption: length of encoded serial number is less than 256 bytes");
+ let dbKeyHeader = [ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, serialNumberBytes.length,
+ 0, 0, 0, issuerBytes.length ];
+ let expectedDbKeyBytes = dbKeyHeader.concat(serialNumberBytes, issuerBytes);
+ let expectedDbKey = btoa(byteArrayToByteString(expectedDbKeyBytes));
+ equal(cert.dbKey, expectedDbKey,
+ "actual and expected dbKey values should match");
+
+ let certFromDbKey = certDB.findCertByDBKey(expectedDbKey);
+ ok(certFromDbKey.equals(cert),
+ "nsIX509CertDB.findCertByDBKey should find the right certificate");
+
+ ok(expectedDbKey.length > 64,
+ "test assumption: dbKey should be longer than 64 characters");
+ let expectedDbKeyWithCRLF = expectedDbKey.replace(/(.{64})/, "$1\r\n");
+ ok(expectedDbKeyWithCRLF.indexOf("\r\n") == 64,
+ "test self-check: adding CRLF to dbKey should succeed");
+ certFromDbKey = certDB.findCertByDBKey(expectedDbKeyWithCRLF);
+ ok(certFromDbKey.equals(cert),
+ "nsIX509CertDB.findCertByDBKey should work with dbKey with CRLF");
+
+ let expectedDbKeyWithSpaces = expectedDbKey.replace(/(.{64})/, "$1 ");
+ ok(expectedDbKeyWithSpaces.indexOf(" ") == 64,
+ "test self-check: adding spaces to dbKey should succeed");
+ certFromDbKey = certDB.findCertByDBKey(expectedDbKeyWithSpaces);
+ ok(certFromDbKey.equals(cert),
+ "nsIX509CertDB.findCertByDBKey should work with dbKey with spaces");
+
+ // Test some invalid dbKey values.
+ testInvalidDBKey(certDB, "AAAA"); // Not long enough.
+ // No header.
+ testInvalidDBKey(certDB, btoa(byteArrayToByteString(
+ [ 0, 0, 0, serialNumberBytes.length,
+ 0, 0, 0, issuerBytes.length ].concat(serialNumberBytes, issuerBytes))));
+ testInvalidDBKey(certDB, btoa(byteArrayToByteString(
+ [ 0, 0, 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, // serial number length is way too long
+ 255, 255, 255, 255, // issuer length is way too long
+ 0, 0, 0, 0 ])));
+ // Truncated issuer.
+ testInvalidDBKey(certDB, btoa(byteArrayToByteString(
+ [ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1,
+ 0, 0, 0, 10,
+ 1,
+ 1, 2, 3 ])));
+ // Issuer doesn't decode to valid common name.
+ testDBKeyForNonexistentCert(certDB, btoa(byteArrayToByteString(
+ [ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1,
+ 0, 0, 0, 3,
+ 1,
+ 1, 2, 3 ])));
+
+ // zero-length serial number and issuer -> no such certificate
+ testDBKeyForNonexistentCert(certDB, btoa(byteArrayToByteString(
+ [ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0 ])));
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_eku.js b/security/manager/ssl/tests/unit/test_cert_eku.js
new file mode 100644
index 000000000..5a7e28de1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku.js
@@ -0,0 +1,131 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Tests that the extended key usage extension is properly processed by the
+// platform when verifying certificates. There are already comprehensive tests
+// in mozilla::pkix itself, but these tests serve as integration tests to ensure
+// that the cases we're particularly concerned about are correctly handled.
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function certFromFile(certName) {
+ return constructCertFromFile(`test_cert_eku/${certName}.pem`);
+}
+
+function loadCertWithTrust(certName, trustString) {
+ addCertFromFile(certdb, `test_cert_eku/${certName}.pem`, trustString);
+}
+
+function checkEndEntity(cert, expectedResult) {
+ checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLServer);
+}
+
+function checkCertOn25August2016(cert, expectedResult) {
+ // (new Date("2016-08-25T00:00:00Z")).getTime() / 1000
+ const VALIDATION_TIME = 1472083200;
+ checkCertErrorGenericAtTime(certdb, cert, expectedResult,
+ certificateUsageSSLServer, VALIDATION_TIME);
+}
+
+function run_test() {
+ loadCertWithTrust("ca", "CTu,,");
+ // end-entity has id-kp-serverAuth => success
+ checkEndEntity(certFromFile("ee-SA"), PRErrorCodeSuccess);
+ // end-entity has id-kp-serverAuth => success
+ checkEndEntity(certFromFile("ee-SA-CA"), PRErrorCodeSuccess);
+ // end-entity has extended key usage, but id-kp-serverAuth is not present =>
+ // failure
+ checkEndEntity(certFromFile("ee-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+ // end-entity has id-kp-serverAuth => success
+ checkEndEntity(certFromFile("ee-SA-nsSGC"), PRErrorCodeSuccess);
+
+ // end-entity has extended key usage, but id-kp-serverAuth is not present =>
+ // failure (in particular, Netscape Server Gated Crypto (also known as
+ // Netscape Step Up) is not an acceptable substitute for end-entity
+ // certificates).
+ // Verify this for all Netscape Step Up policy configurations.
+ // 0 = "always accept nsSGC in place of serverAuth for CA certificates"
+ Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 0);
+ checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+ // 1 = "accept nsSGC before 23 August 2016"
+ Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 1);
+ checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+ // 2 = "accept nsSGC before 23 August 2015"
+ Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 2);
+ checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+ // 3 = "never accept nsSGC"
+ Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 3);
+ checkEndEntity(certFromFile("ee-nsSGC"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+
+ // end-entity has id-kp-OCSPSigning, which is not acceptable for end-entity
+ // certificates being verified as TLS server certificates => failure
+ checkEndEntity(certFromFile("ee-SA-OCSP"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+
+ // intermediate has id-kp-serverAuth => success
+ loadCertWithTrust("int-SA", ",,");
+ checkEndEntity(certFromFile("ee-int-SA"), PRErrorCodeSuccess);
+ // intermediate has id-kp-serverAuth => success
+ loadCertWithTrust("int-SA-CA", ",,");
+ checkEndEntity(certFromFile("ee-int-SA-CA"), PRErrorCodeSuccess);
+ // intermediate has extended key usage, but id-kp-serverAuth is not present
+ // => failure
+ loadCertWithTrust("int-CA", ",,");
+ checkEndEntity(certFromFile("ee-int-CA"), SEC_ERROR_INADEQUATE_CERT_TYPE);
+ // intermediate has id-kp-serverAuth => success
+ loadCertWithTrust("int-SA-nsSGC", ",,");
+ checkEndEntity(certFromFile("ee-int-SA-nsSGC"), PRErrorCodeSuccess);
+
+ // Intermediate has Netscape Server Gated Crypto. Success will depend on the
+ // Netscape Step Up policy configuration and the notBefore property of the
+ // intermediate.
+ loadCertWithTrust("int-nsSGC-recent", ",,");
+ loadCertWithTrust("int-nsSGC-old", ",,");
+ loadCertWithTrust("int-nsSGC-older", ",,");
+ // 0 = "always accept nsSGC in place of serverAuth for CA certificates"
+ Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 0);
+ do_print("Netscape Step Up policy: always accept");
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
+ PRErrorCodeSuccess);
+ // 1 = "accept nsSGC before 23 August 2016"
+ do_print("Netscape Step Up policy: accept before 23 August 2016");
+ Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 1);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
+ SEC_ERROR_INADEQUATE_CERT_TYPE);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
+ PRErrorCodeSuccess);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
+ PRErrorCodeSuccess);
+ // 2 = "accept nsSGC before 23 August 2015"
+ do_print("Netscape Step Up policy: accept before 23 August 2015");
+ Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 2);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
+ SEC_ERROR_INADEQUATE_CERT_TYPE);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
+ SEC_ERROR_INADEQUATE_CERT_TYPE);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
+ PRErrorCodeSuccess);
+ // 3 = "never accept nsSGC"
+ do_print("Netscape Step Up policy: never accept");
+ Services.prefs.setIntPref("security.pki.netscape_step_up_policy", 3);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-recent"),
+ SEC_ERROR_INADEQUATE_CERT_TYPE);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-old"),
+ SEC_ERROR_INADEQUATE_CERT_TYPE);
+ checkCertOn25August2016(certFromFile("ee-int-nsSGC-older"),
+ SEC_ERROR_INADEQUATE_CERT_TYPE);
+
+ // intermediate has id-kp-OCSPSigning, which is acceptable for CA
+ // certificates => success
+ loadCertWithTrust("int-SA-OCSP", ",,");
+ checkEndEntity(certFromFile("ee-int-SA-OCSP"), PRErrorCodeSuccess);
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ca.pem b/security/manager/ssl/tests/unit/test_cert_eku/ca.pem
new file mode 100644
index 000000000..f9bc514d4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICuDCCAaKgAwIBAgIUNRoMRQGf1ZJA3n83kdc6L92/CEowCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MAsGCSqG
+SIb3DQEBCwOCAQEAs/WSLtD9nmferqrktS7n94DuJKXYIyVwANS+HUSP515q0zTY
+12Poo6n4UAJpAcO+MK2DhBREa3qtQBxxazmC6zAqvyOCE6l7YlzDXbjqLSfKn3ti
+JrltsfR/0P5zqLDPu2TaXaYey+dtGqvGINjRccB9OknroUH+jX7jWqGBL4Gz8IOR
+5I30FWKfDZTuhMNyBCVpCo5IL5VUdEgZsOlBe5jnGPtN7Q3LmFU91yoRXoOtp+e6
+94pZNhJqGfqLpH8ArRi5qr4QteCRSfvYFBusniJOLnGDi6K3Nh6iBvwPM8qSfQ5A
+Cj361pbNvT+OPpdlm9DFCh6k8jKhZ2fXXMHdtg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ca.pem.certspec
new file mode 100644
index 000000000..eb7c4b4be
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ca.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-CA.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-CA.pem
new file mode 100644
index 000000000..a92b75aab
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-CA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUNTNJjnkkZVkSqyxFevGNL4LSwUowCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBAxDjAMBgNVBAMMBWVlLUNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGc
+BptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzC
+a2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8Xg
+uEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK
+9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGP
+mRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxcwFTATBgNVHSUEDDAKBggrBgEF
+BQcDAjALBgkqhkiG9w0BAQsDggEBABqY2vFn+HYKesMyzER/V6bypmpBTSNerPdh
+cUaLKr0dIXqwhcNi1C/e4RVnMH/mQIru/ts5Q8g6FErgNaDk78fE329xvlxUF4d8
+3tagpgo58YXz0O+cTb9MjSb4esoq8wSb5/7XJwIOOUekGDucou3SJmjhc5PJsz1M
+tC0LZdS9/dW9isNC7cucG3iqqc7JeWi5wjnaDOlDa97fn307PDhoxpa/RCBOQHIu
+c4HAdZmVa7bfq3xHTCo7/tyDGRSVBkJoNPVQq87sHPUKjBETUFiIvwhwkQdE+Xav
+0cJeEbpH/v8dBtnIqSPdz/pNym0RAbj3vUxUefrwHf9vRkGI540=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-CA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-CA.pem.certspec
new file mode 100644
index 000000000..d49cabaa2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-CA.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-CA
+extension:extKeyUsage:clientAuth
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-CA.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-CA.pem
new file mode 100644
index 000000000..e213e4494
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-CA.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbmgAwIBAgIUJ0QK+zSmb5HCuQ8LczjgBonFNKgwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBMxETAPBgNVBAMMCGVlLVNBLUNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4Ngf
+vbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTb
+uUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3S
+O8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR
+3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv
+5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoyEwHzAdBgNVHSUEFjAUBggr
+BgEFBQcDAQYIKwYBBQUHAwIwCwYJKoZIhvcNAQELA4IBAQBrWrTkqS66uaIJtips
+SYF7wyReLJVmft0oAR2cWejAJcW00smFFkAttsxhMw1ttSKF3y2++zfPe24ufIjL
+w1l2xa5dDPaHHS5dNvbcjmNWjb6zjErWd7d9fpMpeWA828Yy51hXViuj+DktVz+z
+XF+Q0v8oVgaIPRClhwzt40rjNUlXG7S6ZJP6pcCZuWeMryRfmCt4SBgqjUsFZBHu
+U2iPv+624W/Ov0jnpHi7TmHQY1veAvUEllnxXABMosWyrY2L8TPKIhi/5wWUtliH
+BWKJR5x4mS4tIrLUPPDB3tX/rATaX1MPO1x30UsYmj4PJg84j1o1mGdes1bKTTpb
+gwJF
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-CA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-CA.pem.certspec
new file mode 100644
index 000000000..5250cc4a8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-CA.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-SA-CA
+extension:extKeyUsage:serverAuth,clientAuth
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-OCSP.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-OCSP.pem
new file mode 100644
index 000000000..926ccbe8e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-OCSP.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0TCCAbugAwIBAgIUF5x+VY327TZW9Rb4sP1wubzN60kwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBUxEzARBgNVBAMMCmVlLVNBLU9DU1AwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjITAfMB0GA1UdJQQWMBQG
+CCsGAQUFBwMBBggrBgEFBQcDCTALBgkqhkiG9w0BAQsDggEBAA4WIwtwzwVqvYG6
+zemLkiA2Po4Y3gjucKY9WY/ko7PjSRjZs4CM4JbIEtnWJUe0HlDyDRO7csv8WABo
+15lrLhqGW/1vPVVuUUnpsDTiJN4cJnF7CLpT2GO/teYvmt1ZY+n5JhfI4FDO6t2x
+xsIgRv7SFMqwKv5OiqGAFScgkYnsNZa9q+aqzGNcTJbJXvLuiTpdUL1vxoT2iiYo
+rO/tlCnqAG9ryCS7/ZbiNytd3aOV0+Y64Sh7NoFbs3RJMNqGUklTL8qpaHgO3v0c
+mzI9eh7683imPMZ7o7EeEOHix0M/6G7fFP7XF46ww6skQKfPqhPtoGoxN0/zpJWI
+7VMlXFA=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-OCSP.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-OCSP.pem.certspec
new file mode 100644
index 000000000..3b3eff9ae
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-OCSP.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-SA-OCSP
+extension:extKeyUsage:serverAuth,OCSPSigning
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-nsSGC.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-nsSGC.pem
new file mode 100644
index 000000000..177e17a7f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-nsSGC.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAb2gAwIBAgIUO/vVDR6vZfT1VN3k7nnF9d2DfaQwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2VlLVNBLW5zU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoyIwIDAeBgNVHSUEFzAV
+BggrBgEFBQcDAQYJYIZIAYb4QgQBMAsGCSqGSIb3DQEBCwOCAQEASeKD1BrhVCUv
+xLJWGeeMLQEmhC9jzTqPnkhVgdnQLVgbT6uGUBfb6thCqUwzkmqeSS3FwDlHrcuW
+mZtvRVjmTJtkXnqW0ItmrfmGBzcky6Yf1JFIKh4zcj2dWDX7Z2jL/G80M0Sd92gA
+dGNFK/7hJi8fK7GEwCsZuXrOF5V2tIJuBgSbadDP/BXkQQzdgJuymPlNNOQ2AUle
+UJdlMMeAHN46ElQmTJ5qFO/q+73RXx2X7GKh/zMjnFoZmOjv6kcHNVirLghwyn5A
+TzhUqyxYJIOesx2iToh3eounF5+ON+Tv24GZwHt8+LpywN4pbrvwdubiuTDgYBRC
+U8xbVBqd0Q==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-nsSGC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-nsSGC.pem.certspec
new file mode 100644
index 000000000..4c51425ce
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA-nsSGC.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-SA-nsSGC
+extension:extKeyUsage:serverAuth,nsSGC
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-SA.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA.pem
new file mode 100644
index 000000000..0b01c231a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUWQVaB4XyLq+dtmI7YOOKHIfM+xowCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBAxDjAMBgNVBAMMBWVlLVNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGc
+BptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzC
+a2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8Xg
+uEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK
+9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGP
+mRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxcwFTATBgNVHSUEDDAKBggrBgEF
+BQcDATALBgkqhkiG9w0BAQsDggEBAJqJhFqbvu7bF39gdfgp7zkiESuvlR1O9YNR
+42QE9E8vzXz7Yc3D6EDT54WmSRtbPa2y/LAeOQkUFV3vp5oFnHpU2dV5QH/p4clh
+oRG1hCr5sicPGTNpUuD/ZQrYAzFt/EtfdhNEq81lPS2GZ/mCy+mWE8jNBUnOVO2Y
+TtkAGJJafLEPghu5X4xQuxPJuPT1IycADL4bFxZUqRqoGUhcVeeGhUidz4I2q3rn
+qRvdMGbWXx4o343M4H3auQMiVAnUzkCZIyUN0n0T35JfckIwthZSffFF6oBy0RDJ
+bS/DoluvZ2NlJ8HIujgn0LOcJpKvxh7Yx1+5iBAM5+Hiwr0lQ6E=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-SA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA.pem.certspec
new file mode 100644
index 000000000..690f579af
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-SA.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-SA
+extension:extKeyUsage:serverAuth
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-CA.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-CA.pem
new file mode 100644
index 000000000..3e37a4a72
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-CA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsTCCAZugAwIBAgIUGaRSC/MYTPhfTuLxPkyLSJSeh8swCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HH
+Jajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOr
+IMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQ
+sVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLA
+dTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQE
+LL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQEL
+A4IBAQAVnl1ZyAFD1Q9U9sWZZ4xqSV22f4eG8ox79yvIIQkb1kj4hsopxeRjwVMU
+uND1/J1ravsvPoTy/fdawYFTmeW65XzzXypnreSxM4O0J6DTEE1UNrvj3yb8RaWh
+JNBbjmcGKHDfU4CpQ28vgWKgPH4NzVnqvy9mMzbfkwBInfK1z+6PT9iQGaw5w1UI
+ML0uD15Vd7Tcx2YjUdxCeqBnyS295soWVHRqI32HsPRVSG0Xt7JVzmVtrGS/dyPk
+jrTFh6gd9tdcQf7sKDOQpwIRo5iE/uvRndXUe1kE48RQnt+VMJupQWA03Gxu3a0P
+pCx8oCJbwVyfNk+p6obXosFOTrPG
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-CA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-CA.pem.certspec
new file mode 100644
index 000000000..670973930
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-CA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-CA
+subject:ee-int-CA
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-CA.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-CA.pem
new file mode 100644
index 000000000..0c95864e7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-CA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtzCCAaGgAwIBAgIUC68xy9MKWn3DXtSpmvrui0OyNr0wCwYJKoZIhvcNAQEL
+MBQxEjAQBgNVBAMMCWludC1TQS1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgw
+MjA1MDAwMDAwWjAXMRUwEwYDVQQDDAxlZS1pbnQtU0EtQ0EwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVo
+V2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p
+0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKk
+fbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZh
+W7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EI
+TjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZI
+hvcNAQELA4IBAQAVhShahEDEtyapGsFV7MvyyS9dqsmklEsnNAfJ+3yXb81yfYDG
+maQdAxVf/nNH71PYlOJOxTb9JeV26vf/mSFJOcwrODP5vMrUJdopo011QKsgm046
+qumgVfqPqPHhzpWBoQTNfQHpOV/iVKjBRZu+hD/x4LLlt4G8jVXwayG58t/d1/7Q
+Yv8a/2Dv+b07Q25EW0tgC8WraaP/KXPnbYArOu0sgWoRGMhc8fpswwSPas3xqrwz
+MtLDyfllAPZthvthTeeIUWdWClvpJqrBSqlTPBaS8AFCntaROQHNaAbzBCIdZZKg
+uZ9K9l3lUeUsDaNvVNuUKy5SXuno/wO/mr3Q
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-CA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-CA.pem.certspec
new file mode 100644
index 000000000..bd012ab71
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-CA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-SA-CA
+subject:ee-int-SA-CA
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-OCSP.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-OCSP.pem
new file mode 100644
index 000000000..6f6b17601
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-OCSP.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICuzCCAaWgAwIBAgIUARy1oarqQUJskMjRknN9jLVwVHQwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC2ludC1TQS1PQ1NQMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBkxFzAVBgNVBAMMDmVlLWludC1TQS1PQ1NQMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVK
+tOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7N
+Q/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39Zgsr
+sCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxs
+l62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYl
+nauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsG
+CSqGSIb3DQEBCwOCAQEASPYSc13k95EbV7+XmbxGacDe4LXWsy4P+oUsbNaSLtA/
+3ojBL3IaznMNZ3O7fVdQoPGtN7SxPKZtC44GLx8va6i32pXhwBp29mcc3vjAUwnl
+3GsJmw7/KP9C/KGZpf46ofw7ORDSs+32NB7QuKssh+FMpIYblDMVISX2fNqEQ5qB
+BktkgWh8EsgwbCLqHapgtfY2i/y1MtKBLxpIfCqx59iMCbA90ZvuELpA+2F6ZtR8
+7BvgC4zJ0YgkYrQApPjM00aFBAtjGEnsFBCRfpBGDIavqgfZoUlzh1jw9pTbF5ux
+1jX+GL3TOF3DG2qhylJh+w2Dogyyc7G2n7mvGIHfSQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-OCSP.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-OCSP.pem.certspec
new file mode 100644
index 000000000..2374d248f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-OCSP.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-SA-OCSP
+subject:ee-int-SA-OCSP
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-nsSGC.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-nsSGC.pem
new file mode 100644
index 000000000..4345d995c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-nsSGC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvTCCAaegAwIBAgIUTR//dWc2i2WpKXdEqfs1MgNXtVEwCwYJKoZIhvcNAQEL
+MBcxFTATBgNVBAMMDGludC1TQS1uc1NHQzAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
+MTgwMjA1MDAwMDAwWjAaMRgwFgYDVQQDDA9lZS1pbnQtU0EtbnNTR0MwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erk
+NUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwC
+fs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1m
+CyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTM
+HGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m
+1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEw
+CwYJKoZIhvcNAQELA4IBAQANPvkHZK6XUFOFNO0ZWRCOd8ZA4btmK1vttAOEMVWy
+GDVu2SoYDN6JW11wJr6L+V1P7cTF7e3+4sC0oS9LoTCPxie/6UAsyBUOQvl45dHw
+udRHJBPH04E8KWAa+odOK9McKgNt4oUA0DHm20eXDuISUEiV7R5N8XrpUweIgkFg
+iXJnOebZYV4lrIAC5CvFJ6ubUVdJ3rqQfrTMmJm4DYaS0zGEqglP/TGwLb9r9QdQ
+iJ0kktUZb3jiZYQAYZnSfGyiyy20bstt2WlXXTKKB5MBoDYW6mzL0NwwQOl6Nf6V
+UfglFYd9/E8bsa69VIlvGekfYcOdrAxsTMliayTIwKjG
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-nsSGC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-nsSGC.pem.certspec
new file mode 100644
index 000000000..6c3cb6473
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA-nsSGC.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-SA-nsSGC
+subject:ee-int-SA-nsSGC
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA.pem
new file mode 100644
index 000000000..97ea224d6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsTCCAZugAwIBAgIUczLFMp0nvVMly27yYa/Y6nG0kpEwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1TQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtU0EwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HH
+Jajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOr
+IMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQ
+sVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLA
+dTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQE
+LL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQEL
+A4IBAQCaGWv/SDygA6tYqxX/ild+418YW5bTpTzUoWppENrVQ7WRdLAz91/9dhPS
+Y9znou5eLMVa7IoOqaNG4x7DvefqenYhKGDyQbVahOalsVVYTke901B9I6ci9wfp
+wsKBYkLDzedlOCZVzU8aWH+uBi5ZOOD0T8NcTQE5x9T0gExu7rUOLa91+4h8NRTY
+m1yyX9zSpZuY65qveSX47FR0QbPAjq5KNyUcGuQSjEf9fUsVXEC9QAuaQHJEROR2
+CKzbaqtRlLqv89B9OKVsbdstLTW/L7tRTQNpkjH2lLgxfGBPDy8eHSpVW/WvBKlu
+/WxDnqx2W8TrJKA/RIQ56MeaOP+b
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA.pem.certspec
new file mode 100644
index 000000000..72ddb78df
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-SA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-SA
+subject:ee-int-SA
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-old.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-old.pem
new file mode 100644
index 000000000..703d5b29b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-old.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvzCCAamgAwIBAgIUG7btAHXGerwL88Jd7sb8IkeFKBkwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDWludC1uc1NHQy1vbGQwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowGzEZMBcGA1UEAwwQZWUtaW50LW5zU0dDLW9sZDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ
+6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUk
+nAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N
+/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAG
+JMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd
+7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEA
+ATALBgkqhkiG9w0BAQsDggEBAA/82zxrEW1c/neIl0E5/KOr0NL/F4lAdN+WUTT+
+P2DSf8Ke0EKO9lgMZKDBptlPT/XzTvmzvT3tM8vjFdcOF+1QQtFqoQ2pwpg7lXTA
+2hh/gSNklJfWCSQkgVr07fCX0/ip7TM7R9pBhL+x5MSQxdF7xW9eFP8lE8dq3L93
+1iIApcexVSjb/MbGBr9rRe0LvdY5wRjbGPxCEyp/316CxXg29vWwYalW96CnZHnR
+SAl34xTEaLeHjC6eeDSt4Fna5obAEw/p8dcC6TnGkKHEcZ/wSRNU42K8kIR0Rjdh
+EyWRvajemwXDlKsLgRcWqN+nL8hn0O0yI9mKLxo6oQNsApA=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-old.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-old.pem.certspec
new file mode 100644
index 000000000..c8444d337
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-old.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-nsSGC-old
+subject:ee-int-nsSGC-old
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-older.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-older.pem
new file mode 100644
index 000000000..45bab52a7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-older.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwzCCAa2gAwIBAgIUV1Eo/pl5MBWjV8NHjvDSYjdoz9cwCwYJKoZIhvcNAQEL
+MBoxGDAWBgNVBAMMD2ludC1uc1NHQy1vbGRlcjAiGA8yMDE1MTEyODAwMDAwMFoY
+DzIwMTgwMjA1MDAwMDAwWjAdMRswGQYDVQQDDBJlZS1pbnQtbnNTR0Mtb2xkZXIw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAEwCwYJKoZIhvcNAQELA4IBAQCoka+kd2S/FnF34++D0mZ4xSeFqNU9ookP
+oKqeQp8wXUtemulTI0MKOFavJjzq82Vm1LJLoFf46lU3q6oTuH/ylj9VMJn9/Etm
+v+kJyjydlx1MVQUacQ+v+9QxwsYvt9KjgqSUDlwoh6BX8dKKFHgYKJJx7JyvyeHp
+5FfSlEEIFdwWb42bzx4a6Va3lA6svpWP5mDZOOwp6b9wP8Bw7WxXQgjYP8pOmwYy
+Q9inlnGCdTC2GhV5CNL+eq43eGdL/gAvQ1aCZPKovICxMzkv9f5Sx2nGcDUnqcJD
+kICrqJ6gjTm+Q86UOSxiIioVSDt2BZjbyhBj4wgjCzsM4zeMcx+l
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-older.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-older.pem.certspec
new file mode 100644
index 000000000..c5b12e8da
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-older.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-nsSGC-older
+subject:ee-int-nsSGC-older
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-recent.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-recent.pem
new file mode 100644
index 000000000..3bf0f2bac
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-recent.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUe35zCPUg4TWN0gQjqfNVjK8KFqgwCwYJKoZIhvcNAQEL
+MBsxGTAXBgNVBAMMEGludC1uc1NHQy1yZWNlbnQwIhgPMjAxNTExMjgwMDAwMDBa
+GA8yMDE4MDIwNTAwMDAwMFowHjEcMBoGA1UEAwwTZWUtaW50LW5zU0dDLXJlY2Vu
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogG
+NhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqn
+RYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHu
+p3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQ
+Lzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p
+47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo1
+7Y0CAwEAATALBgkqhkiG9w0BAQsDggEBAF2ltx1XJtzG/bhTsu/bo9qr3p9Um2Yr
+2aXMzX8GNR/wmxBHVhNjBMHzQeuDBbYOkssDXQThFn3qAvLixNkD3cFez5D2LG0o
+fR/Ftb7XDsEw6MdBNmjgrM1Sse3v6DOVKMcdoJ+HS7FZ4USbeJ0dkWvv4f1Secjk
+yo1mZx3nq9cw1qI5pnH95YncD8u2rzErWeZHpIRW7SxfabpPxhlUFFyywST11WEa
+bZa2H4h5oFBmE84gDteDjM8BA9PbuPkwqS7MmfvdPHT9mwH+ppln4Ays/v9HnjmU
+qRRyYP73/S8/J/N6DDXAQCJ3yWLIm08pFC0RS+mF729M0B0g4F52NpU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-recent.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-recent.pem.certspec
new file mode 100644
index 000000000..6e736adc0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-int-nsSGC-recent.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-nsSGC-recent
+subject:ee-int-nsSGC-recent
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-nsSGC.pem b/security/manager/ssl/tests/unit/test_cert_eku/ee-nsSGC.pem
new file mode 100644
index 000000000..6849a15ae
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-nsSGC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxjCCAbCgAwIBAgIUeS+Bwx6kFrNZMCbqJdx6V/Dd4pIwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBMxETAPBgNVBAMMCGVlLW5zU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4Ngf
+vbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTb
+uUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3S
+O8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR
+3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv
+5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxgwFjAUBgNVHSUEDTALBglg
+hkgBhvhCBAEwCwYJKoZIhvcNAQELA4IBAQA/aXkP4qYhXpfW4Vk+Y4L8ufv0/LzR
+VkObq/K9xdbt53X5i1cur+VmE8BQlaDTJ0lZ+efSvKZsBHLjLJWs7ghzBEQY0zW9
+bh56nwwEgv91GMUJeb4krm8Pe0N5b15QrtQE4nFCHQs9Bkkhmhm9Dormw20fa1A/
+82ADTMMhTen4bJYpKbcWP9z0pv3wattrfKpsNHYprgV7eqznjAsr2hClc089CsFl
+msc+2gbiz+yk2TO7naaWhuNc5p8zevPb5m4UzOVKqnXqGdjJ2ev8j5N7LYAB6IJh
+68vieEO/P1ovkSUUmR69jaI0eIiWEfYqbW4v9d8/pMutmyeOZh3RT5u+
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/ee-nsSGC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/ee-nsSGC.pem.certspec
new file mode 100644
index 000000000..43d58ab6d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/ee-nsSGC.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-nsSGC
+extension:extKeyUsage:nsSGC
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-CA.pem b/security/manager/ssl/tests/unit/test_cert_eku/int-CA.pem
new file mode 100644
index 000000000..67125227d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-CA.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0TCCAbugAwIBAgIUafQ18/NBMv9lR5wdiAdnVzIZvWkwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBExDzANBgNVBAMMBmludC1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMlMCMwDAYDVR0TBAUwAwEB/zAT
+BgNVHSUEDDAKBggrBgEFBQcDAjALBgkqhkiG9w0BAQsDggEBAHljHawI2YeWnSsd
+ERqVkdmQKh+VKosuBp7RwiEZcLk8lRMtmgIkrCShc1HNsGW2X1QDk3btC0GRXXO4
+UFmpDFrcnblhCfkD73Gann6uk/1P7J7B+cG9HOrw9e8keazclz/FXgPXcTr061SO
+fhJaPB6/6sYWw2f6o6lBg5uGZKrJtZiEjEqUAI0/eh7QJ0N8jdG8kzgOAFsvaS6C
+LWtDAr1HwTRitb6AFeI+jP/hhAPQkuxbts1RmJUFQdTBmM/GwyT1LwBUpxgXW0xM
+ta/7BP7TaBtsZx9N3hH7L4ADMU3E0rb7yYtN7RF40eRXB9RvnYy4Tn4YTIsaZFnR
+xC6WzJ4=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-CA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/int-CA.pem.certspec
new file mode 100644
index 000000000..e5bc18198
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-CA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-CA
+extension:basicConstraints:cA,
+extension:extKeyUsage:clientAuth
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-SA-CA.pem b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-CA.pem
new file mode 100644
index 000000000..aaa392db5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-CA.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3jCCAcigAwIBAgIUAepQZqbEvSiQSE1cR9U5YmUbq48wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBQxEjAQBgNVBAMMCWludC1TQS1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODY
+H72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk
+27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A9
+0jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMM
+kd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaL
+L+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMvMC0wDAYDVR0TBAUwAwEB
+/zAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwCwYJKoZIhvcNAQELA4IB
+AQAl23nZRqJVVi1D4CrC3FPJyitFtZF+ss85jSvtNIH1DK0tZHYpTqouVdBCVyz3
+31vb5Yq+33V0Lg4LS39Q7gYz3ofcyCCuTpSvYL6dV0EEbiYX6AVwFXXD8jeV16/V
+7QFI/pae7sjr/2v2WJVmupdt1lT2hWVd/rilYBZPgri11QSiZVJP6qmf5AcA9dkg
+pyZ5su1SwOaFN0XdrwvnW1+SSFYQtOWTfffr9ctMAXF0uGv/duGHLxPt2MIXvwWg
+83che74+n8mYuZNUCTOh+BG/bR572KWDFY/hwBDpWXJUmFh5GtF/z29NDnY9IFyQ
+HyE5qtltjnv0D2vSA2f7eoyH
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-SA-CA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-CA.pem.certspec
new file mode 100644
index 000000000..94e9a42d4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-CA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-SA-CA
+extension:basicConstraints:cA,
+extension:extKeyUsage:serverAuth,clientAuth
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-SA-OCSP.pem b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-OCSP.pem
new file mode 100644
index 000000000..e487b8ef6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-OCSP.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4DCCAcqgAwIBAgIUY0Zp7/A39C/kccD4uV3b1yP2K1swCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2ludC1TQS1PQ1NQMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoy8wLTAMBgNVHRMEBTAD
+AQH/MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDCTALBgkqhkiG9w0BAQsD
+ggEBAEwVcLGSPMdCLiXXgXqDdEU81Ti3bfp3pEzI+g5X6H27cbLwNMb+DM1Qu6wt
+w8UpXCxP6i8F3XnrKZCdfJG7caDlDoylCPpXaVd37B4lPcnd2j1sfb3PwG4cp2x7
+Qv4ur3sjG3nVn3kSKgrTVCojyo876Iy/ZKQpQAtiggS4pG7ztRPIPOVIZHzNEUfQ
+RUpD9RFuoezM2aAPaTjTixKtIWjL1Fc+OCWHn4uAkPAnRuTm3SRIgVPREk2671oo
+9OAtXwaNsEn9+P6FBdV69BE68n2Tl6bv8scE0JvSBJg3NfCq7gZJ16rpQXW0fEGV
+ZqQiPT0JAJFYcK/l0ynVFZ4k9ZE=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-SA-OCSP.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-OCSP.pem.certspec
new file mode 100644
index 000000000..c38a640b9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-OCSP.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-SA-OCSP
+extension:basicConstraints:cA,
+extension:extKeyUsage:serverAuth,OCSPSigning
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-SA-nsSGC.pem b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-nsSGC.pem
new file mode 100644
index 000000000..29c734bb6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-nsSGC.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4jCCAcygAwIBAgIUUazTcP2+J+/snjciQqhPNClvzlAwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBcxFTATBgNVBAMMDGludC1TQS1uc1NHQzCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMwMC4wDAYDVR0TBAUw
+AwEB/zAeBgNVHSUEFzAVBggrBgEFBQcDAQYJYIZIAYb4QgQBMAsGCSqGSIb3DQEB
+CwOCAQEArh/GECvDvQVnv2UdZUx5nL1VTxr1GS30/e83nTmTrIeN+lV9M4UR8UL5
+ecEl9eDBxGnTAAlvK1PupSQgZJzzDFD2tkqMWNrKwMMHTt4zPCx2gA6KBQcp9Dsj
+ThB2jUAwcK24eXAcfEj2XRROhoKkKScd2Qo9FsFBl7r91KWTlHTsdkdT3wSJ73DP
+jYn4S7Y82OiNgIY5KacH+L9VqY1MHI1TDlMb+MBYDniUbmpMMB0lE1EIt0oiu6XQ
+n20+81inwxonsMikHI0YGdttWPotm8Yu/PxvwIeiOYd8fOPZkzD5rhd5aJLmOoMk
+GuVcrNke+iBvK6Fc6A2uTj6t9CV6zg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-SA-nsSGC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-nsSGC.pem.certspec
new file mode 100644
index 000000000..c84201d87
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-SA-nsSGC.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-SA-nsSGC
+extension:basicConstraints:cA,
+extension:extKeyUsage:serverAuth,nsSGC
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-SA.pem b/security/manager/ssl/tests/unit/test_cert_eku/int-SA.pem
new file mode 100644
index 000000000..538b6d2ce
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-SA.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0TCCAbugAwIBAgIUfYQTgJQVjmkz6KfdBM+7rJ9TXLQwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBExDzANBgNVBAMMBmludC1TQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMlMCMwDAYDVR0TBAUwAwEB/zAT
+BgNVHSUEDDAKBggrBgEFBQcDATALBgkqhkiG9w0BAQsDggEBALnNW8RtP4S8LNYc
+fpYdeArseY6SkVXSiYLWb7kUVuhGcJPO11FVfU4SCVdYqz1f1+4bev41ao/K5/dn
+hs9koIzRFqErl7kP6Xi6jSwLKpl/rD3BH9waa7k57rJHrt6KCzOMICaIXQBPxzlg
+hZBp9BFeuOxb8lJjSWXbplgAsU4FhAHVbTUWw9BfjbTAyoIx9N4r3X8ah5TDLlUN
+NPp/aPKuC2jpRb9yEnOMvw8ziXmCjEFEIT8D+Z00OLOaCJ2dmsR6vWtE3qKwxFTG
+14zYiG6pqTUwrg9F/F0mi4AoRkCIqNbiHvvZGaVLTpgOOG0EZgLH9WXMf+30RsDD
++DinBfU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-SA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/int-SA.pem.certspec
new file mode 100644
index 000000000..74bec2b21
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-SA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-SA
+extension:basicConstraints:cA,
+extension:extKeyUsage:serverAuth
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-old.pem b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-old.pem
new file mode 100644
index 000000000..0d20e07ec
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-old.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2TCCAcOgAwIBAgIUbcXBg0y82WEm7Yor5jl0vYp6sLQwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTYwNzI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBgxFjAUBgNVBAMMDWludC1uc1NHQy1vbGQwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HH
+Jajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOr
+IMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQ
+sVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLA
+dTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQE
+LL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjJjAkMAwGA1UdEwQF
+MAMBAf8wFAYDVR0lBA0wCwYJYIZIAYb4QgQBMAsGCSqGSIb3DQEBCwOCAQEAM+vf
+k8pAexjnMg1N5zp/X53Q6CaDseUj3FWnO/prJiMSWa2pcE+09naIc2gR7YsuapRr
++7Z1cOrF7uKVRnSKHmmZHGr+/EtoUuhwtkMpcbaCL5061Of6Un8UnK5sAQTECUip
+CMChu0kX/qVlBiE/eJG2lrq8lycCdhjjjQjS0Fk1Jikh33/JeJCCay/pWOoiagv2
+ansOq+gUWiG55jTGT4b+0TdY70rLX7WDpliqieTfd7xVB0Zv4U41ydI/tcP5lo3g
+/X4szNbZNyu9dRmLjVqDS3lhGGnRPiDblxlKm6vafrsd3zk4vg+UJlrHPP1q94Bh
+Fbax9mimAkqXvI/F+A==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-old.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-old.pem.certspec
new file mode 100644
index 000000000..35f61671e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-old.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-nsSGC-old
+extension:basicConstraints:cA,
+extension:extKeyUsage:nsSGC
+validity:20160724-20160924
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-older.pem b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-older.pem
new file mode 100644
index 000000000..f42288896
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-older.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAcWgAwIBAgIUDUfr/LSKxxp6n1UoiDvmm9b4cCswCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUwNzI0MDAwMDAwWhgPMjAxNjA5MjQwMDAw
+MDBaMBoxGDAWBgNVBAMMD2ludC1uc1NHQy1vbGRlcjCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMmMCQwDAYDVR0T
+BAUwAwEB/zAUBgNVHSUEDTALBglghkgBhvhCBAEwCwYJKoZIhvcNAQELA4IBAQAY
+46wuAov03l8b+soIfL0TR+7LMwHnekiaa6M52nToHE8oDyH0NgFx4mMbdQYxKHvi
+xn9Lgp650JN0ofkJ2Z5lduakAW8n316+bfimkJVCHst7jhSEc7qWAb96kLabZD7U
+N+8cpelepAbfe8vpH043qon8tg9fYABZ4RrXCEQvhb+nHbNnW+GgnnnrtD7GM165
+krU12IDIOO/rQ04/vrKOa0p+Zv+oaLJMLhPPeXlQTno/bRY9VRq0oQej3iOyd6vH
+wfq2PUCmTeOziI8YO6V9Ddtc/TYPwh3yF0AtKFXsl9MZ3xrlD17pl1BsVdIGANQf
+qus1PdEkVZc8fRGBCJKv
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-older.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-older.pem.certspec
new file mode 100644
index 000000000..f7a870c0f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-older.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-nsSGC-older
+extension:basicConstraints:cA,
+extension:extKeyUsage:nsSGC
+validity:20150724-20160924
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-recent.pem b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-recent.pem
new file mode 100644
index 000000000..a2a6dfd89
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-recent.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAcagAwIBAgIUE3ByAD3ROipiblgZuY8BtAMhi6swCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTYwODI0MDAwMDAwWhgPMjAxNzA4MjQwMDAw
+MDBaMBsxGTAXBgNVBAMMEGludC1uc1NHQy1yZWNlbnQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjJjAkMAwGA1Ud
+EwQFMAMBAf8wFAYDVR0lBA0wCwYJYIZIAYb4QgQBMAsGCSqGSIb3DQEBCwOCAQEA
+VPtQzyrS2EDjCT6V7b8KKEXAyl70GZe1rD2s/xS+Uj43la5vVQyB0PtabDTh4lVy
+hut0M0o3E9hQ39qswMOcmNQdTnXTrhUzJPuGUnXxb8Jxjv+FR6+M8cmcdIlnFfXF
+HQXwVn9LzvxwlbMatY3xQXrKQz6RzrMQ0V6tYKZZSHZvecy1iCbr2CIpU7I3D2aR
+NatT1GYjaU+8u2afAoYKd+euB7pVMew7JuAxJ13iM1IMWyMil+/36ZOv5MBSSWRU
+7ts0vZeH5Ne0kEYf5uOY7LWaw7fCo7HKiyOcB0xSvQL1BvjTf6NqbCO4a29BYQF6
+Ieyp6ItfrpIuwcpfyq1d7A==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-recent.pem.certspec b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-recent.pem.certspec
new file mode 100644
index 000000000..f421ddc1a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/int-nsSGC-recent.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-nsSGC-recent
+extension:basicConstraints:cA,
+extension:extKeyUsage:nsSGC
+validity:20160824-20170824
diff --git a/security/manager/ssl/tests/unit/test_cert_eku/moz.build b/security/manager/ssl/tests/unit/test_cert_eku/moz.build
new file mode 100644
index 000000000..7a4124e02
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_eku/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca.pem',
+# 'ee-CA.pem',
+# 'ee-SA-CA.pem',
+# 'ee-SA-OCSP.pem',
+# 'ee-SA-nsSGC.pem',
+# 'ee-SA.pem',
+# 'ee-int-CA.pem',
+# 'ee-int-SA-CA.pem',
+# 'ee-int-SA-OCSP.pem',
+# 'ee-int-SA-nsSGC.pem',
+# 'ee-int-SA.pem',
+# 'ee-int-nsSGC-old.pem',
+# 'ee-int-nsSGC-older.pem',
+# 'ee-int-nsSGC-recent.pem',
+# 'ee-nsSGC.pem',
+# 'int-CA.pem',
+# 'int-SA-CA.pem',
+# 'int-SA-OCSP.pem',
+# 'int-SA-nsSGC.pem',
+# 'int-SA.pem',
+# 'int-nsSGC-old.pem',
+# 'int-nsSGC-older.pem',
+# 'int-nsSGC-recent.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null.js b/security/manager/ssl/tests/unit/test_cert_embedded_null.js
new file mode 100644
index 000000000..4e4767560
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null.js
@@ -0,0 +1,38 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Tests that a certificate with a clever subject common name like
+// 'www.bank1.com[NUL]www.bad-guy.com' (where [NUL] is a single byte with
+// value 0) will not be treated as valid for www.bank1.com.
+// Includes a similar test case but for the subject alternative name extension.
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function do_testcase(certname, checkCommonName) {
+ let cert = constructCertFromFile(`test_cert_embedded_null/${certname}.pem`);
+ // Where applicable, check that the testcase is meaningful (i.e. that the
+ // certificate's subject common name has an embedded NUL in it).
+ if (checkCommonName) {
+ equal(cert.commonName, "www.bank1.com\\00www.bad-guy.com",
+ "certificate subject common name should have an embedded NUL byte");
+ }
+ checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN,
+ certificateUsageSSLServer, {}, "www.bank1.com");
+ checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN,
+ certificateUsageSSLServer, {}, "www.bad-guy.com");
+}
+
+function run_test() {
+ addCertFromFile(certdb, "test_cert_embedded_null/ca.pem", "CTu,,");
+
+ do_testcase("embeddedNull", true);
+ do_testcase("embeddedNullSAN", false);
+ do_testcase("embeddedNullCNAndSAN", true);
+ do_testcase("embeddedNullSAN2", false);
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem b/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem
new file mode 100644
index 000000000..1a18e2bf0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUL5zykZEc2ro5d6th43aWGfm735cwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
+DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHPYBjNnv//Ssc8Elepb8SWIXRdahKbL
+/dcPoMR+7yhJVaelUaxdwUytJWJAGdkkuv+P+G4b82RVYEXT+9k1S/aAfByFyR9q
+vS7POfdy/ZPfGTXltlnmYX/84a6QeYQa4Nl4JpIOXBCesLxmErBhczka6D26iqsz
+GeseKRSjVPgF3mXc2CRGZnTDRhUmd7wOABLmj7GtuFvOm96363M3IUByMohvoj1G
+dic3s5D0seXwTKnEc5B27lJt7Q0oIXEldL+UW8Mo1hfGWQeXzqTZbpOVLnVWvHBH
+H8yYs5hyH01qFJZbztJ1JJ3F2NpYLlr4P5I6fW2e9w5MG/VMQRU3wzQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem.certspec
new file mode 100644
index 000000000..6660f5d47
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem
new file mode 100644
index 000000000..7e846ed83
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwTCCAaugAwIBAgIUPzul3x9eLLB//njMNwnlOFqHCCcwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMCgxJjAkBgNVBAMMHXd3dy5iYW5rMS5jb20Ad3d3LmJhZC1ndXkuY29tMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08
+E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc
+1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAP
+DY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQ
+gAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqV
+YR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQID
+AQABMAsGCSqGSIb3DQEBCwOCAQEAbPT/bQi9B1F3k6Xa8b8yG56+KqssBjA/BQXp
+TbXHd2xwtlbpiCzA6pI/MTiTzR4y9dj7mD9kj/vcD4GEcrhe0IBJ/juim68EhbFM
+QQ5KRSITj51+hPAvK2E79AAvyCweRndxqvlAak9PfJX4zEUoo07pQ6qE6tDaLgCN
+dZ3hV0syAE29Gtj86ew8Z6fPOoA3Sd9xw9wqULdZk+XG4rWMQzuoXLR1OHzvHQs0
+sP1mMhTCRdXwD7xmbhY4Zhsey2tagADlLTIVCKZDWdTjwVACxuRkvqX9Iy1/W16Y
+f0K7j6omyj/ziRnrNfKkCAl/REuTCrAWV8M0o/854RwFCg6UEQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem.certspec
new file mode 100644
index 000000000..d1a32349a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:www.bank1.com\0www.bad-guy.com
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem
new file mode 100644
index 000000000..af4572d66
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7zCCAdmgAwIBAgIUX4OgrL3nEzXRzIfkNVd6fxsHvDcwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMCgxJjAkBgNVBAMMHXd3dy5iYW5rMS5jb20Ad3d3LmJhZC1ndXkuY29tMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08
+E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc
+1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAP
+DY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQ
+gAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqV
+YR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQID
+AQABoywwKjAoBgNVHREEITAfgh13d3cuYmFuazEuY29tAHd3dy5iYWQtZ3V5LmNv
+bTALBgkqhkiG9w0BAQsDggEBAKyN7qvmdcryAaKPxDKEpIEg7emhEigt7sNYq41I
+ZteYbYRSsJDIKs+n7TmaQ2Qtxdb3KNJGxU5jd6nBqh+WZrhjWJjZNFP9VT29pZpf
+H+D2yHvJV8It5OU86IaAjNxEopGJABXf1EwP3RSsmbI8PFrSLzzkV7qY+kgMbVLX
+Txswvv5nITzWu4BXmznusDf/xdY9kR9EK2KZo9fCbBgzqoCFB9dtPsZmzDSHerYi
+o0Mh33JwVgDLi05yd/RVyi3TYjaSNDA0TcnyPirKPJDDFzHWyqP/Yd0G6WI0Ke9G
+ka0v/vIh+cLqMozHPO4Ks1MfRqWqsbCTRYnlqOW0iYZghR8=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem.certspec
new file mode 100644
index 000000000..1029d6cdd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:www.bank1.com\0www.bad-guy.com
+extension:subjectAlternativeName:www.bank1.com\0www.bad-guy.com
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem
new file mode 100644
index 000000000..b0e05c6b9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5TCCAc+gAwIBAgIUGytwo7XSf4hWQWGePWi/WuFru/4wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMB4xHDAaBgNVBAMME2VtYmVkZGVkIE5VTCBpbiBTQU4wggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVo
+V2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p
+0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKk
+fbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZh
+W7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EI
+TjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjLDAqMCgG
+A1UdEQQhMB+CHXd3dy5iYW5rMS5jb20Ad3d3LmJhZC1ndXkuY29tMAsGCSqGSIb3
+DQEBCwOCAQEAWYQZ0QVwm0rjYpWNZqD6gDOYFOo/DdaGgRWYF9wSueJaSqIY7Jwm
+GAwwDBqcyCZdqssZKtDogt2lgwG8Rt1uqQ46I/JNvFvNwujwHNtrh8FO/sKSs+v1
+I1+b9S7D8Kg6RrKcUXA2cUU+qPlt4J+WXlvVxgUmruJXdJqplerxs8gk9hic0Bc7
+Zo30xzScfp0WpqdMxnc2FupW3y5MfgGpf/98u1gvdS1gnOdyZWAfhtcPEyb+PSOU
+4nmtkDH83QKJ1QvHbjI2XqD57Ge3c+T2f4LpWw5+zn7K9kExNHsoPV4yqd87K5Ty
+j4keE9h15zF/CUBF37wYfK9hBxxis+SW4A==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem.certspec
new file mode 100644
index 000000000..f224888ee
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:embedded NUL in SAN
+extension:subjectAlternativeName:www.bank1.com\0www.bad-guy.com
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem
new file mode 100644
index 000000000..b0672452f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6jCCAdSgAwIBAgIULbAjgyFkKYWb9Jl7dYe85tJgrq4wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2JhZC1ndXkuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozkwNzA1BgNVHREELjAs
+ggtiYWQtZ3V5LmNvbYIdd3d3LmJhbmsxLmNvbQB3d3cuYmFkLWd1eS5jb20wCwYJ
+KoZIhvcNAQELA4IBAQCemALDXRTm0lPpWiP1xCJVhCA1SqhCMNRgwZtxClRr10FC
+l5qkR4Fy9RZoWSOO/obSid1tT6AKly8e49tUHaJ7b1KBPe0EAGPgNJPmlDafHFrC
+wSOsIoiboLrrs9R+xWL0/7nruo2OqlpAbOajBnfvJ65t6JGWPVlSzvbXigwgL2EE
+AfQQydWy5UDCW1/pQuAjd8WD3ZEz9IAgdM49zEeDss6a5t6RE4U+/acSTJBbZOOV
+q7k2tCKEWQwHhWWWQSeiS+JW4PXYXy/N8DYABPHaZ6nK1HoBRCnT2TMvKeDwhv0o
+Cw/NE/ytz6/STzYNV203SnVzmpkuvE4oG0IbGrZd
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem.certspec
new file mode 100644
index 000000000..d352d034b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:bad-guy.com
+extension:subjectAlternativeName:bad-guy.com,www.bank1.com\0www.bad-guy.com
diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/moz.build b/security/manager/ssl/tests/unit/test_cert_embedded_null/moz.build
new file mode 100644
index 000000000..9e2821867
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca.pem',
+# 'embeddedNull.pem',
+# 'embeddedNullCNAndSAN.pem',
+# 'embeddedNullSAN.pem',
+# 'embeddedNullSAN2.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot.js b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot.js
new file mode 100644
index 000000000..148ee4b27
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot.js
@@ -0,0 +1,71 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Tests that nsIX509Cert.isBuiltInRoot works as expected.
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+// This is a certificate that (currently) ships with the platform.
+// It should be considered a built-in root.
+const sGeoTrustBase64 = "" +
+ "MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL" +
+ "MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj" +
+ "KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2" +
+ "MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0" +
+ "eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV" +
+ "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw" +
+ "NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV" +
+ "BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH" +
+ "MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL" +
+ "So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal" +
+ "tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO" +
+ "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG" +
+ "CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT" +
+ "qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz" +
+ "rD6ogRLQy7rQkgu2npaqBA+K";
+
+
+// This is a certificate that does not ship with the platform.
+// It should not be considered a built-in root.
+const sLetsEncryptBase64 = "" +
+ "MIIEqDCCA5CgAwIBAgIRAJgT9HUT5XULQ+dDHpceRL0wDQYJKoZIhvcNAQELBQAw" +
+ "PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD" +
+ "Ew5EU1QgUm9vdCBDQSBYMzAeFw0xNTEwMTkyMjMzMzZaFw0yMDEwMTkyMjMzMzZa" +
+ "MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD" +
+ "ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMTCCASIwDQYJKoZIhvcNAQEBBQAD" +
+ "ggEPADCCAQoCggEBAJzTDPBa5S5Ht3JdN4OzaGMw6tc1Jhkl4b2+NfFwki+3uEtB" +
+ "BaupnjUIWOyxKsRohwuj43Xk5vOnYnG6eYFgH9eRmp/z0HhncchpDpWRz/7mmelg" +
+ "PEjMfspNdxIknUcbWuu57B43ABycrHunBerOSuu9QeU2mLnL/W08lmjfIypCkAyG" +
+ "dGfIf6WauFJhFBM/ZemCh8vb+g5W9oaJ84U/l4avsNwa72sNlRZ9xCugZbKZBDZ1" +
+ "gGusSvMbkEl4L6KWTyogJSkExnTA0DHNjzE4lRa6qDO4Q/GxH8Mwf6J5MRM9LTb4" +
+ "4/zyM2q5OTHFr8SNDR1kFjOq+oQpttQLwNh9w5MCAwEAAaOCAZIwggGOMBIGA1Ud" +
+ "EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMH8GCCsGAQUFBwEBBHMwcTAy" +
+ "BggrBgEFBQcwAYYmaHR0cDovL2lzcmcudHJ1c3RpZC5vY3NwLmlkZW50cnVzdC5j" +
+ "b20wOwYIKwYBBQUHMAKGL2h0dHA6Ly9hcHBzLmlkZW50cnVzdC5jb20vcm9vdHMv" +
+ "ZHN0cm9vdGNheDMucDdjMB8GA1UdIwQYMBaAFMSnsaR7LHH62+FLkHX/xBVghYkQ" +
+ "MFQGA1UdIARNMEswCAYGZ4EMAQIBMD8GCysGAQQBgt8TAQEBMDAwLgYIKwYBBQUH" +
+ "AgEWImh0dHA6Ly9jcHMucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcwPAYDVR0fBDUw" +
+ "MzAxoC+gLYYraHR0cDovL2NybC5pZGVudHJ1c3QuY29tL0RTVFJPT1RDQVgzQ1JM" +
+ "LmNybDATBgNVHR4EDDAKoQgwBoIELm1pbDAdBgNVHQ4EFgQUqEpqYwR93brm0Tm3" +
+ "pkVl7/Oo7KEwDQYJKoZIhvcNAQELBQADggEBANHIIkus7+MJiZZQsY14cCoBG1hd" +
+ "v0J20/FyWo5ppnfjL78S2k4s2GLRJ7iD9ZDKErndvbNFGcsW+9kKK/TnY21hp4Dd" +
+ "ITv8S9ZYQ7oaoqs7HwhEMY9sibED4aXw09xrJZTC9zK1uIfW6t5dHQjuOWv+HHoW" +
+ "ZnupyxpsEUlEaFb+/SCI4KCSBdAsYxAcsHYI5xxEI4LutHp6s3OT2FuO90WfdsIk" +
+ "6q78OMSdn875bNjdBYAqxUp2/LEIHfDBkLoQz0hFJmwAbYahqKaLn73PAAm1X2kj" +
+ "f1w8DdnkabOLGeOVcj9LQ+s67vBykx4anTjURkbqZslUEUsn2k5xeua2zUk=";
+
+function run_test() {
+ let builtInCert = certdb.constructX509FromBase64(sGeoTrustBase64);
+ ok(builtInCert, "should be able to decode base-64 of built-in cert");
+ ok(builtInCert.isBuiltInRoot, "cert should be considered built-in");
+
+ let notBuiltInCert = certdb.constructX509FromBase64(sLetsEncryptBase64);
+ ok(notBuiltInCert, "should be able to decode base-64 of built-in cert");
+ ok(!notBuiltInCert.isBuiltInRoot, "cert should not be considered built-in");
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload.js b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload.js
new file mode 100644
index 000000000..b17c592ee
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload.js
@@ -0,0 +1,123 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Tests that nsIX509Cert.isBuiltInRoot works as expected. Differs from
+// test_cert_isBuiltInRoot.js in that this test uses a preexisting NSS
+// certificate DB that already contains some of the certificates in question.
+//
+// To create the necessary preexisting files, obtain the "GeoTrust Primary
+// Certification Authority - G2" certificate and the "Let's Encrypt Authority
+// X1" certificate (copied below for reference) and perform the following steps:
+//
+// `certutil -d . -N` (use an empty password)
+// `certutil -d . -A -n "GeoTrust Primary Certification Authority - G2" -t ,, \
+// -a -i GeoTrust.pem`
+// `certutil -d . -A -n "Let's Encrypt Authority X1" -t ,, -a \
+// -i LetsEncrypt.pem`
+//
+// This should create cert8.db and key3.db files for use on non-Android
+// platforms. Perform the same steps with "sql:." as the argument to the "-d"
+// flag to create cert9.db and key4.db for use with Android.
+//
+// (The crucial property of the first certificate is that it is a built-in trust
+// anchor, so any replacement must also have this property. The second
+// certificate is not a built-in trust anchor, so any replacement must not be a
+// built-in trust anchor.)
+//
+// GeoTrust Primary Certification Authority - G2:
+// -----BEGIN CERTIFICATE-----
+// MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
+// MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
+// KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
+// MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+// eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
+// BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
+// NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
+// BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+// MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
+// So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
+// tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+// BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
+// CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
+// qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
+// rD6ogRLQy7rQkgu2npaqBA+K
+// -----END CERTIFICATE-----
+//
+// Let's Encrypt Authority X1:
+// -----BEGIN CERTIFICATE-----
+// MIIEqDCCA5CgAwIBAgIRAJgT9HUT5XULQ+dDHpceRL0wDQYJKoZIhvcNAQELBQAw
+// PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+// Ew5EU1QgUm9vdCBDQSBYMzAeFw0xNTEwMTkyMjMzMzZaFw0yMDEwMTkyMjMzMzZa
+// MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+// ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMTCCASIwDQYJKoZIhvcNAQEBBQAD
+// ggEPADCCAQoCggEBAJzTDPBa5S5Ht3JdN4OzaGMw6tc1Jhkl4b2+NfFwki+3uEtB
+// BaupnjUIWOyxKsRohwuj43Xk5vOnYnG6eYFgH9eRmp/z0HhncchpDpWRz/7mmelg
+// PEjMfspNdxIknUcbWuu57B43ABycrHunBerOSuu9QeU2mLnL/W08lmjfIypCkAyG
+// dGfIf6WauFJhFBM/ZemCh8vb+g5W9oaJ84U/l4avsNwa72sNlRZ9xCugZbKZBDZ1
+// gGusSvMbkEl4L6KWTyogJSkExnTA0DHNjzE4lRa6qDO4Q/GxH8Mwf6J5MRM9LTb4
+// 4/zyM2q5OTHFr8SNDR1kFjOq+oQpttQLwNh9w5MCAwEAAaOCAZIwggGOMBIGA1Ud
+// EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMH8GCCsGAQUFBwEBBHMwcTAy
+// BggrBgEFBQcwAYYmaHR0cDovL2lzcmcudHJ1c3RpZC5vY3NwLmlkZW50cnVzdC5j
+// b20wOwYIKwYBBQUHMAKGL2h0dHA6Ly9hcHBzLmlkZW50cnVzdC5jb20vcm9vdHMv
+// ZHN0cm9vdGNheDMucDdjMB8GA1UdIwQYMBaAFMSnsaR7LHH62+FLkHX/xBVghYkQ
+// MFQGA1UdIARNMEswCAYGZ4EMAQIBMD8GCysGAQQBgt8TAQEBMDAwLgYIKwYBBQUH
+// AgEWImh0dHA6Ly9jcHMucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcwPAYDVR0fBDUw
+// MzAxoC+gLYYraHR0cDovL2NybC5pZGVudHJ1c3QuY29tL0RTVFJPT1RDQVgzQ1JM
+// LmNybDATBgNVHR4EDDAKoQgwBoIELm1pbDAdBgNVHQ4EFgQUqEpqYwR93brm0Tm3
+// pkVl7/Oo7KEwDQYJKoZIhvcNAQELBQADggEBANHIIkus7+MJiZZQsY14cCoBG1hd
+// v0J20/FyWo5ppnfjL78S2k4s2GLRJ7iD9ZDKErndvbNFGcsW+9kKK/TnY21hp4Dd
+// ITv8S9ZYQ7oaoqs7HwhEMY9sibED4aXw09xrJZTC9zK1uIfW6t5dHQjuOWv+HHoW
+// ZnupyxpsEUlEaFb+/SCI4KCSBdAsYxAcsHYI5xxEI4LutHp6s3OT2FuO90WfdsIk
+// 6q78OMSdn875bNjdBYAqxUp2/LEIHfDBkLoQz0hFJmwAbYahqKaLn73PAAm1X2kj
+// f1w8DdnkabOLGeOVcj9LQ+s67vBykx4anTjURkbqZslUEUsn2k5xeua2zUk=
+// -----END CERTIFICATE-----
+
+"use strict";
+
+function run_test() {
+ const isAndroid = AppConstants.platform == "android";
+ const certDBName = isAndroid ? "cert9.db" : "cert8.db";
+ const keyDBName = isAndroid ? "key4.db" : "key3.db";
+ let profile = do_get_profile();
+ let certDBFile = do_get_file(`test_cert_isBuiltInRoot_reload/${certDBName}`);
+ certDBFile.copyTo(profile, certDBName);
+ let keyDBFile = do_get_file(`test_cert_isBuiltInRoot_reload/${keyDBName}`);
+ keyDBFile.copyTo(profile, keyDBName);
+
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+ // This is a built-in root, but not one that was added to the preexisting
+ // certificate DB.
+ const veriSignCertDBKey = `AAAAAAAAAAAAAAAQAAAAzS+A/iOM
+ DiIPSGcSKJGHrLMwgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg
+ SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMx
+ KGMpIDIwMDcgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+ eTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0
+ aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0`;
+ let veriSignCert = certdb.findCertByDBKey(veriSignCertDBKey);
+ ok(veriSignCert, "Should be able to find VeriSign root");
+ ok(veriSignCert.isBuiltInRoot, "VeriSign root is a built-in");
+
+ // This is a built-in root. It was added to the preexisting certificate DB. It
+ // should still be considered a built-in.
+ const geoTrustCertDBKey = `AAAAAAAAAAAAAAAQAAAAmzyy9EgK
+ AOL+6yQ7XmA+w2swgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ
+ bmMuMTkwNwYDVQQLEzAoYykgMjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhv
+ cml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlm
+ aWNhdGlvbiBBdXRob3JpdHkgLSBHMg==`;
+ let geoTrustCert = certdb.findCertByDBKey(geoTrustCertDBKey);
+ ok(geoTrustCert, "Should be able to find GeoTrust root");
+ ok(geoTrustCert.isBuiltInRoot, "GeoTrust root is a built-in");
+
+ // This is not a built-in root. It was added to the preexisting certificate
+ // DB. It should not be considered a built-in root.
+ const letsEncryptCertDBKey = `AAAAAAAAAAAAAAARAAAAQQCYE
+ /R1E+V1C0PnQx6XHkS9MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRyd
+ XN0IENvLjEXMBUGA1UEAxMORFNUIFJvb3QgQ0EgWDM=`;
+ let letsEncryptCert = certdb.findCertByDBKey(letsEncryptCertDBKey);
+ ok(letsEncryptCert, "Should be able to find LetsEncrypt root");
+ ok(!letsEncryptCert.isBuiltInRoot, "LetsEncrypt root is not a built-in");
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/cert8.db b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/cert8.db
new file mode 100644
index 000000000..87abcf35a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/cert8.db
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/cert9.db b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/cert9.db
new file mode 100644
index 000000000..b4567566d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/cert9.db
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/key3.db b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/key3.db
new file mode 100644
index 000000000..37241a743
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/key3.db
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/key4.db b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/key4.db
new file mode 100644
index 000000000..ed8747112
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_isBuiltInRoot_reload/key4.db
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage.js b/security/manager/ssl/tests/unit/test_cert_keyUsage.js
new file mode 100644
index 000000000..dd6fc4274
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage.js
@@ -0,0 +1,57 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+var certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+const caList = [ "ca-no-keyUsage-extension", "ca-missing-keyCertSign",
+ "ca-all-usages" ];
+const eeList = [ "ee-no-keyUsage-extension", "ee-keyCertSign-only",
+ "ee-keyEncipherment-only", "ee-keyCertSign-and-keyEncipherment" ];
+
+const caUsage = [ certificateUsageSSLCA, certificateUsageVerifyCA ];
+const allEEUsages = [ certificateUsageSSLClient, certificateUsageSSLServer,
+ certificateUsageEmailSigner, certificateUsageEmailRecipient,
+ certificateUsageObjectSigner ];
+const serverEEUsages = [ certificateUsageSSLServer,
+ certificateUsageEmailRecipient ];
+
+const expectedUsagesMap = {
+ "ca-no-keyUsage-extension": caUsage,
+ "ca-missing-keyCertSign": [],
+ "ca-all-usages": caUsage,
+
+ "ee-no-keyUsage-extension-ca-no-keyUsage-extension": allEEUsages,
+ "ee-no-keyUsage-extension-ca-missing-keyCertSign": [],
+ "ee-no-keyUsage-extension-ca-all-usages": allEEUsages,
+
+ "ee-keyCertSign-only-ca-no-keyUsage-extension": [],
+ "ee-keyCertSign-only-ca-missing-keyCertSign": [],
+ "ee-keyCertSign-only-ca-all-usages": [],
+
+ "ee-keyEncipherment-only-ca-no-keyUsage-extension": serverEEUsages,
+ "ee-keyEncipherment-only-ca-missing-keyCertSign": [],
+ "ee-keyEncipherment-only-ca-all-usages": serverEEUsages,
+
+ "ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension": serverEEUsages,
+ "ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign": [],
+ "ee-keyCertSign-and-keyEncipherment-ca-all-usages": serverEEUsages,
+};
+
+add_task(function* () {
+ for (let ca of caList) {
+ addCertFromFile(certdb, "test_cert_keyUsage/" + ca + ".pem", "CTu,CTu,CTu");
+ let caCert = constructCertFromFile("test_cert_keyUsage/" + ca + ".pem");
+ yield asyncTestCertificateUsages(certdb, caCert, expectedUsagesMap[ca]);
+ for (let ee of eeList) {
+ let eeFullName = ee + "-" + ca;
+ let eeCert = constructCertFromFile("test_cert_keyUsage/" + eeFullName + ".pem");
+ yield asyncTestCertificateUsages(certdb, eeCert, expectedUsagesMap[eeFullName]);
+ }
+ }
+});
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem
new file mode 100644
index 000000000..68cfd91f3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAcWgAwIBAgIUdys2hGpJxVbK3B7BShZ/+fevEdwwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDWNhLWFsbC11c2FnZXMwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowGDEWMBQGA1UEAwwNY2EtYWxsLXVzYWdlczCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
+SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYL
+K7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwc
+bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
+JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMd
+MBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAf4wCwYJKoZIhvcNAQELA4IBAQB3
+PnTXfyK1lZATja9ooGeUFCvJlscLeOSqHoy2NfvZ8EgQYgRFwIyoqKnDvNxoc/tG
+5K4SItulTTK2rG9g5e9NCVrbUThj3AMevJn9YpY/MWc+e8bsLO+djeKPYGGtgOAo
+kj8O5jxoFPItElLIOC9yEQEM02AohkZu4AaoCL2RHsdYDGGqJJHNsjjpumtu5WWR
+/sz2+sxfbnxub+IMk2TgoN/1/OeyFJ/BHPPi3jjiwi/fY9mtBSpYltArZsWu9Moa
+qxqj0b62YfiiqbPPPMy3nqRtcnta8GvKB7j51ONbnwb/pE0Zaijeb286a2JOyItH
+6mpoeFIefyemcfMwFChc
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem.certspec
new file mode 100644
index 000000000..2ca523c74
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-all-usages.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca-all-usages
+subject:ca-all-usages
+extension:basicConstraints:cA,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem
new file mode 100644
index 000000000..b2f21337e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7TCCAdegAwIBAgIUNZz9C1mmhSFhZ3hsQHPCZYTR78owCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmNhLW1pc3Npbmcta2V5Q2VydFNpZ24wIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowITEfMB0GA1UEAwwWY2EtbWlzc2luZy1r
+ZXlDZXJ0U2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahE
+jhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1
+a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1p
+GrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW
+2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcO
+p2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJR
+xDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAfow
+CwYJKoZIhvcNAQELA4IBAQCigLN4JNjaNQUV2oR8T/hBi0oYuPHnNsdKOlC1RJXI
+ol12HE7fI9Yhdp25Nt48fxDu76e19nF+SBpE1hcnE8Bt9BLiyV0Na572f/lrLTx+
+sMDZ+Fq9+tAjagxJgmozXEoLPqDZDR0IlZzeNyqhcrSomqKie4AHxjaXKk32Kwip
+eJfPolWij8NTX+M8JGiNVdMNakMhW4h7ulKvTDXjS1OhWd64tlPAuR/TZCZcfpz6
+Z08CgLcCUT928SG3Wz25FIZK9qiQkMEn7QNtIsF8SmAru0z7AEVuLFUnA71XP084
+hnAO09l608qaSq+xHq5GZ20mzP4ZllomqTKoBufBJ5J0
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem.certspec
new file mode 100644
index 000000000..26e0158eb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca-missing-keyCertSign
+subject:ca-missing-keyCertSign
+extension:basicConstraints:cA,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem
new file mode 100644
index 000000000..42b620d4e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5DCCAc6gAwIBAgIUJYmyGPLkKFkTp5JuDYcONVz01gowCwYJKoZIhvcNAQEL
+MCMxITAfBgNVBAMMGGNhLW5vLWtleVVzYWdlLWV4dGVuc2lvbjAiGA8yMDE1MTEy
+ODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAjMSEwHwYDVQQDDBhjYS1uby1rZXlV
+c2FnZS1leHRlbnNpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6
+iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr
+4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP
+8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OI
+Q+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ
+77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5J
+I/pyUcQx1QOs2hgKNe2NAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wCwYJKoZIhvcN
+AQELA4IBAQAEWzxixVODFWyBRURV4lePTqSy6lTKdiuClufSPtjVv6SVo1ZzfcYy
+71dMnGdQ0zaEAj/twPAYB6RG8Ri7gb+Iven3tYMGDAhAwwcrKQovphLlc5ccRkXw
+Sbw03aacwLoLbheElOBRYM7RInNV/K76SSUXkVVSKfB39nob0vL7je22UUR/1WjO
+6WOsYS6AsgLTzQLLhhDpHXUQVyfHHJ2EivwceGtJPmcHbBRognDybUK1lt/5hKqo
+zHUx7oa5qvAN1rZ/CtrEnSoaqY5BwmUqINalL0sAPwsd6FZM9G0kZaQpVjW3LgnY
+orFxjJ1rrHx8dMjEK0bUT3JcvwfA+Rqv
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem.certspec
new file mode 100644
index 000000000..d32e6a649
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-no-keyUsage-extension
+subject:ca-no-keyUsage-extension
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem
new file mode 100644
index 000000000..bdf9b0969
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4jCCAcygAwIBAgIUL2/9azGOStHNpzE5OuF9/eXyXgYwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDWNhLWFsbC11c2FnZXMwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowLTErMCkGA1UEAwwiZWUta2V5Q2VydFNpZ24tYW5kLWtl
+eUVuY2lwaGVybWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqI
+UahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvi
+r1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/x
+fq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD
+7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnv
+uRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj
++nJRxDHVA6zaGAo17Y0CAwEAAaMPMA0wCwYDVR0PBAQDAgIkMAsGCSqGSIb3DQEB
+CwOCAQEALRuAiMMiGyBra0dMzHR/98nFyiKriXYhp30XGU5hOb3nlumGuQoR6huq
+mUnOFD7PjIeLRfvSyT0HisAr3xR0Cx2AlM8XV8iyyT5S3Obe5z6St5+mLWEtiiBg
+BFPedxTz4M4npdKwEcc6fKhNknZdl/6QtbLWJbV9pqZWkNM+BoZNePo/vVl0ovKG
+7cF4eZilmXD10MzMOQbgZwUOqfP9L6r49mCs7xuJBEAkwE/pnfnFuJyE8bbfGUzY
+BkOj3ZnfOGk1sr8wSGK6LF7ArG2BUokOSstrjoT6v1Y5aXpCwEa/WECEpqphlAe9
+hloiRSezmE2LeOQS+bD0hQXfPvN6gw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem.certspec
new file mode 100644
index 000000000..0bb2721a3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-all-usages
+subject:ee-keyCertSign-and-keyEncipherment
+extension:keyUsage:keyEncipherment,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem
new file mode 100644
index 000000000..07af0afad
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6zCCAdWgAwIBAgIUZWIH141D/q0jpqLy24q/Z/V5Q24wCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmNhLW1pc3Npbmcta2V5Q2VydFNpZ24wIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowLTErMCkGA1UEAwwiZWUta2V5Q2VydFNp
+Z24tYW5kLWtleUVuY2lwaGVybWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMPMA0wCwYDVR0PBAQDAgIkMAsG
+CSqGSIb3DQEBCwOCAQEAYW3PJELJRWf/BpPb8gWUlGt0e3CIwjQqy/OsrXokniYE
+0wDGDQBBBwWUtZ+2Y9b9Buu83NfdYLdLO5fG1ZMSWudSpAvGNoFAbkbyMovnxMuA
+JdV36gfuyxl0nQ86iv3NgRaU7fDG2+wgukd6ugjX3KgKcgskZNS/qyyJNOCWl6M+
+JSC2Jpsz8ES9x8YsqblM/ERsrMXIWJd2r1/TZ0RT6yHIgkZcem0OyypJoMcfvwyA
+92OYV29xCMUjGahOPd3b2WeP1xfIDOQu06/W1u3Ut2locR8/irKPSkgADNFN72/7
+usjX3lxFPwbpTlj4ehDizqQM8/Zjd7TSuT5U8mGGUA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem.certspec
new file mode 100644
index 000000000..567ab0ce2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-missing-keyCertSign
+subject:ee-keyCertSign-and-keyEncipherment
+extension:keyUsage:keyEncipherment,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem
new file mode 100644
index 000000000..c5fafc299
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7TCCAdegAwIBAgIUTVrDE/LymICBYiBG+hIxeTNzILMwCwYJKoZIhvcNAQEL
+MCMxITAfBgNVBAMMGGNhLW5vLWtleVVzYWdlLWV4dGVuc2lvbjAiGA8yMDE1MTEy
+ODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAtMSswKQYDVQQDDCJlZS1rZXlDZXJ0
+U2lnbi1hbmQta2V5RW5jaXBoZXJtZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4Ngf
+vbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTb
+uUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3S
+O8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR
+3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv
+5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABow8wDTALBgNVHQ8EBAMCAiQw
+CwYJKoZIhvcNAQELA4IBAQB+abMJm5HdoKeMDzcqQpSLvSJKhbqrmujR8AKyHF9H
+DQyvFHARUL6GoOxvaILJCTUWGqobHdTFQjhWCOuYjtqQf1CXbgtXAUVL8/EOncnS
+UXcsti2r8h1WT/cDsXbnbmjloO1e/NEHHSK9Cm4zPSaoKQSYVSuXvKr8D9XZXvzj
+JJh0lkmVyhq79kw3aXWg75VQOllhQ7kplPjlbs4XAjWgmyCUJ2v/M5yDn9nNxnqG
+UyNLBEJkoaztUMZnEbx92cGD8FS721kaAZo5pslWx93+sHhHbwA9i5L1VG8UPX+T
+mb/DZkhekaPXrecmw4DZlhdbx0DiDbKpnzYM71YYbmUe
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem.certspec
new file mode 100644
index 000000000..c48ef6612
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-no-keyUsage-extension
+subject:ee-keyCertSign-and-keyEncipherment
+extension:keyUsage:keyEncipherment,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem
new file mode 100644
index 000000000..7f6c21909
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAb2gAwIBAgIUEYlPxi8Q+zUVKvxclDzrfiQ+PcEwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDWNhLWFsbC11c2FnZXMwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowHjEcMBoGA1UEAwwTZWUta2V5Q2VydFNpZ24tb25seTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
+PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
+HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
+Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
+EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
+lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
+AwEAAaMPMA0wCwYDVR0PBAQDAgIEMAsGCSqGSIb3DQEBCwOCAQEAcPa8SfjBKZd8
+qiQeFZSeBUWQB99PcTmJm87XvRH02p5pYzyIydHQ+Esv+kAOjOnZRbrVsd/2jvc+
+/Ae8HpJ/HcNjcSZPWsZ/qCQ/VAi1KkLtW4ETjECOUccCdY2hwBZ0l0XO6XZ3jutR
+GjOngZ91INAcrTv9eq1JKVyc9AxIkNid7vHQ7re1GWp01zBm2c8O8yw8HshTD7JC
+sD+2fiImj/nRsUZT9FPKRh6e1231ZQt4k1IF6Hfrke6vGnHGsOKcISwATMaidk28
+fb+UOopqL+LCxyKXjuNG7jx6EPLTaoN4zDQ3/ZBYAcscdoykzzMHMn7dgqUGgPxu
+kjrUn+ycag==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem.certspec
new file mode 100644
index 000000000..c495ca6d0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-all-usages.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-all-usages
+subject:ee-keyCertSign-only
+extension:keyUsage:keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem
new file mode 100644
index 000000000..6a3e4ee0e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAcagAwIBAgIUG3wZGBaOAqM35Kdlf4GoCOK353owCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmNhLW1pc3Npbmcta2V5Q2VydFNpZ24wIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowHjEcMBoGA1UEAwwTZWUta2V5Q2VydFNp
+Z24tb25seTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbW
+Qf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pk
+cQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHT
+AjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3
+ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jh
+s3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHV
+A6zaGAo17Y0CAwEAAaMPMA0wCwYDVR0PBAQDAgIEMAsGCSqGSIb3DQEBCwOCAQEA
+SeCJZFpmZUB53Cdu+/E8VarNp6jgZVf9KwOP3ihTWkvm7lRtlde8N5aTOP4cfrLp
+se8Xh+ODEo3oNYY9WfvXigDKC1zMc+7+flx53TesO7SUVK5FASCoP5MfVWh+J+4k
+dF6mbtXTOWkrIGSTmkjkGu7LmHYu8RVDagu3UU2zkFwZ/XruUB9ya9ABL6Bx5Th2
+KNcOVqTzdPYi9Uthz/imXbc5xBf6R47CuDu72zOoJJv4mLj6O1Qu3c5S1vrs3/l8
+HvoKu5J+yZRWmneJRJaIcKNBNWoKVQd++r6LlRa5kKMwYUe1tysc/mstGadeJhQB
+kFqHtTynqrDY9dp4oPCXGQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem.certspec
new file mode 100644
index 000000000..23ddd0eb8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-missing-keyCertSign
+subject:ee-keyCertSign-only
+extension:keyUsage:keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem
new file mode 100644
index 000000000..0f4446e8c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3jCCAcigAwIBAgIUKfpiB0n/DY53n/8um9gvIXVTf7wwCwYJKoZIhvcNAQEL
+MCMxITAfBgNVBAMMGGNhLW5vLWtleVVzYWdlLWV4dGVuc2lvbjAiGA8yMDE1MTEy
+ODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAeMRwwGgYDVQQDDBNlZS1rZXlDZXJ0
+U2lnbi1vbmx5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABow8wDTALBgNVHQ8EBAMCAgQwCwYJKoZIhvcNAQELA4IB
+AQAdgSy6hksLymW1pdbptv7dR/9LZt9pvBfXh2mJo+rt3FAO6Pc2hQdap3hZjOP4
+a3mlJXkQ+xhXt+mUBzEn/zeKWvAG0/RX7WqGhHU9BR2BIdfxUAYmZSoTnK0Q+8sn
+vtV+gQhVTB4FiAyvcE0Xno23Ge0HXTjL4PBsmEmTSrI0mgIpCY+LgOUs0Px3fu6S
+OIHGKmiCqprDaOk8vA7cXfqF0i6/aOuAgu9yP6PtdgORdkEj1SRcbP3L4BX6DkZ4
+8RxdP7Us9zJc8JbXaNYsVmGhs1K1U4P7IeDqK99+idqkv5IZOGmRH6XSDNSKAWGL
+7q/AnWlxjKyP1PXHQDs6fI0D
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem.certspec
new file mode 100644
index 000000000..a5a2d62a7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyCertSign-only-ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-no-keyUsage-extension
+subject:ee-keyCertSign-only
+extension:keyUsage:keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem
new file mode 100644
index 000000000..5cb293924
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1zCCAcGgAwIBAgIUCagPpigas5zVKduGrpGcKSE3bs0wCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDWNhLWFsbC11c2FnZXMwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowIjEgMB4GA1UEAwwXZWUta2V5RW5jaXBoZXJtZW50LW9u
+bHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braI
+BjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVa
+p0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB
+7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4C
+kC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJv
+aeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgK
+Ne2NAgMBAAGjDzANMAsGA1UdDwQEAwIFIDALBgkqhkiG9w0BAQsDggEBADVINQwH
+c6c0CNWqnwCuW+lwsFZ53TlZAeSzqCwnd/wRtBEAAz8KSmfoy158l1gz7M/1RpEn
+I0cdEWDOGzqXea1nIBHP3JBoHRe/ZVm6VWW4KgNgXfi1X7wN0UWjADX1XBhebo4f
+qVFRm4vatqyGEbm+sNvnJy2OXlC6g8VYeTmfXeLFmcHzWwJ59d3UYLB7fuW2R8GQ
+xQSJnkR1vAUJNX2U9WUriiTalLP7DkoYoPODqSmC2S2W/gaU3R2Lv/EwX/o+I9xe
+luxL8Zm6YctCfNNWdDDe8cqa1+h1meVr1QJww8Bmt8K9WIqDWjr+Lq5N/ZNbnt9f
+HzdZ40d5wD/9Cxc=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem.certspec
new file mode 100644
index 000000000..08154a53e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-all-usages.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-all-usages
+subject:ee-keyEncipherment-only
+extension:keyUsage:keyEncipherment
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem
new file mode 100644
index 000000000..75e64e3b3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4DCCAcqgAwIBAgIUA37iPfJhzPzGvR57p7UZYQrfgUIwCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmNhLW1pc3Npbmcta2V5Q2VydFNpZ24wIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowIjEgMB4GA1UEAwwXZWUta2V5RW5jaXBo
+ZXJtZW50LW9ubHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGo
+RI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9a
+dWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6t
+aRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8n
+FthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kX
+Dqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/py
+UcQx1QOs2hgKNe2NAgMBAAGjDzANMAsGA1UdDwQEAwIFIDALBgkqhkiG9w0BAQsD
+ggEBAKjvH8ZfuHOX5TvQfjhWK4bItjHec6pZeRDF0V2cGAVOu66Qk6ZJc8oUtH/N
+zAV0WLJ+CmJa4BU2fc56LWbomPO5bqSgbVJuf72bPr/ppWIpXxtVJJXbnY0UWcFs
+rNLBQfUlJzhApfsm/DgkRN/9ztHFi7MfgdpOaKjmFfy2WtOJnLzPH3/vsH2VAlDV
+2YAdMSwCiK52FLBhGel+S63FagTNtkozPY83ePU0nstSakdfXfLEpM0vnJCUQgFJ
+7SR/Eg1UbRSu/RWppEoFjEUnc+utXM8++9RlbO+0O5g3QpoVjI0iAgI5mMpAdYOj
+ZfovJrJ1KiU3NFgCu2KS7QNbo4g=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem.certspec
new file mode 100644
index 000000000..9bdcf4b7b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-missing-keyCertSign
+subject:ee-keyEncipherment-only
+extension:keyUsage:keyEncipherment
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem
new file mode 100644
index 000000000..7707ffa36
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4jCCAcygAwIBAgIUVaKLSYOm33xK4veKbBmaWOu6OoowCwYJKoZIhvcNAQEL
+MCMxITAfBgNVBAMMGGNhLW5vLWtleVVzYWdlLWV4dGVuc2lvbjAiGA8yMDE1MTEy
+ODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAiMSAwHgYDVQQDDBdlZS1rZXlFbmNp
+cGhlcm1lbnQtb25seTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqI
+UahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvi
+r1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/x
+fq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD
+7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnv
+uRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj
++nJRxDHVA6zaGAo17Y0CAwEAAaMPMA0wCwYDVR0PBAQDAgUgMAsGCSqGSIb3DQEB
+CwOCAQEAcH/p+TMlDVgnQ6pHcYKDaPcHOTxbVAF/WO5Zx8jtXZQZq3Ls7HzKh7Nb
+vF1nLvdNiAXmz58ynA83SQAj9dzU4etX4PRBqFFNVUXJngsWTqPBeBoPUK2rgWdE
+BpsqczEkBtLGX3+MdVFoc76x66oVoHItUP2bTcEPCRrivPjPE4FvQMMzenbz9iH/
+z5n4IiwYE3KHnkzv/SI3fR7ZB/JEy1DcQ9eSsHAauS9N+FB1RI+tmi7dsPUPxEsu
+PZ+YMoKF/qUvsLC8bFLm9Lxaj76F60ZDJib/Q+Lfll0D9zuKLtYUcYnVJOxExasE
+PPPsmL1LO2t4GR6Ohr0scBp2DouuTw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem.certspec
new file mode 100644
index 000000000..a2383ecfd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-keyEncipherment-only-ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca-no-keyUsage-extension
+subject:ee-keyEncipherment-only
+extension:keyUsage:keyEncipherment
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem
new file mode 100644
index 000000000..37a0b68b1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxzCCAbGgAwIBAgIUGbQXZixwJI9yhFsp9KXc1wHRU60wCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDWNhLWFsbC11c2FnZXMwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowIzEhMB8GA1UEAwwYZWUtbm8ta2V5VXNhZ2UtZXh0ZW5z
+aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62
+iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHql
+WqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosq
+Qe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+
+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8i
+b2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoY
+CjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEANC3lB6czGJeL8EiQbEf+DUGDXETg
+pTfbnV4si7kJ2ft5bXhltO92pus+v6jUjCFfQdxWfyzoJKX7FNlfRqtAPXXnjV9+
+UdvleX2IXtyGuvWb1J8wp9Ky+Yx1OBAEFtvGhjFnvYdt2/30S6eW3UmRfyBKshx7
+ZOASwi04RRWTvuvUN76UD+Fiy5RpLOHFAxb1o4oscTsncVarFqxQ76FviskjH8jH
+LcMWOAG4KIqQuteWhdUEO2B0MVsj6JYDCZEiXU2WGRlvzd3GcQqffxcQatyVkX7y
+hz/j+C/JEkCp9KN9g7DHbXehusONkmU/LgwkmKBtiU9yJMyK2PU/0qKFoQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem.certspec
new file mode 100644
index 000000000..6d2e67296
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-all-usages.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca-all-usages
+subject:ee-no-keyUsage-extension
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem
new file mode 100644
index 000000000..bc192ff9c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0DCCAbqgAwIBAgIUC6nvDJKsdXHlkcwJjyB1tgpBS8owCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmNhLW1pc3Npbmcta2V5Q2VydFNpZ24wIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowIzEhMB8GA1UEAwwYZWUtbm8ta2V5VXNh
+Z2UtZXh0ZW5zaW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR
+qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv
+WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+
+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv
+JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5
+Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6
+clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAr86WOKGBV6SUEBuH
+/jEA5AWdo/iv6Y6l3qJxCR2QxLu9WU5T95FwimLDvnc9YfDXb8Y7skLZVutkpVQ3
+jUZ86jF30c0/gT1x/4MhqJGMKZ+bWLgQkL+Odv1rpP/M9FhDmQz35T9IkedFE+QT
+znUH6BkOAd4KII1QGDKP34iFwtzdmypTZIWcw2Qvg+OSB/Z+MBdDq0giiabpSd2e
+xWfKsZAP+XmltADeZhF2Iicle7m6seajfQDaQam8j3F0Tktj4n62JGfcxQdjEcpO
+wbSIz3QkhJi2IAyEYaJNa4O6d/GG8qLo8ouvppB8nQxWeDr3PKOI0PGDlZT/2qzs
+rPWlfQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem.certspec
new file mode 100644
index 000000000..3cba2f0d8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-missing-keyCertSign.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca-missing-keyCertSign
+subject:ee-no-keyUsage-extension
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem
new file mode 100644
index 000000000..340de5e33
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0jCCAbygAwIBAgIUdTpgn8FIg/Q9On6r92BmokOw4U8wCwYJKoZIhvcNAQEL
+MCMxITAfBgNVBAMMGGNhLW5vLWtleVVzYWdlLWV4dGVuc2lvbjAiGA8yMDE1MTEy
+ODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAjMSEwHwYDVQQDDBhlZS1uby1rZXlV
+c2FnZS1leHRlbnNpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6
+iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr
+4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP
+8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OI
+Q+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ
+77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5J
+I/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IBAQAki2UmEYnRUxwj
+U7WHSwJKfzl42K/sMceI1VICE00QEhkyFenM3tuxqr8S2H3QlqjHPPORlyEcuP5T
+mchTpgU2lIbPxbNQjALSp2OOxo5WDBsl5G4H+Mw5OqgvcvH9Ko0hnxVMYuDvrziC
+4V6yoj6P+LS9NQ0yOHMgMkXG10DAXTEp/L8KHd8STaT8FNIC/kFJWq24yodASdwJ
+ak9RRPpMkC0XMT+LFhjjWrJvzyJKsyMnDB7RtH++MxnlwpqkHHX/Kq46yMPUheWC
+jJBIRJRHn1eED+6fatv89/2hqCLimGYA3FaFSxtm+UITHqLpnGCRNlLIwiMwNT6L
+K9zvsxW1
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem.certspec b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem.certspec
new file mode 100644
index 000000000..c850725a6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca-no-keyUsage-extension
+subject:ee-no-keyUsage-extension
diff --git a/security/manager/ssl/tests/unit/test_cert_keyUsage/moz.build b/security/manager/ssl/tests/unit/test_cert_keyUsage/moz.build
new file mode 100644
index 000000000..7fe54a9cc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_keyUsage/moz.build
@@ -0,0 +1,27 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca-all-usages.pem',
+# 'ca-missing-keyCertSign.pem',
+# 'ca-no-keyUsage-extension.pem',
+# 'ee-keyCertSign-and-keyEncipherment-ca-all-usages.pem',
+# 'ee-keyCertSign-and-keyEncipherment-ca-missing-keyCertSign.pem',
+# 'ee-keyCertSign-and-keyEncipherment-ca-no-keyUsage-extension.pem',
+# 'ee-keyCertSign-only-ca-all-usages.pem',
+# 'ee-keyCertSign-only-ca-missing-keyCertSign.pem',
+# 'ee-keyCertSign-only-ca-no-keyUsage-extension.pem',
+# 'ee-keyEncipherment-only-ca-all-usages.pem',
+# 'ee-keyEncipherment-only-ca-missing-keyCertSign.pem',
+# 'ee-keyEncipherment-only-ca-no-keyUsage-extension.pem',
+# 'ee-no-keyUsage-extension-ca-all-usages.pem',
+# 'ee-no-keyUsage-extension-ca-missing-keyCertSign.pem',
+# 'ee-no-keyUsage-extension-ca-no-keyUsage-extension.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_cert_override_bits_mismatches.js b/security/manager/ssl/tests/unit/test_cert_override_bits_mismatches.js
new file mode 100644
index 000000000..83b4fdbc6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_override_bits_mismatches.js
@@ -0,0 +1,89 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Test that when an override exists for a (host, certificate) pair,
+// connections will succeed only if the set of error bits in the override
+// contains each bit in the set of encountered error bits.
+// Strangely, it is possible to store an override with an empty set of error
+// bits, so this tests that too.
+
+do_get_profile();
+
+function add_override_bits_mismatch_test(host, certPath, expectedBits,
+ expectedError) {
+ const MAX_BITS = Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+ Ci.nsICertOverrideService.ERROR_MISMATCH |
+ Ci.nsICertOverrideService.ERROR_TIME;
+ let cert = constructCertFromFile(certPath);
+ let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
+ .getService(Ci.nsICertOverrideService);
+ for (let overrideBits = 0; overrideBits <= MAX_BITS; overrideBits++) {
+ add_test(function() {
+ certOverrideService.clearValidityOverride(host, 8443);
+ certOverrideService.rememberValidityOverride(host, 8443, cert,
+ overrideBits, true);
+ run_next_test();
+ });
+ // The override will succeed only if the set of error bits in the override
+ // contains each bit in the set of expected error bits.
+ let successExpected = (overrideBits | expectedBits) == overrideBits;
+ add_connection_test(host, successExpected ? PRErrorCodeSuccess
+ : expectedError);
+ }
+}
+
+function run_test() {
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+ add_tls_server_setup("BadCertServer", "bad_certs");
+
+ let fakeOCSPResponder = new HttpServer();
+ fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
+ response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
+ });
+ fakeOCSPResponder.start(8888);
+
+ add_override_bits_mismatch_test("unknownissuer.example.com",
+ "bad_certs/unknownissuer.pem",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_override_bits_mismatch_test("mismatch.example.com",
+ "bad_certs/mismatch.pem",
+ Ci.nsICertOverrideService.ERROR_MISMATCH,
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ add_override_bits_mismatch_test("expired.example.com",
+ "bad_certs/expired-ee.pem",
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_EXPIRED_CERTIFICATE);
+
+ add_override_bits_mismatch_test("mismatch-untrusted.example.com",
+ "bad_certs/mismatch-untrusted.pem",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+ Ci.nsICertOverrideService.ERROR_MISMATCH,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_override_bits_mismatch_test("untrusted-expired.example.com",
+ "bad_certs/untrusted-expired.pem",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_override_bits_mismatch_test("mismatch-expired.example.com",
+ "bad_certs/mismatch-expired.pem",
+ Ci.nsICertOverrideService.ERROR_MISMATCH |
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SSL_ERROR_BAD_CERT_DOMAIN);
+
+ add_override_bits_mismatch_test("mismatch-untrusted-expired.example.com",
+ "bad_certs/mismatch-untrusted-expired.pem",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+ Ci.nsICertOverrideService.ERROR_MISMATCH |
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_UNKNOWN_ISSUER);
+
+ add_test(function () {
+ fakeOCSPResponder.stop(run_next_test);
+ });
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_overrides.js b/security/manager/ssl/tests/unit/test_cert_overrides.js
new file mode 100644
index 000000000..038ca814f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_overrides.js
@@ -0,0 +1,340 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Tests the certificate overrides we allow.
+// add_cert_override_test will queue a test that does the following:
+// 1. Attempt to connect to the given host. This should fail with the
+// given error and override bits.
+// 2. Add an override for that host/port/certificate/override bits.
+// 3. Connect again. This should succeed.
+
+do_get_profile();
+
+function check_telemetry() {
+ let histogram = Cc["@mozilla.org/base/telemetry;1"]
+ .getService(Ci.nsITelemetry)
+ .getHistogramById("SSL_CERT_ERROR_OVERRIDES")
+ .snapshot();
+ equal(histogram.counts[0], 0, "Should have 0 unclassified counts");
+ equal(histogram.counts[2], 8,
+ "Actual and expected SEC_ERROR_UNKNOWN_ISSUER counts should match");
+ equal(histogram.counts[3], 1,
+ "Actual and expected SEC_ERROR_CA_CERT_INVALID counts should match");
+ equal(histogram.counts[4], 0,
+ "Actual and expected SEC_ERROR_UNTRUSTED_ISSUER counts should match");
+ equal(histogram.counts[5], 1,
+ "Actual and expected SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE counts should match");
+ equal(histogram.counts[6], 0,
+ "Actual and expected SEC_ERROR_UNTRUSTED_CERT counts should match");
+ equal(histogram.counts[7], 0,
+ "Actual and expected SEC_ERROR_INADEQUATE_KEY_USAGE counts should match");
+ equal(histogram.counts[8], 2,
+ "Actual and expected SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED counts should match");
+ equal(histogram.counts[9], 10,
+ "Actual and expected SSL_ERROR_BAD_CERT_DOMAIN counts should match");
+ equal(histogram.counts[10], 5,
+ "Actual and expected SEC_ERROR_EXPIRED_CERTIFICATE counts should match");
+ equal(histogram.counts[11], 2,
+ "Actual and expected MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY counts should match");
+ equal(histogram.counts[12], 1,
+ "Actual and expected MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA counts should match");
+ equal(histogram.counts[13], 1,
+ "Actual and expected MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE counts should match");
+ equal(histogram.counts[14], 2,
+ "Actual and expected MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE counts should match");
+ equal(histogram.counts[15], 1,
+ "Actual and expected MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE counts should match");
+ equal(histogram.counts[16], 2,
+ "Actual and expected SEC_ERROR_INVALID_TIME counts should match");
+ equal(histogram.counts[17], 1,
+ "Actual and expected MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME counts should match");
+
+ let keySizeHistogram = Cc["@mozilla.org/base/telemetry;1"]
+ .getService(Ci.nsITelemetry)
+ .getHistogramById("CERT_CHAIN_KEY_SIZE_STATUS")
+ .snapshot();
+ equal(keySizeHistogram.counts[0], 0,
+ "Actual and expected unchecked key size counts should match");
+ equal(keySizeHistogram.counts[1], 12,
+ "Actual and expected successful verifications of 2048-bit keys should match");
+ equal(keySizeHistogram.counts[2], 0,
+ "Actual and expected successful verifications of 1024-bit keys should match");
+ equal(keySizeHistogram.counts[3], 58,
+ "Actual and expected verification failures unrelated to key size should match");
+
+ run_next_test();
+}
+
+// Internally, specifying "port" -1 is the same as port 443. This tests that.
+function run_port_equivalency_test(inPort, outPort) {
+ Assert.ok((inPort == 443 && outPort == -1) || (inPort == -1 && outPort == 443),
+ "The two specified ports must be -1 and 443 (in any order)");
+ let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
+ .getService(Ci.nsICertOverrideService);
+ let cert = constructCertFromFile("bad_certs/default-ee.pem");
+ let expectedBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED;
+ let expectedTemporary = true;
+ certOverrideService.rememberValidityOverride("example.com", inPort, cert,
+ expectedBits, expectedTemporary);
+ let actualBits = {};
+ let actualTemporary = {};
+ Assert.ok(certOverrideService.hasMatchingOverride("example.com", outPort,
+ cert, actualBits,
+ actualTemporary),
+ `override set on port ${inPort} should match port ${outPort}`);
+ equal(actualBits.value, expectedBits,
+ "input override bits should match output bits");
+ equal(actualTemporary.value, expectedTemporary,
+ "input override temporary value should match output temporary value");
+ Assert.ok(!certOverrideService.hasMatchingOverride("example.com", 563,
+ cert, {}, {}),
+ `override set on port ${inPort} should not match port 563`);
+ certOverrideService.clearValidityOverride("example.com", inPort);
+ Assert.ok(!certOverrideService.hasMatchingOverride("example.com", outPort,
+ cert, actualBits, {}),
+ `override cleared on port ${inPort} should match port ${outPort}`);
+ equal(actualBits.value, 0, "should have no bits set if there is no override");
+}
+
+function run_test() {
+ run_port_equivalency_test(-1, 443);
+ run_port_equivalency_test(443, -1);
+
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+ add_tls_server_setup("BadCertServer", "bad_certs");
+
+ let fakeOCSPResponder = new HttpServer();
+ fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
+ response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
+ });
+ fakeOCSPResponder.start(8888);
+
+ add_simple_tests();
+ add_combo_tests();
+ add_distrust_tests();
+
+ add_test(function () {
+ fakeOCSPResponder.stop(check_telemetry);
+ });
+
+ run_next_test();
+}
+
+function add_simple_tests() {
+ add_cert_override_test("expired.example.com",
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_EXPIRED_CERTIFICATE);
+ add_cert_override_test("notyetvalid.example.com",
+ Ci.nsICertOverrideService.ERROR_TIME,
+ MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE);
+ add_cert_override_test("before-epoch.example.com",
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_INVALID_TIME);
+ add_cert_override_test("selfsigned.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_cert_override_test("unknownissuer.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_cert_override_test("expiredissuer.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
+ add_cert_override_test("notyetvalidissuer.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE);
+ add_cert_override_test("before-epoch-issuer.example.com",
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_INVALID_TIME);
+ add_cert_override_test("md5signature.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ add_cert_override_test("emptyissuername.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME);
+ // This has name information in the subject alternative names extension,
+ // but not the subject common name.
+ add_cert_override_test("mismatch.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH,
+ SSL_ERROR_BAD_CERT_DOMAIN,
+ /The certificate is only valid for the following names:\s*doesntmatch\.example\.com, \*\.alsodoesntmatch\.example\.com/);
+ // This has name information in the subject common name but not the subject
+ // alternative names extension.
+ add_cert_override_test("mismatch-CN.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH,
+ SSL_ERROR_BAD_CERT_DOMAIN,
+ /The certificate is not valid for the name mismatch-CN\.example\.com/);
+
+ // A Microsoft IIS utility generates self-signed certificates with
+ // properties similar to the one this "host" will present.
+ add_cert_override_test("selfsigned-inadequateEKU.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+
+ add_prevented_cert_override_test("inadequatekeyusage.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_INADEQUATE_KEY_USAGE);
+
+ // This is intended to test the case where a verification has failed for one
+ // overridable reason (e.g. unknown issuer) but then, in the process of
+ // reporting that error, a non-overridable error is encountered. The
+ // non-overridable error should be prioritized.
+ add_test(function() {
+ let rootCert = constructCertFromFile("bad_certs/test-ca.pem");
+ setCertTrust(rootCert, ",,");
+ run_next_test();
+ });
+ add_prevented_cert_override_test("nsCertTypeCritical.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+ add_test(function() {
+ let rootCert = constructCertFromFile("bad_certs/test-ca.pem");
+ setCertTrust(rootCert, "CTu,,");
+ run_next_test();
+ });
+
+ // Bug 990603: Apache documentation has recommended generating a self-signed
+ // test certificate with basic constraints: CA:true. For compatibility, this
+ // is a scenario in which an override is allowed.
+ add_cert_override_test("self-signed-end-entity-with-cA-true.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+
+ add_cert_override_test("ca-used-as-end-entity.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+
+ // If an X.509 version 1 certificate is not a trust anchor, we will
+ // encounter an overridable error.
+ add_cert_override_test("end-entity-issued-by-v1-cert.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
+ // If we make that certificate a trust anchor, the connection will succeed.
+ add_test(function() {
+ let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
+ .getService(Ci.nsICertOverrideService);
+ certOverrideService.clearValidityOverride("end-entity-issued-by-v1-cert.example.com", 8443);
+ let v1Cert = constructCertFromFile("bad_certs/v1Cert.pem");
+ setCertTrust(v1Cert, "CTu,,");
+ clearSessionCache();
+ run_next_test();
+ });
+ add_connection_test("end-entity-issued-by-v1-cert.example.com",
+ PRErrorCodeSuccess);
+ // Reset the trust for that certificate.
+ add_test(function() {
+ let v1Cert = constructCertFromFile("bad_certs/v1Cert.pem");
+ setCertTrust(v1Cert, ",,");
+ clearSessionCache();
+ run_next_test();
+ });
+
+ // Due to compatibility issues, we allow overrides for certificates issued by
+ // certificates that are not valid CAs.
+ add_cert_override_test("end-entity-issued-by-non-CA.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_CA_CERT_INVALID);
+
+ // This host presents a 1016-bit RSA key.
+ add_cert_override_test("inadequate-key-size-ee.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+
+ add_cert_override_test("ipAddressAsDNSNameInSAN.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH,
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ add_cert_override_test("noValidNames.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH,
+ SSL_ERROR_BAD_CERT_DOMAIN,
+ /The certificate is not valid for the name noValidNames\.example\.com/);
+ add_cert_override_test("badSubjectAltNames.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH,
+ SSL_ERROR_BAD_CERT_DOMAIN);
+
+ add_cert_override_test("bug413909.xn--hxajbheg2az3al.xn--jxalpdlp",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_test(function() {
+ // At this point, the override for bug413909.xn--hxajbheg2az3al.xn--jxalpdlp
+ // is still valid. Do some additional tests relating to IDN handling.
+ let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
+ .getService(Ci.nsICertOverrideService);
+ let uri = Services.io.newURI("https://bug413909.xn--hxajbheg2az3al.xn--jxalpdlp", null, null);
+ let cert = constructCertFromFile("bad_certs/idn-certificate.pem");
+ Assert.ok(certOverrideService.hasMatchingOverride(uri.asciiHost, 8443, cert, {}, {}),
+ "IDN certificate should have matching override using ascii host");
+ Assert.ok(!certOverrideService.hasMatchingOverride(uri.host, 8443, cert, {}, {}),
+ "IDN certificate should not have matching override using (non-ascii) host");
+ run_next_test();
+ });
+}
+
+function add_combo_tests() {
+ add_cert_override_test("mismatch-expired.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH |
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SSL_ERROR_BAD_CERT_DOMAIN,
+ /The certificate is only valid for <a id="cert_domain_link" title="doesntmatch\.example\.com">doesntmatch\.example\.com<\/a>/);
+ add_cert_override_test("mismatch-notYetValid.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH |
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SSL_ERROR_BAD_CERT_DOMAIN);
+ add_cert_override_test("mismatch-untrusted.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH |
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_cert_override_test("untrusted-expired.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_cert_override_test("mismatch-untrusted-expired.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH |
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_UNKNOWN_ISSUER);
+
+ add_cert_override_test("md5signature-expired.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+
+ add_cert_override_test("ca-used-as-end-entity-name-mismatch.example.com",
+ Ci.nsICertOverrideService.ERROR_MISMATCH |
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+}
+
+function add_distrust_tests() {
+ // Before we specifically distrust this certificate, it should be trusted.
+ add_connection_test("untrusted.example.com", PRErrorCodeSuccess);
+
+ add_distrust_test("bad_certs/default-ee.pem", "untrusted.example.com",
+ SEC_ERROR_UNTRUSTED_CERT);
+
+ add_distrust_test("bad_certs/other-test-ca.pem",
+ "untrustedissuer.example.com", SEC_ERROR_UNTRUSTED_ISSUER);
+
+ add_distrust_test("bad_certs/test-ca.pem",
+ "ca-used-as-end-entity.example.com",
+ SEC_ERROR_UNTRUSTED_ISSUER);
+}
+
+function add_distrust_test(certFileName, hostName, expectedResult) {
+ let certToDistrust = constructCertFromFile(certFileName);
+
+ add_test(function () {
+ // Add an entry to the NSS certDB that says to distrust the cert
+ setCertTrust(certToDistrust, "pu,,");
+ clearSessionCache();
+ run_next_test();
+ });
+ add_prevented_cert_override_test(hostName,
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ expectedResult);
+ add_test(function () {
+ setCertTrust(certToDistrust, "u,,");
+ run_next_test();
+ });
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1.js b/security/manager/ssl/tests/unit/test_cert_sha1.js
new file mode 100644
index 000000000..f0d7c570a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1.js
@@ -0,0 +1,142 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Tests the rejection of SHA-1 certificates based on the preference
+// security.pki.sha1_enforcement_level.
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+// We need to test as if we are at a fixed time, so that we are testing the
+// 2016 checks on SHA-1, not the notBefore checks.
+//
+// (new Date("2016-03-01")).getTime() / 1000
+const VALIDATION_TIME = 1456790400;
+
+function certFromFile(certName) {
+ return constructCertFromFile("test_cert_sha1/" + certName + ".pem");
+}
+
+function loadCertWithTrust(certName, trustString) {
+ addCertFromFile(certdb, "test_cert_sha1/" + certName + ".pem", trustString);
+}
+
+function checkEndEntity(cert, expectedResult) {
+ checkCertErrorGenericAtTime(certdb, cert, expectedResult,
+ certificateUsageSSLServer, VALIDATION_TIME);
+}
+
+function run_test() {
+ loadCertWithTrust("ca", "CTu,,");
+ loadCertWithTrust("int-pre", ",,");
+ loadCertWithTrust("int-post", ",,");
+
+ // Test cases per pref setting
+ //
+ // root intermed. end entity
+ // ===========================
+ // root
+ // |
+ // +--- pre-2016
+ // | |
+ // | +----- pre-2016 <--- (a)
+ // | +----- post-2016 <--- (b)
+ // |
+ // +--- post-2016
+ // |
+ // +----- post-2016 <--- (c)
+ //
+ // Expected outcomes (accept / reject):
+ //
+ // a b c
+ // Allowed (0) Accept Accept Accept
+ // Forbidden (1) Reject Reject Reject
+ // (2) is no longer available and is treated as Forbidden (1) internally.
+ // ImportedRoot (3) Reject Reject Reject (for built-in roots)
+ // ImportedRoot Accept Accept Accept (for non-built-in roots)
+ // ImportedRootOrBefore2016 (4) Accept Reject Reject (for built-in roots)
+ // ImportedRootOrBefore2016 Accept Accept Accept (for non-built-in roots)
+ //
+ // The pref setting of ImportedRoot accepts usage of SHA-1 only for
+ // certificates issued by non-built-in roots. By default, the testing
+ // certificates are all considered issued by a non-built-in root. However, we
+ // have the ability to treat a given non-built-in root as built-in. We test
+ // both of these situations below.
+ //
+ // As a historical note, a policy option (Before2016) was previously available
+ // that only allowed SHA-1 for certificates with a notBefore before 2016.
+ // However, to enable the policy of only allowing SHA-1 from non-built-in
+ // roots in the most straightforward way (while still having a time-based
+ // policy that users could enable if this new policy were problematic),
+ // Before2016 was shifted to also allow SHA-1 from non-built-in roots, hence
+ // ImportedRootOrBefore2016.
+ //
+ // A note about intermediate certificates: the certificate verifier has the
+ // ability to directly verify a given certificate for the purpose of issuing
+ // TLS web server certificates. However, when asked to do so, the certificate
+ // verifier does not take into account the currently configured SHA-1 policy.
+ // This is in part due to implementation complexity and because this isn't
+ // actually how TLS web server certificates are verified in the TLS handshake
+ // (which makes a full implementation that supports heeding the SHA-1 policy
+ // unnecessary).
+
+ // SHA-1 allowed
+ Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 0);
+ checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
+
+ // SHA-1 forbidden
+ Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 1);
+ checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+
+ // SHA-1 forbidden (test the case where the pref has been set to 2)
+ Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 2);
+ checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+
+ // SHA-1 allowed only when issued by an imported root. First test with the
+ // test root considered a built-in (on debug only - this functionality is
+ // disabled on non-debug builds).
+ Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 3);
+ if (isDebugBuild) {
+ let root = certFromFile("ca");
+ Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint);
+ checkEndEntity(certFromFile("ee-pre_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ Services.prefs.clearUserPref("security.test.built_in_root_hash");
+ }
+
+ // SHA-1 still allowed only when issued by an imported root.
+ // Now test with the test root considered a non-built-in.
+ checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
+
+ // SHA-1 allowed before 2016 or when issued by an imported root. First test
+ // with the test root considered a built-in.
+ Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
+ if (isDebugBuild) {
+ let root = certFromFile("ca");
+ Services.prefs.setCharPref("security.test.built_in_root_hash", root.sha256Fingerprint);
+ checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-post_int-pre"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ checkEndEntity(certFromFile("ee-post_int-post"), SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ Services.prefs.clearUserPref("security.test.built_in_root_hash");
+ }
+
+ // SHA-1 still only allowed before 2016 or when issued by an imported root.
+ // Now test with the test root considered a non-built-in.
+ checkEndEntity(certFromFile("ee-pre_int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-post_int-pre"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-post_int-post"), PRErrorCodeSuccess);
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/ca.pem b/security/manager/ssl/tests/unit/test_cert_sha1/ca.pem
new file mode 100644
index 000000000..3eb86849d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUM2w8iT4pElSjs7q3vwwClj34aqcwCwYJKoZIhvcNAQEF
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTAwMTAxMDAwMDAwWhgPMjA1MDAxMDEwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzALBgNVHQ8EBAMCAQYwDAYDVR0T
+BAUwAwEB/zALBgkqhkiG9w0BAQUDggEBAGOFkUTVsazVYYVZn3v9wIKlEZYMfJ7B
+V+INq12QVUgENBzIfQ/TPIYz+mkY5uCr94v5YUmW0eeyaSwJPlNaKWOyR0pQYd03
+Bd6gltdcdRkHs2FBaSOOli9vR0IZt2FAKE6w/05xcV4XSZOpztAf1wXFCF+OF3F3
+TdRzcbUj2iVFH0Vh99oBL/CXAJ3yiJQZo/8W9433GuRLDFcvtInMfzjX1N+NxIbR
+TLXqjB/gOV8rcmnRtvloEEWibj7628QxaiOoN08VPSI8+9t1Fd2EkJzF9jmffrwG
+v3e9kb4X/08YG6hFRwjhQGgF/kcs2LMD5BiYAxPqc3KP3VrwmhVqQ6w=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_sha1/ca.pem.certspec
new file mode 100644
index 000000000..7e65e9ee3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/ca.pem.certspec
@@ -0,0 +1,6 @@
+issuer:ca
+subject:ca
+validity:20100101-20500101
+extension:keyUsage:keyCertSign,cRLSign
+extension:basicConstraints:cA,
+signature:sha1WithRSAEncryption
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-post.pem b/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-post.pem
new file mode 100644
index 000000000..19d8f096a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-post.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsTCCAZugAwIBAgIUJWQl8gkrLL7gPn47YYMdN7qBP5wwCwYJKoZIhvcNAQEF
+MBMxETAPBgNVBAMMCGludC1wb3N0MCIYDzIwMTYwMTAyMDAwMDAwWhgPMjAxNzAy
+MDEwMDAwMDBaMBIxEDAOBgNVBAMMB2VlLXBvc3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HH
+Jajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOr
+IMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQ
+sVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLA
+dTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQE
+LL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQEF
+A4IBAQAuEj6tFW9t1D7+X7uAP6yb/rO0dKB9ZIkisPyxzKgOtl1yTyfeNOnylwLY
+W/et09JkBOqcp/lP8J30F4dciAdmff02FCd6uMnxPnihWRpnPZH6Fo5ZpbkUuRUk
+ufPmYx2qP4kZnsz/oHJKOpDPZCvLOYggkQEM4EOcds3DxAXYwoxjqEJ3H/n3/Bt0
+y78WvwJ3GV2N2uxL40r99tMM9dovujXwgPCxl27MCoAUIB0jDq3CboLLk9T55iVO
+HknFyCDjOcwOF4tSXyVWqp67pnHcwPKfF1IkDkGK5bBbT5+RS/md3PTh+7zsz7sN
+b22AlQXylN9RhPHywIK4RY4OX0Kx
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-post.pem.certspec b/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-post.pem.certspec
new file mode 100644
index 000000000..76834f844
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-post.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-post
+subject:ee-post
+validity:20160102-20170201
+signature:sha1WithRSAEncryption
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-pre.pem b/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-pre.pem
new file mode 100644
index 000000000..2d1ff2d2e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-pre.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsDCCAZqgAwIBAgIUIVsTCuql4BDO2r4O5zePBEoHg3QwCwYJKoZIhvcNAQEF
+MBIxEDAOBgNVBAMMB2ludC1wcmUwIhgPMjAxNjAxMDEwMDAwMDBaGA8yMDE3MDIw
+MTAwMDAwMFowEjEQMA4GA1UEAwwHZWUtcG9zdDCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQUD
+ggEBADyJnTjky3W6jcfsSv9AS+aVYpJHzLexTI1wzv+ntg6zUFbpDb/RFerp61Wb
+zef+72XEJJtRQO28udN59OOnytX71ulvmmgSOeFNb/znLzGyIGf9ag8qIbt8m7/r
+jR3010kh9zruD1RE0QbTTPXeeFlh0yUT69ZvxRMWJxaASY/vibCjmR22hpiHjM+1
+bpXgUEtj4u8WFRVpHwGsca1uXjQQDgPaLv/7byiC1DtBHP1P5wdYtNXY+dL/W4mn
+y3Lqe96ddO9dIDetEdzzk7PLzqIkDJM1DiGrYxGgM70GjF1BiMGkskGMwfMfe6Pt
+UmMzpYci8vcbHF8lj+Ja8Aw3SHo=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-pre.pem.certspec b/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-pre.pem.certspec
new file mode 100644
index 000000000..1e8bb35b3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/ee-post_int-pre.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-pre
+subject:ee-post
+validity:20160101-20170201
+signature:sha1WithRSAEncryption
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/ee-pre_int-pre.pem b/security/manager/ssl/tests/unit/test_cert_sha1/ee-pre_int-pre.pem
new file mode 100644
index 000000000..a992d8272
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/ee-pre_int-pre.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUOU+CyYnf3GRRgGHvbeJB8HTUvJ4wCwYJKoZIhvcNAQEF
+MBIxEDAOBgNVBAMMB2ludC1wcmUwIhgPMjAxNTAxMDEwMDAwMDBaGA8yMDE3MDIw
+MTAwMDAwMFowETEPMA0GA1UEAwwGZWUtcHJlMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBBQOC
+AQEAn0lp9zXbe2pAVI8aR/+xFD8AOTB0bzlD6xNIQahBPd/JE93ni1oi3N6PUKRp
+vtDECKigcX4OLOZid8rt82CS6I6/OiKYqfZrMmr3BMjpNFNOFZqhEGtm4y6j+hjo
+HV8FEXmse06hZkwIkqacF16+P9boBCP2mF5zrUuIML48GnwPCtb7KIEmZTl8dsXn
+oUMrAQXPZYTcCb6U8GVU3WQRMRLsZ+WenATuOZPZeDQRrYUkoaJ+KfGG/ZNnmw6u
+ribqtEPBu3CqXj5BZiF3rcr+QjSlluuGDWrR0TpGTJmBiTXilUYSWv/lKOJR7rJA
+89uNoWp/kCkbxWLlguPWAEx+kg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/ee-pre_int-pre.pem.certspec b/security/manager/ssl/tests/unit/test_cert_sha1/ee-pre_int-pre.pem.certspec
new file mode 100644
index 000000000..0f4a6ec25
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/ee-pre_int-pre.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-pre
+subject:ee-pre
+validity:20150101-20170201
+signature:sha1WithRSAEncryption
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/int-post.pem b/security/manager/ssl/tests/unit/test_cert_sha1/int-post.pem
new file mode 100644
index 000000000..c1a9ab2fa
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/int-post.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyzCCAbWgAwIBAgIUU3gwFYS/POd5EH541PQ4aTV8eN8wCwYJKoZIhvcNAQEF
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTYwMTAxMDAwMDAwWhgPMjAyNjAxMDEwMDAw
+MDBaMBMxETAPBgNVBAMMCGludC1wb3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4Ngf
+vbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTb
+uUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3S
+O8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR
+3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv
+5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzALBgNVHQ8EBAMCAQYw
+DAYDVR0TBAUwAwEB/zALBgkqhkiG9w0BAQUDggEBAFwbiQ3x7M+JecpGomrBJ6uu
+ajH2cU5B6q3+842jNRTJ8kjE5sXvaaF5Zasdlp/pOq5Xu3tgniDuLbr280MxDx/i
+eyDBfZefJRskgBl/a4F7w0i0LlwYGJkyr++XWckEutO06ou6ATzsA6WAhh+O3fSB
+tLaf0V9Pof3pglNETpSlIFzQytoIc5aICMjt9Ur72S/IpM7sHkJoPpKwscOovTCp
+4k6jDTOHAHr8ck0X89KPHT/nRmm6bAQHsGMjSnrpEgXQ+ZuwVLEEdQPZ2L5028Uq
+RJn0mFu6Z53EYYrZURWdiq/p5N67TknC28REilfoG3PPqFD/CLbEMq5lrA5IGxM=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/int-post.pem.certspec b/security/manager/ssl/tests/unit/test_cert_sha1/int-post.pem.certspec
new file mode 100644
index 000000000..50156c9f6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/int-post.pem.certspec
@@ -0,0 +1,6 @@
+issuer:ca
+subject:int-post
+validity:20160101-20260101
+extension:keyUsage:keyCertSign,cRLSign
+extension:basicConstraints:cA,
+signature:sha1WithRSAEncryption
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/int-pre.pem b/security/manager/ssl/tests/unit/test_cert_sha1/int-pre.pem
new file mode 100644
index 000000000..41170f837
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/int-pre.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyjCCAbSgAwIBAgIUGZVI6HsbDll1DnYoYIZ0eqi4ZPwwCwYJKoZIhvcNAQEF
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTAwMTAxMDAwMDAwWhgPMjAyMDAxMDEwMDAw
+MDBaMBIxEDAOBgNVBAMMB2ludC1wcmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAsGA1UdDwQEAwIBBjAM
+BgNVHRMEBTADAQH/MAsGCSqGSIb3DQEBBQOCAQEAjpiGO9woF0OKiGVLk/SjpU3M
+NFbLNsFYGL6PQfpZHHCxc78qtZZ6uVM8fh9tRzlFbRx0eGWVFqcjxTrsAVopM+wJ
+1lRa8O4VXrtzhBoknPIBpdLvLYTdipLOL8qxCad6DdlX31JwQYgdmSUQ3YyqoCaC
+C3b3cVEF4h2A7hbBIxOTl1Xvs/aVbllYdnoO0HEs4FBrQVfQsjTPzJeF42GNW/OV
+KvX9XQ/Oq8r9sxyyGRKILj9yTqKtwXNU50QxW9MxN1vMY9w1skmMAMqrwn3FgjIU
+cxv3oqfeTwAa9V2S0B+4k3lX6Ku5ON1YRX+w5oD9RruHMu+qzJZMhrdQjhf34w==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/int-pre.pem.certspec b/security/manager/ssl/tests/unit/test_cert_sha1/int-pre.pem.certspec
new file mode 100644
index 000000000..9f0a59ee9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/int-pre.pem.certspec
@@ -0,0 +1,6 @@
+issuer:ca
+subject:int-pre
+validity:20100101-20200101
+extension:keyUsage:keyCertSign,cRLSign
+extension:basicConstraints:cA,
+signature:sha1WithRSAEncryption
diff --git a/security/manager/ssl/tests/unit/test_cert_sha1/moz.build b/security/manager/ssl/tests/unit/test_cert_sha1/moz.build
new file mode 100644
index 000000000..d94bb0498
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_sha1/moz.build
@@ -0,0 +1,18 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca.pem',
+# 'int-pre.pem',
+# 'ee-pre_int-pre.pem',
+# 'ee-post_int-pre.pem',
+# 'int-post.pem',
+# 'ee-post_int-post.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures.js b/security/manager/ssl/tests/unit/test_cert_signatures.js
new file mode 100644
index 000000000..8be89c8a2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures.js
@@ -0,0 +1,121 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+// Tests that certificates cannot be tampered with without being detected.
+// Tests a combination of cases: RSA signatures, ECDSA signatures, certificate
+// chains where the intermediate has been tampered with, chains where the
+// end-entity has been tampered, tampering of the signature, and tampering in
+// the rest of the certificate.
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+var certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+// Reads a PEM-encoded certificate, modifies the nth byte (0-indexed), and
+// returns the base64-encoded bytes of the certificate. Negative indices may be
+// specified to modify a byte from the end of the certificate.
+function readAndTamperWithNthByte(certificatePath, n) {
+ let pem = readFile(do_get_file(certificatePath, false));
+ let der = atob(pemToBase64(pem));
+ if (n < 0) {
+ // remember, n is negative at this point
+ n = der.length + n;
+ }
+ let replacement = '\x22';
+ if (der.charCodeAt(n) == replacement) {
+ replacement = '\x23';
+ }
+ der = der.substring(0, n) + replacement + der.substring(n + 1);
+ return btoa(der);
+}
+
+// The signature on certificates appears last. This should modify the contents
+// of the signature such that it no longer validates correctly while still
+// resulting in a structurally valid certificate.
+const BYTE_IN_SIGNATURE = -8;
+function addSignatureTamperedCertificate(certificatePath) {
+ let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE);
+ certdb.addCertFromBase64(base64, ",,", null);
+}
+
+function ensureSignatureVerificationFailure(certificatePath) {
+ let cert = constructCertFromFile(certificatePath);
+ checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
+ certificateUsageSSLServer);
+}
+
+function tamperWithSignatureAndEnsureVerificationFailure(certificatePath) {
+ let base64 = readAndTamperWithNthByte(certificatePath, BYTE_IN_SIGNATURE);
+ let cert = certdb.constructX509FromBase64(base64);
+ checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
+ certificateUsageSSLServer);
+}
+
+// The beginning of a certificate looks like this (in hex, using DER):
+// 30 XX XX XX [the XX encode length - there are probably 3 bytes here]
+// 30 XX XX XX [length again]
+// A0 03
+// 02 01
+// 02
+// 02 XX [length again - 1 byte as long as we're using pycert]
+// XX XX ... [serial number - 20 bytes as long as we're using pycert]
+// Since we want to modify the serial number, we need to change something from
+// byte 15 to byte 34 (0-indexed). If it turns out that the two length sections
+// we assumed were 3 bytes are shorter (they can't be longer), modifying
+// something from byte 15 to byte 30 will still get us what we want. Since the
+// serial number is a DER INTEGER and because it must be positive, it's best to
+// skip the first two bytes of the serial number so as to not run into any
+// issues there. Thus byte 17 is a good byte to modify.
+const BYTE_IN_SERIAL_NUMBER = 17;
+function addSerialNumberTamperedCertificate(certificatePath) {
+ let base64 = readAndTamperWithNthByte(certificatePath,
+ BYTE_IN_SERIAL_NUMBER);
+ certdb.addCertFromBase64(base64, ",,", null);
+}
+
+function tamperWithSerialNumberAndEnsureVerificationFailure(certificatePath) {
+ let base64 = readAndTamperWithNthByte(certificatePath,
+ BYTE_IN_SERIAL_NUMBER);
+ let cert = certdb.constructX509FromBase64(base64);
+ checkCertErrorGeneric(certdb, cert, SEC_ERROR_BAD_SIGNATURE,
+ certificateUsageSSLServer);
+}
+
+function run_test() {
+ addCertFromFile(certdb, "test_cert_signatures/ca-rsa.pem", "CTu,,");
+ addCertFromFile(certdb, "test_cert_signatures/ca-secp384r1.pem", "CTu,,");
+
+ // Tamper with the signatures on intermediate certificates and ensure that
+ // end-entity certificates issued by those intermediates do not validate
+ // successfully.
+ addSignatureTamperedCertificate("test_cert_signatures/int-rsa.pem");
+ addSignatureTamperedCertificate("test_cert_signatures/int-secp384r1.pem");
+ ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
+ ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem");
+
+ // Tamper with the signatures on end-entity certificates and ensure that they
+ // do not validate successfully.
+ tamperWithSignatureAndEnsureVerificationFailure(
+ "test_cert_signatures/ee-rsa-direct.pem");
+ tamperWithSignatureAndEnsureVerificationFailure(
+ "test_cert_signatures/ee-secp384r1-direct.pem");
+
+ // Tamper with the serial numbers of intermediate certificates and ensure
+ // that end-entity certificates issued by those intermediates do not validate
+ // successfully.
+ addSerialNumberTamperedCertificate("test_cert_signatures/int-rsa.pem");
+ addSerialNumberTamperedCertificate("test_cert_signatures/int-secp384r1.pem");
+ ensureSignatureVerificationFailure("test_cert_signatures/ee-rsa.pem");
+ ensureSignatureVerificationFailure("test_cert_signatures/ee-secp384r1.pem");
+
+ // Tamper with the serial numbers of end-entity certificates and ensure that
+ // they do not validate successfully.
+ tamperWithSerialNumberAndEnsureVerificationFailure(
+ "test_cert_signatures/ee-rsa-direct.pem");
+ tamperWithSerialNumberAndEnsureVerificationFailure(
+ "test_cert_signatures/ee-secp384r1-direct.pem");
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.pem b/security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.pem
new file mode 100644
index 000000000..d69aa25b6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUO2lYN9PBRm2JcO9v6CRF34O3zf4wCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmNhLXJzYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjARMQ8wDQYDVQQDDAZjYS1yc2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAwGA1UdEwQFMAMB
+Af8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEALKYfcXwaFc61IDWngVq6
+3PdKTQHw31/w7GyBo19DE5MDVxyrXZq+fRAhGre8ge1gKrOlMcmLIoEVcK+y1MwY
+f4yIpStfOg+6Tf1C2e8UUTzhsolQxKFU0rtEJXPlRgMA2pcO6RjFhK2/D79icYra
+0U0OQrMnGGw46QPZkynKw4RwTZpCaJTkN8+LzXyik6Pj0mjpb7Xeo5FCmI6eEIkF
+n8Ni6pepA+kHCRqPQIkbl5tzrfVTUEKAVxnv2TeCrTCdDK6dRGVycrOfNlma34in
+Poo/6uDgjGyMp2c2zOpg6igYED/8SDMFzyHVQ52Db8xaPxOyNykyGTWEE3IW8cpB
+NA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.pem.certspec b/security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.pem.certspec
new file mode 100644
index 000000000..5890d2db6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ca-rsa.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca-rsa
+subject:ca-rsa
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ca-secp384r1.pem b/security/manager/ssl/tests/unit/test_cert_signatures/ca-secp384r1.pem
new file mode 100644
index 000000000..efa00a41b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ca-secp384r1.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBjjCCARSgAwIBAgIUUVp8W0nO+hAF/W78cEBWzlRXvGAwCgYIKoZIzj0EAwIw
+FzEVMBMGA1UEAwwMY2Etc2VjcDM4NHIxMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBcxFTATBgNVBAMMDGNhLXNlY3AzODRyMTB2MBAGByqGSM49
+AgEGBSuBBAAiA2IABKFockM2K1x7GInzeRVGFaHHP7SN7oY+AikV22COJS3ktxMt
+qM6Y6DFTTmqcDAsJyNY5regyBuW6gTRzoR+jMOBdqMluQ4P+J4c9qXEDviiIz/AC
+8Fr3Gh/dzIN0qm6pzqMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCgYI
+KoZIzj0EAwIDaAAwZQIxAO0GJz6haDpUtNgaQ3SESJY85j6+gRcD7Nc9cvCiVAZZ
+1OxFRuhW515lVbeTqfcA8wIwFdIanp6v61Q6pot5X6fHyn7G+ZIsEbHDPOZPaq0U
+QR5t1/Y5Fe4hDulAXXt+jvE0
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ca-secp384r1.pem.certspec b/security/manager/ssl/tests/unit/test_cert_signatures/ca-secp384r1.pem.certspec
new file mode 100644
index 000000000..0701c23c1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ca-secp384r1.pem.certspec
@@ -0,0 +1,7 @@
+issuer:ca-secp384r1
+subject:ca-secp384r1
+issuerKey:secp384r1
+subjectKey:secp384r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa-direct.pem b/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa-direct.pem
new file mode 100644
index 000000000..17c1eddac
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa-direct.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtTCCAZ+gAwIBAgIULa69PvpLSrw920lPhbLY+O4VRUEwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmNhLXJzYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAYMRYwFAYDVQQDDA1lZS1yc2EtZGlyZWN0MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFds
+JHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4
+ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25
+iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu3
+4pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42
+yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3
+DQEBCwOCAQEAF1HRj4EAiAQcWXyOijM6CkccZiCnnWGDJaEv2okPC5vYrDnhcrqi
+xmaYAtpyU60GzYslxy52f3n7kzykXB7Uv0fUFX3ZUedCNwEh8WTfks8mEDUeibt/
+eSK6uLuhe9njiWQv1b71QySUjcWDTfJ8JhpS1Dr8BdpEuWc7CUSwoQqS72iF4wou
+vjP7AD8WkmyoAlPSCAnL5P5n6iPdeFpupnQQ7apbH+6uhq0p9r6tuTWGdCJN8CHk
+hfQGuhERyTbmC0wOcE9NmVGM9MB0fn/W92GSr8ZWnQoudrH3H+HR3ULjV9TpB2W2
+RpfmOWnsPDTUM3q4qqYZcz1O+1CGgSe2qg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa-direct.pem.certspec b/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa-direct.pem.certspec
new file mode 100644
index 000000000..4e25ddcf9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa-direct.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca-rsa
+subject:ee-rsa-direct
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa.pem b/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa.pem
new file mode 100644
index 000000000..85a3256bf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUS+9dGZZa6H0mcsDNp90hmo3/2IIwCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB2ludC1yc2EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowETEPMA0GA1UEAwwGZWUtcnNhMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEAdFA74biUzEKaexSV4U6UKgXlDez+YUjqZyPg+XJ88Zdt3ldBD2YFZLBYYX+B
+Mls6i5s+UsmH7X0OFD9JJf9ti1n/lNEriyj9tF35w020OtLrYRhTdiafGgwKZXj1
+FWgQpA8+lDXoVrSYOozfIZCR5RwTraJ676jy5l8+f+fY06gGfNOA+Raj3WI0veh/
+HZhXtF9K+qFzyYSX1c6YFFEUo3horxyyuEgPDF9gsmxHzErbPkbbTkgihdZKwXYg
+FUCIjKFNOtLTm+yESBi5YN69hO33mr5RbYsqu2Wwh+m0405dp7U0+zxOhoYVEpYb
+MIZgbeJrQjO6n/+sHPZXkYOhpQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa.pem.certspec b/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa.pem.certspec
new file mode 100644
index 000000000..b974a0a0a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ee-rsa.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-rsa
+subject:ee-rsa
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1-direct.pem b/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1-direct.pem
new file mode 100644
index 000000000..373e3227f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1-direct.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBdTCB/KADAgECAhQ/DpvvKy1cb0ww9HrO6/Ao0FwezjAKBggqhkjOPQQDAjAX
+MRUwEwYDVQQDDAxjYS1zZWNwMzg0cjEwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowHjEcMBoGA1UEAwwTZWUtc2VjcDM4NHIxLWRpcmVjdDB2MBAG
+ByqGSM49AgEGBSuBBAAiA2IABKFockM2K1x7GInzeRVGFaHHP7SN7oY+AikV22CO
+JS3ktxMtqM6Y6DFTTmqcDAsJyNY5regyBuW6gTRzoR+jMOBdqMluQ4P+J4c9qXED
+viiIz/AC8Fr3Gh/dzIN0qm6pzjAKBggqhkjOPQQDAgNoADBlAjEA7QYnPqFoOlS0
+2BpDdIRIljzmPr6BFwPs1z1y8KJUBlnU7EVG6FbnXmVVt5Op9wDzAjAboNLdytrv
+bPTA8IfMt71/9F/w9GqjK0616TVZY9I/DiERYT6X6PE2il/eMGaQEgg=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1-direct.pem.certspec b/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1-direct.pem.certspec
new file mode 100644
index 000000000..386ab95f7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1-direct.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca-secp384r1
+subject:ee-secp384r1-direct
+issuerKey:secp384r1
+subjectKey:secp384r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1.pem b/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1.pem
new file mode 100644
index 000000000..b11cfd53c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbjCB9qADAgECAhQ7FJ+9gQKCxkNdRiyOldB2DMRpnjAKBggqhkjOPQQDAjAY
+MRYwFAYDVQQDDA1pbnQtc2VjcDM4NHIxMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBcxFTATBgNVBAMMDGVlLXNlY3AzODRyMTB2MBAGByqGSM49
+AgEGBSuBBAAiA2IABKFockM2K1x7GInzeRVGFaHHP7SN7oY+AikV22COJS3ktxMt
+qM6Y6DFTTmqcDAsJyNY5regyBuW6gTRzoR+jMOBdqMluQ4P+J4c9qXEDviiIz/AC
+8Fr3Gh/dzIN0qm6pzjAKBggqhkjOPQQDAgNnADBkAjEA7QYnPqFoOlS02BpDdIRI
+ljzmPr6BFwPs1z1y8KJUBlnU7EVG6FbnXmVVt5Op9wDzAi9/y9J21YfiwsBalvKh
++ruL6jHmzpxdR7p5IORvNQEHWl6/H8cHmi3Wn8GieN5RgA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1.pem.certspec b/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1.pem.certspec
new file mode 100644
index 000000000..b8f7993be
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/ee-secp384r1.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int-secp384r1
+subject:ee-secp384r1
+issuerKey:secp384r1
+subjectKey:secp384r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/int-rsa.pem b/security/manager/ssl/tests/unit/test_cert_signatures/int-rsa.pem
new file mode 100644
index 000000000..f01885f4b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/int-rsa.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzjCCAbigAwIBAgIUET5f4owvO60JtJUbi1xFtlVRRaQwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmNhLXJzYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjASMRAwDgYDVQQDDAdpbnQtcnNhMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTAD
+AQH/MAsGA1UdDwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAEHH8NBKQ0v8G/ad07vk
+v1LbgP5oEj2NXbFPCAgNez4M7XDgCPEtbiKCt1bBXtLrZPggCzyH9cTZjzJFMoNr
+6sB7x76+E+y6+jkKPCeMhsR4WL1GY4IFX7YueNQ94Twb+RAjHPJqEyI7GoTpRKhi
+0hix8QgPVOTdItp4Sm9AZiyHjlTIo5Lvphm708SFKT4iQco256zjLog7LE7NLZxo
+IZdUoUClnNXj0Ua4P4hbGf4uRIldSUV82Xbz6VNcVJ0fCB11YqlNsyXa3Nj5HyTN
+uBXMOItSedvOQmwwRM9QM5a/Uy5vUhZeHuY/MpXpQoj43D3s1qQWXCe7TYSYEpOl
+Gwc=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/int-rsa.pem.certspec b/security/manager/ssl/tests/unit/test_cert_signatures/int-rsa.pem.certspec
new file mode 100644
index 000000000..a86d28b44
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/int-rsa.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca-rsa
+subject:int-rsa
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/int-secp384r1.pem b/security/manager/ssl/tests/unit/test_cert_signatures/int-secp384r1.pem
new file mode 100644
index 000000000..5893cf191
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/int-secp384r1.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBkDCCARWgAwIBAgIUTZPJwmeUhMvv2i6MC21jYsZd1E8wCgYIKoZIzj0EAwIw
+FzEVMBMGA1UEAwwMY2Etc2VjcDM4NHIxMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBgxFjAUBgNVBAMMDWludC1zZWNwMzg0cjEwdjAQBgcqhkjO
+PQIBBgUrgQQAIgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtgjiUt5LcT
+LajOmOgxU05qnAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalxA74oiM/w
+AvBa9xof3cyDdKpuqc6jHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoG
+CCqGSM49BAMCA2kAMGYCMQDtBic+oWg6VLTYGkN0hEiWPOY+voEXA+zXPXLwolQG
+WdTsRUboVudeZVW3k6n3APMCMQDsCu5UY7Sp5LHK9qsrKLL5YD8FhYR0oQCOAzgX
+/AbvvDsssBIBBT5McBixnMHuYDU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/int-secp384r1.pem.certspec b/security/manager/ssl/tests/unit/test_cert_signatures/int-secp384r1.pem.certspec
new file mode 100644
index 000000000..e002a1569
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/int-secp384r1.pem.certspec
@@ -0,0 +1,7 @@
+issuer:ca-secp384r1
+subject:int-secp384r1
+issuerKey:secp384r1
+subjectKey:secp384r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_cert_signatures/moz.build b/security/manager/ssl/tests/unit/test_cert_signatures/moz.build
new file mode 100644
index 000000000..779339bec
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_signatures/moz.build
@@ -0,0 +1,20 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca-rsa.pem',
+# 'ca-secp384r1.pem',
+# 'ee-rsa-direct.pem',
+# 'ee-rsa.pem',
+# 'ee-secp384r1-direct.pem',
+# 'ee-secp384r1.pem',
+# 'int-rsa.pem',
+# 'int-secp384r1.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_cert_trust.js b/security/manager/ssl/tests/unit/test_cert_trust.js
new file mode 100644
index 000000000..622678c7a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_trust.js
@@ -0,0 +1,216 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+var certList = [
+ 'ee',
+ 'int',
+ 'ca',
+];
+
+function load_cert(cert_name, trust_string) {
+ let cert_filename = cert_name + ".pem";
+ addCertFromFile(certdb, "test_cert_trust/" + cert_filename, trust_string);
+}
+
+function setup_basic_trusts(ca_cert, int_cert) {
+ certdb.setCertTrust(ca_cert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL |
+ Ci.nsIX509CertDB.TRUSTED_EMAIL |
+ Ci.nsIX509CertDB.TRUSTED_OBJSIGN);
+
+ certdb.setCertTrust(int_cert, Ci.nsIX509Cert.CA_CERT, 0);
+}
+
+function test_ca_distrust(ee_cert, cert_to_modify_trust, isRootCA) {
+ // On reset most usages are successful
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageSSLServer);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageSSLClient);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageSSLCA);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageEmailSigner);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageEmailRecipient);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageObjectSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageVerifyCA);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_INADEQUATE_CERT_TYPE,
+ certificateUsageStatusResponder);
+
+
+ // Test of active distrust. No usage should pass.
+ setCertTrust(cert_to_modify_trust, 'p,p,p');
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageSSLServer);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageSSLClient);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageSSLCA);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageEmailSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageEmailRecipient);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageObjectSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageVerifyCA);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageStatusResponder);
+
+ // Trust set to T - trusted CA to issue client certs, where client cert is
+ // usageSSLClient.
+ setCertTrust(cert_to_modify_trust, 'T,T,T');
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageSSLServer);
+
+ // XXX(Bug 982340)
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageSSLClient);
+
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageSSLCA);
+
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageEmailSigner);
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageEmailRecipient);
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageObjectSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageVerifyCA);
+ checkCertErrorGeneric(certdb, ee_cert,
+ isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : SEC_ERROR_INADEQUATE_CERT_TYPE,
+ certificateUsageStatusResponder);
+
+
+ // Now tests on the SSL trust bit
+ setCertTrust(cert_to_modify_trust, 'p,C,C');
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageSSLServer);
+
+ //XXX(Bug 982340)
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageSSLClient);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageSSLCA);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageEmailSigner);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageEmailRecipient);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageObjectSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageVerifyCA);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageStatusResponder);
+
+ // Inherited trust SSL
+ setCertTrust(cert_to_modify_trust, ',C,C');
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageSSLServer);
+ // XXX(Bug 982340)
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageSSLClient);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageSSLCA);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageEmailSigner);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageEmailRecipient);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageObjectSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageVerifyCA);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_INADEQUATE_CERT_TYPE,
+ certificateUsageStatusResponder);
+
+ // Now tests on the EMAIL trust bit
+ setCertTrust(cert_to_modify_trust, 'C,p,C');
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageSSLServer);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageSSLClient);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageSSLCA);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageEmailSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_UNTRUSTED_ISSUER,
+ certificateUsageEmailRecipient);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageObjectSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageVerifyCA);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_INADEQUATE_CERT_TYPE,
+ certificateUsageStatusResponder);
+
+
+ //inherited EMAIL Trust
+ setCertTrust(cert_to_modify_trust, 'C,,C');
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageSSLServer);
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageSSLClient);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageSSLCA);
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageEmailSigner);
+ checkCertErrorGeneric(certdb, ee_cert, isRootCA ? SEC_ERROR_UNKNOWN_ISSUER
+ : PRErrorCodeSuccess,
+ certificateUsageEmailRecipient);
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageObjectSigner);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_CA_CERT_INVALID,
+ certificateUsageVerifyCA);
+ checkCertErrorGeneric(certdb, ee_cert, SEC_ERROR_INADEQUATE_CERT_TYPE,
+ certificateUsageStatusResponder);
+}
+
+
+function run_test() {
+ for (let i = 0 ; i < certList.length; i++) {
+ load_cert(certList[i], ',,');
+ }
+
+ let ca_cert = certdb.findCertByNickname('ca');
+ notEqual(ca_cert, null, "CA cert should be in the cert DB");
+ let int_cert = certdb.findCertByNickname('int');
+ notEqual(int_cert, null, "Intermediate cert should be in the cert DB");
+ let ee_cert = certdb.findCertByNickname('ee');
+ notEqual(ee_cert, null, "EE cert should be in the cert DB");
+
+ setup_basic_trusts(ca_cert, int_cert);
+ test_ca_distrust(ee_cert, ca_cert, true);
+
+ setup_basic_trusts(ca_cert, int_cert);
+ test_ca_distrust(ee_cert, int_cert, false);
+
+ // Reset trust to default ("inherit trust")
+ setCertTrust(ca_cert, ",,");
+ setCertTrust(int_cert, ",,");
+
+ // It turns out that if an end-entity certificate is manually trusted, it can
+ // be the root of its own verified chain. This will be removed in bug 1294580.
+ setCertTrust(ee_cert, "C,,");
+ checkCertErrorGeneric(certdb, ee_cert, PRErrorCodeSuccess,
+ certificateUsageSSLServer);
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_trust/ca.pem b/security/manager/ssl/tests/unit/test_cert_trust/ca.pem
new file mode 100644
index 000000000..1a18e2bf0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_trust/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUL5zykZEc2ro5d6th43aWGfm735cwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
+DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHPYBjNnv//Ssc8Elepb8SWIXRdahKbL
+/dcPoMR+7yhJVaelUaxdwUytJWJAGdkkuv+P+G4b82RVYEXT+9k1S/aAfByFyR9q
+vS7POfdy/ZPfGTXltlnmYX/84a6QeYQa4Nl4JpIOXBCesLxmErBhczka6D26iqsz
+GeseKRSjVPgF3mXc2CRGZnTDRhUmd7wOABLmj7GtuFvOm96363M3IUByMohvoj1G
+dic3s5D0seXwTKnEc5B27lJt7Q0oIXEldL+UW8Mo1hfGWQeXzqTZbpOVLnVWvHBH
+H8yYs5hyH01qFJZbztJ1JJ3F2NpYLlr4P5I6fW2e9w5MG/VMQRU3wzQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_trust/ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_trust/ca.pem.certspec
new file mode 100644
index 000000000..d809dbd63
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_trust/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_cert_trust/ee.pem b/security/manager/ssl/tests/unit/test_cert_trust/ee.pem
new file mode 100644
index 000000000..91c1ffcab
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_trust/ee.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3jCCAcigAwIBAgIUYfpH7OFfqiJDcQnM/gVlKieeyOAwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjANMQswCQYDVQQDDAJlZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAab
+bhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmts
+Du0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhI
+H6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8
+rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kX
+Mbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaM1MDMwMQYDVR0lBCowKAYIKwYBBQUH
+AwEGCCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwMwCwYJKoZIhvcNAQELA4IB
+AQCqaSdnhHXFqLkMT5eU8FiyfpJeMDmyl0UFSB0yXrjh4dsiCayLECagJyVtxFJ/
+K8XBZz3USUOIaK3j8VADK7o6s7dKSy68EacYEF4MtGUpL3Bn7353RSB3hFRfpMuD
+rohMZ8ZBDpvRPddOchpd9OW798duxJWYmotY4wrbK5E+xXhJaaJk4utbx8hqo+xz
+gKusj3w33uYbGQgCNPZ9zbFeyP+1K0vDV5NKC8JdL+KqbECdc9OcpA3jg17owubM
+yovO/bYKzy6bWMpEdzr64JK2n2fDoEQgfwi6O5iC0A7JjOfAkyWYgbrgve5qWamd
+6v71Lnux30zRSwsliFhUl6Md
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_trust/ee.pem.certspec b/security/manager/ssl/tests/unit/test_cert_trust/ee.pem.certspec
new file mode 100644
index 000000000..9666c1806
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_trust/ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:ee
+extension:extKeyUsage:serverAuth,clientAuth,emailProtection,codeSigning
diff --git a/security/manager/ssl/tests/unit/test_cert_trust/int.pem b/security/manager/ssl/tests/unit/test_cert_trust/int.pem
new file mode 100644
index 000000000..fd60e5fe2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_trust/int.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxjCCAbCgAwIBAgIUazy/vTocAuxP85PTc+O1JXs8WWEwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA4xDDAKBgNVBAMMA2ludDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAab
+bhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmts
+Du0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhI
+H6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8
+rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kX
+Mbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNV
+HQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQA6lr0lbqcaGYjYAAcA5BngiUobuYFn
+4jdYK9eR6hiT5PmYRQZ9/y+2aYNF/ygiBBqBdEq/Nhrm35WeUHvDBaT8OZLBjf+g
+krEAmu2ivrHZWrx16HBVDd9JdTUCx8j1HUo5fadFnsQh7nuh/VIoemox+/e8mKfh
++fW3noAoH/MRfP9VYoS0KzkW8ILiWOR1joNOHDZzanMiM/YCHO1nckq2ntI2T+kO
+MNMkB+j1w5Fu6P8pgyToleHs3WmlWAeDjXygZkEhg+9uuBXb8/IyuS3cYt9ovhSh
+++A25JRmqaQn2Ywd+CMsGe4MTYOsRnZPK0Co6TBteRWRdwSpqzb+UOqY
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_trust/int.pem.certspec b/security/manager/ssl/tests/unit/test_cert_trust/int.pem.certspec
new file mode 100644
index 000000000..a7f6d8141
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_trust/int.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_cert_trust/moz.build b/security/manager/ssl/tests/unit/test_cert_trust/moz.build
new file mode 100644
index 000000000..a075d0cb3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_trust/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca.pem',
+# 'ee.pem',
+# 'int.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_cert_version.js b/security/manager/ssl/tests/unit/test_cert_version.js
new file mode 100644
index 000000000..063bcb1cc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version.js
@@ -0,0 +1,190 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Tests the interaction between the basic constraints extension and the
+// certificate version field. In general, the testcases consist of verifying
+// certificate chains of the form:
+//
+// end-entity (issued by) intermediate (issued by) trusted X509v3 root
+//
+// where the intermediate is one of X509 v1, v2, v3, or v4, and either does or
+// does not have the basic constraints extension. If it has the extension, it
+// either does or does not specify that it is a CA.
+//
+// To test cases where the trust anchor has a different version and/or does or
+// does not have the basic constraint extension, there are testcases where the
+// intermediate is trusted as an anchor and the verification is repeated.
+// (Loading a certificate with trust "CTu,," means that it is a trust anchor
+// for SSL. Loading a certificate with trust ",," means that it inherits its
+// trust.)
+//
+// There are also testcases for end-entities issued by a trusted X509v3 root
+// where the end-entities similarly cover the range of versions and basic
+// constraint extensions.
+//
+// Finally, there are testcases for self-signed certificates that, again, cover
+// the range of versions and basic constraint extensions.
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function certFromFile(certName) {
+ return constructCertFromFile("test_cert_version/" + certName + ".pem");
+}
+
+function loadCertWithTrust(certName, trustString) {
+ addCertFromFile(certdb, "test_cert_version/" + certName + ".pem", trustString);
+}
+
+function checkEndEntity(cert, expectedResult) {
+ checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLServer);
+}
+
+function checkIntermediate(cert, expectedResult) {
+ checkCertErrorGeneric(certdb, cert, expectedResult, certificateUsageSSLCA);
+}
+
+// Test that the code that decodes certificates to display them in the
+// certificate manager correctly handles the version field.
+function checkCertVersion(cert, expectedVersionString) {
+ let asn1 = cert.ASN1Structure.QueryInterface(Ci.nsIASN1Sequence);
+ let tbsCertificate = asn1.ASN1Objects.queryElementAt(0, Ci.nsIASN1Sequence);
+ let version = tbsCertificate.ASN1Objects.queryElementAt(0, Ci.nsIASN1Object);
+ equal(version.displayValue, expectedVersionString,
+ "Actual and expected version strings should match");
+}
+
+function run_test() {
+ loadCertWithTrust("ca", "CTu,,");
+
+ // Section for CAs lacking the basicConstraints extension entirely:
+ loadCertWithTrust("int-v1-noBC_ca", ",,");
+ checkIntermediate(certFromFile("int-v1-noBC_ca"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
+ checkEndEntity(certFromFile("ee_int-v1-noBC"), MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA);
+ // A v1 certificate with no basicConstraints extension may issue certificates
+ // if it is a trust anchor.
+ loadCertWithTrust("int-v1-noBC_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v1-noBC_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v1-noBC"), PRErrorCodeSuccess);
+
+ loadCertWithTrust("int-v2-noBC_ca", ",,");
+ checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID);
+ loadCertWithTrust("int-v2-noBC_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v2-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v2-noBC"), SEC_ERROR_CA_CERT_INVALID);
+
+ loadCertWithTrust("int-v3-noBC_ca", ",,");
+ checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID);
+ loadCertWithTrust("int-v3-noBC_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v3-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v3-noBC"), SEC_ERROR_CA_CERT_INVALID);
+
+ loadCertWithTrust("int-v4-noBC_ca", ",,");
+ checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID);
+ loadCertWithTrust("int-v4-noBC_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v4-noBC_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v4-noBC"), SEC_ERROR_CA_CERT_INVALID);
+
+ // Section for CAs with basicConstraints not specifying cA:
+ loadCertWithTrust("int-v1-BC-not-cA_ca", ",,");
+ checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+ loadCertWithTrust("int-v1-BC-not-cA_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v1-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v1-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+
+ loadCertWithTrust("int-v2-BC-not-cA_ca", ",,");
+ checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+ loadCertWithTrust("int-v2-BC-not-cA_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v2-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v2-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+
+ loadCertWithTrust("int-v3-BC-not-cA_ca", ",,");
+ checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+ loadCertWithTrust("int-v3-BC-not-cA_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v3-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v3-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+
+ loadCertWithTrust("int-v4-BC-not-cA_ca", ",,");
+ checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+ loadCertWithTrust("int-v4-BC-not-cA_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v4-BC-not-cA_ca"), SEC_ERROR_CA_CERT_INVALID);
+ checkEndEntity(certFromFile("ee_int-v4-BC-not-cA"), SEC_ERROR_CA_CERT_INVALID);
+
+ // Section for CAs with basicConstraints specifying cA:
+ loadCertWithTrust("int-v1-BC-cA_ca", ",,");
+ checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess);
+ loadCertWithTrust("int-v1-BC-cA_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v1-BC-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v1-BC-cA"), PRErrorCodeSuccess);
+
+ loadCertWithTrust("int-v2-BC-cA_ca", ",,");
+ checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess);
+ loadCertWithTrust("int-v2-BC-cA_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v2-BC-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v2-BC-cA"), PRErrorCodeSuccess);
+
+ loadCertWithTrust("int-v3-BC-cA_ca", ",,");
+ checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess);
+ loadCertWithTrust("int-v3-BC-cA_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v3-BC-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v3-BC-cA"), PRErrorCodeSuccess);
+
+ loadCertWithTrust("int-v4-BC-cA_ca", ",,");
+ checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess);
+ loadCertWithTrust("int-v4-BC-cA_ca", "CTu,,");
+ checkIntermediate(certFromFile("int-v4-BC-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee_int-v4-BC-cA"), PRErrorCodeSuccess);
+
+ // Section for end-entity certificates with various basicConstraints:
+ checkEndEntity(certFromFile("ee-v1-noBC_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-v2-noBC_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-v3-noBC_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-v4-noBC_ca"), PRErrorCodeSuccess);
+
+ checkEndEntity(certFromFile("ee-v1-BC-not-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-v2-BC-not-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-v3-BC-not-cA_ca"), PRErrorCodeSuccess);
+ checkEndEntity(certFromFile("ee-v4-BC-not-cA_ca"), PRErrorCodeSuccess);
+
+ checkEndEntity(certFromFile("ee-v1-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+ checkEndEntity(certFromFile("ee-v2-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+ checkEndEntity(certFromFile("ee-v3-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+ checkEndEntity(certFromFile("ee-v4-BC-cA_ca"), MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY);
+
+ // Section for self-signed certificates:
+ checkEndEntity(certFromFile("ss-v1-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v2-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v3-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v4-noBC"), SEC_ERROR_UNKNOWN_ISSUER);
+
+ checkEndEntity(certFromFile("ss-v1-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v2-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v3-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v4-BC-not-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+
+ checkEndEntity(certFromFile("ss-v1-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v2-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v3-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+ checkEndEntity(certFromFile("ss-v4-BC-cA"), SEC_ERROR_UNKNOWN_ISSUER);
+
+ checkCertVersion(certFromFile("ss-v1-noBC"), "Version 1");
+ checkCertVersion(certFromFile("int-v2-BC-cA_ca"), "Version 2");
+ checkCertVersion(certFromFile("ee-v3-BC-not-cA_ca"), "Version 3");
+ checkCertVersion(certFromFile("int-v4-BC-not-cA_ca"), "Version 4");
+}
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ca.pem
new file mode 100644
index 000000000..d5d688220
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUGamqdMD0Nm1H+VfFhPYfXjLHRokwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzALBgNVHQ8EBAMCAQYwDAYDVR0T
+BAUwAwEB/zALBgkqhkiG9w0BAQsDggEBAAvQClqGp0semC/2XyWMk9xUJfroOET9
+beRv7cv8KUZnG3PaE+J5F7ER7f8COvvamkdeaatPcUc3+6JSErSibRZuwSNu7y55
+8D2DW5tVYNpni/bQCeR2S1SX2wQXOLTDZgYYnAP6dfUUoWIcoqRoQdFo4/clhTCc
+Cdbi7YYMRgiPX1Lr2Wlr6lzA78ri6jul1Xv+x01qDuSGYshXWLy3s4Rn8KcCNdt0
+qeCHYOKY/HdDv4xX/kHrkCm8qxfqLRG6GkbXahySaNm7gaTjFN9tn/n8z1SOz4fQ
+c/lWMN8xE4W645GavbrrTCYG3sMBLF3uXULlIaQb1imtoj/T+cEA/6o=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ca.pem.certspec
new file mode 100644
index 000000000..8689ef9ea
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:keyUsage:keyCertSign,cRLSign
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-cA_ca.pem
new file mode 100644
index 000000000..2b606ba68
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvDCCAaYCFAGWmOxUiv3Wiz/EpnGMkzvZ1CC4MAsGCSqGSIb3DQEBCzANMQsw
+CQYDVQQDDAJjYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAW
+MRQwEgYDVQQDDAtlZS12MS1CQy1jQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zAL
+BgkqhkiG9w0BAQsDggEBAJoTmk+UuRV8BjvLAikw3jMlQLRZksGVezou/oWY6xB0
+5cBhexPniE5Wloareu929H7GroKodIS7byou7brNOFid1WufroaahmS2eKaDoEEr
+OQ7q6KsCKTh7fIi4JOHB43bRpumqAAC/F+PMpyH9breHoMRw70emfbPssbf0sJLt
+fcw6UtxiCLKZ75gQSYvZxwTdzEVon0FMVE/eXpG7TI+5ruzwPhpWbk+NVPTQByjd
+7aBXRjt7IsSM1s4k86FVOFCJW23e+NirdBhpXcIV8JhxOCaDEWlhAK6vGH/cvdHe
+zRU03uzpl4OAngMfjsol790KiyBR6ZcpDeBURiVd1Ms=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-cA_ca.pem.certspec
new file mode 100644
index 000000000..4570e6e3f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-cA_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ee-v1-BC-cA
+version:1
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-not-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-not-cA_ca.pem
new file mode 100644
index 000000000..8fccea824
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-not-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaoCFE1BLhsmfyyB2fW6gUjQwrgYB0uOMAsGCSqGSIb3DQEBCzANMQsw
+CQYDVQQDDAJjYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAa
+MRgwFgYDVQQDDA9lZS12MS1CQy1ub3QtY0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjEDAOMAwGA1UdEwQFMAMB
+AQAwCwYJKoZIhvcNAQELA4IBAQCfLK68eVDBxO0+W/ye0RgZHwRXn5nTaIj8s1iu
+CttV8uBYM1Hw5NUrmpI2bVlZA262qvbKTbhvIPOYz0wD1WkqMabQbuY32XRYKcaM
+cUec2RPy5ZWnZIT4AcYDSGaz8s24223GnlPgresZBhaQ0LzzbSJwtC8S2Fpt5pa1
+V1TenVU1KcjnyiDpGQSj5BsTJG/JONq5eIbP4T1k26Hi9VM8q8bjO0oKBFAxaw6/
+YulGByT8/BoNZXW8yGZu4h2KII7Mun4S13qNgLuGFTT6OJ6/zEwRR3x19o/NhHVm
+pbjyfxFfqnd6HDMAlW1uZt0FtejGPG0ZUL7FlhBy/vTt8Ju+
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-not-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-not-cA_ca.pem.certspec
new file mode 100644
index 000000000..f4257841f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-BC-not-cA_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ee-v1-BC-not-cA
+version:1
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v1-noBC_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-noBC_ca.pem
new file mode 100644
index 000000000..c65444481
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-noBC_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICqTCCAZMCFDG06FmDxQmJyGqH60Gs9a/BJSTTMAsGCSqGSIb3DQEBCzANMQsw
+CQYDVQQDDAJjYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAV
+MRMwEQYDVQQDDAplZS12MS1ub0JDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGc
+BptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzC
+a2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8Xg
+uEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK
+9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGP
+mRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEANnkU
+K6FLFlD2tKjK8Ky22ATkd68zdLs1HxDbVCa57fsToBwAiZdme+mIjQW+w42Zep4Y
+3E0GfjfVNyjVVaEPdLpQiZN8NKB9c/omwoMRyQEq6uhYGTg6o8FcYiQ3/WFBXGc+
+07YmEe9jmhozobUnJ5At5tkymL448qUQ7z9kNHu9L0p2fgEJa146RAyHQ+sXpz4X
+us/+IyqQGaI7q0Hz89clL6tUM9c5Z7r/Jp2UAhpm58ytMpKR0RJuQ5gfDKQKMjPk
+rEfjcxeA40TB5OhKVXYAy2yMJ7hiGByZed3FBSAId/Xmn+ltnaLUocXltgLyB9pG
+TfO49CA2VK0a2vhtaA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v1-noBC_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-noBC_ca.pem.certspec
new file mode 100644
index 000000000..48fe9e541
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v1-noBC_ca.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-v1-noBC
+version:1
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-cA_ca.pem
new file mode 100644
index 000000000..2d16032b3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwTCCAaugAwIBAQIUfQVCkqBjryqY0hxn56/dGr7n01wwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2VlLXYyLUJDLWNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAwDjAMBgNVHRMEBTAD
+AQH/MAsGCSqGSIb3DQEBCwOCAQEABme7cHcrv89ZFbbeOZH3sTrjNOGyAJhRczT2
+muEbJlLCAstllOrIY/KbJHFEi9p7NoEb57ubRweVzhZn7slriY1N8s+jkR3LFlLS
+1e0Xp82FEATF6C/SBhKdnTrz3NBsIG4WPI99x7BTBgCiHYucpOUhd72tpho3wdmK
+/4gPqWIoUyULRJB1NXaDtil3766DBA143mnuIgS34cQerK+vTgxWoUwBKfEzDkzZ
+sl9at4DsZefP7rYOmQ95B0kpM+uI6UUpJYdC9jX/c3JkoZgOZG1sDpQT4quqjoNO
+Hg58ZJ69Vj2GbS8i9tKKVPQLySmiU3L4W0y4XdBMMOfWAdj2qA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-cA_ca.pem.certspec
new file mode 100644
index 000000000..f714725d2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-cA_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ee-v2-BC-cA
+version:2
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-not-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-not-cA_ca.pem
new file mode 100644
index 000000000..224e4f075
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-not-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAQIUf+XAs2m7oSCNvUK7DEGaRr2dTwYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBoxGDAWBgNVBAMMD2VlLXYyLUJDLW5vdC1jQTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMQMA4wDAYDVR0T
+BAUwAwEBADALBgkqhkiG9w0BAQsDggEBALAH32l8H1kmrrw2syJ0p9BTp60bRKty
+1l+kCu7P8ZSH7+eGqROJpvYty9Ao1OrOSyQAfcj0BUn5IsgEDgTogF1PveZlvRtA
+YNd2AFQqP6/lbU8+licG46D0NjUcZRzZZb/daAo91I2qcdIj8VluDhDA4yVh1G/L
+PMIvJ+I/Zscz2M/IlDlH9pdb408YPVOxoK1OdzC7eFsT25hiH+lyn1faPkauY+GF
+m3IVSlUQUOrjpJOQluPKii0j3fdJWGawy7W9Rou9RqcHpEdFx1tdC3Gie/DLrsmJ
+eAfuyJlkK5++IgdlQwLHsTWW/6o6mTfqS7TAsxcBt9tJnLw4fOlaA9s=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-not-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-not-cA_ca.pem.certspec
new file mode 100644
index 000000000..db7228881
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-BC-not-cA_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ee-v2-BC-not-cA
+version:2
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v2-noBC_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-noBC_ca.pem
new file mode 100644
index 000000000..b54cfd23c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-noBC_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrjCCAZigAwIBAQIUdQe+ZPF/+uPABp+LHcJbzs80mlUwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBUxEzARBgNVBAMMCmVlLXYyLW5vQkMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IB
+AQBUaAqzcDmmrd4Wep1/lRJU9qzvkTNfYjE+kjIyW+KlQoh1ESoIgKgMEkIAZ8gW
+VgMwwcLJqqrTyr/Do5gYLzGlSvgi7HWHhu5NbxbbDZ/jKjytVNA/PEGJ7nIh1ka4
+vlwTJBQ/5A4r+2C+IMp2/cAUFHsf2N0ng8ubtl9O9rA5W2Hfz0KMVZ46clcCKCP8
+6KsNqA52FU9s6/z6r2m11YX/QWpO9jVOYcguc4s2PiDPn2R2s/Ok7JqkpVglLehr
+vSlPpeAfqoeSHCr7FfMH/csZ10Ax3XbnPQTnDEfjNxVHcIS3HkUZM5y8X/xm2om3
+BNvtFytBamlQ8Xb/erQ5pmX2
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v2-noBC_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-noBC_ca.pem.certspec
new file mode 100644
index 000000000..cc304ab87
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v2-noBC_ca.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-v2-noBC
+version:2
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-cA_ca.pem
new file mode 100644
index 000000000..0db92cab3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwTCCAaugAwIBAgIUB8OP2Jy4CAmKxxBski29TdDy3JUwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2VlLXYzLUJDLWNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAwDjAMBgNVHRMEBTAD
+AQH/MAsGCSqGSIb3DQEBCwOCAQEAlZW+VCvoVVjk61KPrCGT/npj/xlOkXRO+G3E
+DvvoSEaeq9r5YcSWlb8cuYtLVqWP2S3S5HdgLk8ziIDI/z3y4cEn8j2wyBdYezAy
+N6zpFRwEuWTmdeMQ+xTKf/nyOHGcSyIlXvj6Y2B0T8anAS/vdAa2sfkERt4nMFwd
+Kmwmg+QAnh6MXwb/0EXmX2z5B0qyWlsPy3+CsR+qgWBAOCAUVwjbgMP44XyhgKeX
+bTHJhuIm3yO2ItB5YwDt1DbeH2+Q7+hdnUf1jPKtVha2cnKfnngn10QK4ZApVChg
+OX5fB8CjvMLp5bOa4Pgn962s2KBB2Wy7PV25AbfXKt/Hc3ovuQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-cA_ca.pem.certspec
new file mode 100644
index 000000000..6f69c3574
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-cA_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ee-v3-BC-cA
+version:3
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-not-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-not-cA_ca.pem
new file mode 100644
index 000000000..768871d74
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-not-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUJ20yvWlIyReCYJ+kcsG+DkJ640UwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBoxGDAWBgNVBAMMD2VlLXYzLUJDLW5vdC1jQTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMQMA4wDAYDVR0T
+BAUwAwEBADALBgkqhkiG9w0BAQsDggEBAIOkqY4yOoyfH40DXCLBXL0rrmflioBT
+dl9oRE65btGHLQUn15BQZugBVSbyIdMAv4aeBEt1oqSAB6I4e20rKDeslwexLQtr
+yV2nuAlMTYOBp64UpcG2kG6mAdhYOYICYa67NBNQpc8uvU3hAIoD6kpv+0b3ytRD
+xV4X6cWUcYbqCFIJkans/FrQG/Gy+5Mg2lmdqE1KtkVzq7Tt/QXGaPxhr2rYmuPE
+cNiMAknatOwA4KSaclNkuxkq9axtGCwIa5NNV+4mXrPglWhU6ke5DgO/dln+mfO2
+UB2aj4romZScF2qo9uNaBKyGRAE8yaCxanOGUiwKyl8mOBJ424Xqxkw=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-not-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-not-cA_ca.pem.certspec
new file mode 100644
index 000000000..4a9de0635
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-BC-not-cA_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ee-v3-BC-not-cA
+version:3
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v3-noBC_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-noBC_ca.pem
new file mode 100644
index 000000000..2be86fcdb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-noBC_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrjCCAZigAwIBAgIUWQH07Krh10EOvFLY8UBqyG5xYBYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBUxEzARBgNVBAMMCmVlLXYzLW5vQkMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IB
+AQCQXyyODh2FWO4TxBiuaQdFnFk+2zeqV2iWqpQGFDmgrHCZXrlJM+BVuAFzw0LQ
+hOf9qd33+f2sBDc4lf0qxu5/5Xqt8zERkvK0/zdMz3EpSoLMKvXv+7Z8YH3Ajt3O
+D4SV+3/Pk+/oweJ4XPMTeBhJ7qbU5/aALIzB5hqJHopmkqr8Zi4XTg/VgeZPM9zQ
+47HcOIvWnos99OxRte3xBxOU7aLmXOU4CMvAvzyFI0QCR9yh6UL2f0rICkagfLaB
+vMzUfgCg6dc/yJfroEebIwIJfBdjKNtzkWcIjXKZoNfRwpW7u6qxoopvuQmplg5n
+XnaTJFmePQ15kF2iDzb1hZ4W
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v3-noBC_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-noBC_ca.pem.certspec
new file mode 100644
index 000000000..9d385900f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v3-noBC_ca.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-v3-noBC
+version:3
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-cA_ca.pem
new file mode 100644
index 000000000..e766ae395
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwTCCAaugAwIBAwIUUfTQFSAC8qOhLbeI7Wqaa6VG0fAwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2VlLXY0LUJDLWNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAwDjAMBgNVHRMEBTAD
+AQH/MAsGCSqGSIb3DQEBCwOCAQEAOPqznyrSXvk8Dcw2Y1shbinmUKgIodAD1eHe
+ydM9c77RVLYCtzivERid2WMDVSVtPkniQBSpHh8rq75fUDwUXoUNnlUDi+hE5HBC
+eYc8duCo3Is7FofCqxych1M+WRz/Vr+Dme45/1+7o2YLnp972Vd5WqnNRPBx6B89
+uU1pp7mS1EfNPObYImAD0mHfTLYa4nCoGWrp4tLxChQ79FnOZlZtTykyQoutPeGI
+GI7BW60ABF9t9Z2LNX5hL0idV8jwcQy8XuqRxOgwkdUL5ErezWgN1J6M3zBa4cBX
+aZsU3VuAkImdubbIpPeHQX2Chj4rLXmKxibgJCqKsQqNaTdRFA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-cA_ca.pem.certspec
new file mode 100644
index 000000000..1f44c1dd2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-cA_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ee-v4-BC-cA
+version:4
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-not-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-not-cA_ca.pem
new file mode 100644
index 000000000..627429ed7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-not-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAwIUPW7xxyFS8KpDVIUpRpqCNCmBOuUwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBoxGDAWBgNVBAMMD2VlLXY0LUJDLW5vdC1jQTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMQMA4wDAYDVR0T
+BAUwAwEBADALBgkqhkiG9w0BAQsDggEBALbzCIRcwRjqa1a2Y1wTPVSSSLD80lcW
+il7AGT/hEJ6+uuy9sSl3M+LUU6BMG3XeEERRZg5iWoSvRp0UHGo1ViM+fsgm+C7D
+uby2iVv4nMokrAEZ10azZrgDjEuKQlmdarPzdakoL6YaOXrkP9P4/6v5HeLmxd7I
+Q/iry5TKPFrfkk5xrQwZw8zr8P6ygsnNGZO/MH3+yR4cuSS1piC0i9lO9RAyNk1I
+sAKedwB1sirklVldeWcll9L9WLtYINsn5cWEVKxT2goF0BrkIxNSZLH64tWuIGHG
+Y+QHZqGJum8tYddNuoES8nsKZZ+zAzJ4IrA0NE7MknHrD1Ph7FmnX40=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-not-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-not-cA_ca.pem.certspec
new file mode 100644
index 000000000..e9659153e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-BC-not-cA_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ee-v4-BC-not-cA
+version:4
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v4-noBC_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-noBC_ca.pem
new file mode 100644
index 000000000..1852ea6ce
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-noBC_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrjCCAZigAwIBAwIUVfwLTWJ99GNH7nvKMDko2v0xjCowCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBUxEzARBgNVBAMMCmVlLXY0LW5vQkMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IB
+AQCCJPLfbxTQnHMP1Wl/XpCifu2deo9tcoEb9Hvpc5y9oJUS0qumTMq0H3dVLsnv
++UQ7/YghsGChqveMKVdaeL2UhNvw4nasPLYq2s8nor4+s00moSysgogauvUrQxB+
+SFO09zcX3bVy6/MPrnMVRXlXTCDji8EnI9hcMhQbFfbgd8V+k1oyuDD06PPak5DB
+yR1J+Z673Cp2KhcwIJUNbbOS3wqUU72lanXMzGj8xkhf4GsYYF7e+eWfMDIIlZuj
+mKM1fSCe1m9p9EUVZI3uzuP2NUJbdCsoe8VWGe9TUOEfokmHAykMgKVpbMKsd0Fc
+GAGDU8/x0mGGrA9Jk9T7iagp
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee-v4-noBC_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-noBC_ca.pem.certspec
new file mode 100644
index 000000000..19229ba76
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee-v4-noBC_ca.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ee-v4-noBC
+version:4
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-cA.pem
new file mode 100644
index 000000000..1347bc1ae
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsDCCAZqgAwIBAgIUE6KjPmbDFR43gm22W31CxcYLnNYwCwYJKoZIhvcNAQEL
+MBcxFTATBgNVBAMMDGludC12MS1CQy1jQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
+MTgwMjA1MDAwMDAwWjANMQswCQYDVQQDDAJlZTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQsD
+ggEBAB5f3BeuLOxnnFy7ivHW6k197ycHOS/ilmtfZHxnf6ypIzqq32ooMNfF4+/4
+M3IMfXwe0NuZHiTxwohV58ZEVtfYXQ+tM9E39YQMHemludT4rKgINAEwCHZCXvvn
+txaLMWN1UgQc2aPdlyWagBF6YhmTFExmIUSbe9BnbuIhP00kOls45RnFfcsJJffQ
+lCniEIo+hwRWMjnajh+ecNNFlM3ToTH7+ZUGX6KtfpiBX+kFEtgevNbyghifZ/eY
+HcXNA2LlXbRzKD/xspyk2BnNTaniBwqGQjwWd5IJzEHpvOrqDjEyvx8cGjUFOxsC
++BFqPQs9lD/SOmlPmk66sNw+iMU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-cA.pem.certspec
new file mode 100644
index 000000000..6a7dc5c43
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-cA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v1-BC-cA
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-not-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-not-cA.pem
new file mode 100644
index 000000000..c42913f1f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-not-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtDCCAZ6gAwIBAgIUcUd8DHziTDCWlJ6HrPIr/B8aaUQwCwYJKoZIhvcNAQEL
+MBsxGTAXBgNVBAMMEGludC12MS1CQy1ub3QtY0EwIhgPMjAxNTExMjgwMDAwMDBa
+GA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCZWUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcN
+AQELA4IBAQAuPQwVmkSWN1A59vPXjQNaM+sVKeEiEpRZKbCfhYR0aeutl7MAg5sM
+RiHz2p3H4VALW1J2BdL7CM6X2A101UDY7LO2AEyrzYdm/+fvgd3XFWBeMx/UBZdh
+09I06b0p8tZrQgIk4xIcw/fP5YeYKVnMWcietQ0EnZl9jmqwjvHKTh0x8hkkIDu3
+uY+aByZC4InIcpfgBkqZaJgI7qAGmIokMMs+RHOlGwrOKbsCuvRw/xHIArgmHNfj
++BigwjBIrxW4IT2d0/65O3vlQ9HhMaS+UjXiubny2TZ9I2kvWfLQvAqtPE7DOibe
+zw2iooLP75X/UzNmLpYtr20S9Ea+S3RS
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-not-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-not-cA.pem.certspec
new file mode 100644
index 000000000..639f83d66
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-BC-not-cA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v1-BC-not-cA
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-noBC.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-noBC.pem
new file mode 100644
index 000000000..39cf67e24
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-noBC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUCeeMurpySlbHPa/G6N9eg9Af8+gwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC2ludC12MS1ub0JDMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMA0xCzAJBgNVBAMMAmVlMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEAlYbGEgRSFPynbiDuMRskGkoV+9/53fmP+y8S2YfEGjziuKZOeOIKjG+unU1e
+/2Gz3pktpNr5TwqnDZEIYDvAAy8ByZ9mVUb060rac+7iQxVJCy0epakYA1aIyvXR
+Fk7W3Ivjm6cvl10OqKRySQTqSq708kxg2abLmjqza6AlZlPDCprylVXy9S3op4a5
+TsIiD3R0cmg12AAH19lJVd1jhdKARBaC8d7vXC77+bb4MYngGm3iOX2ZyFkF/0Zp
+OH+xKSVgGHXyfjaecY6JDgyk9zxxeYpPLUSKY8O7KW/2knGxWh5l4rk9+j3oJY2Y
+MvpxLCpOSeibhcsrWXH2UTMosA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-noBC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-noBC.pem.certspec
new file mode 100644
index 000000000..d704f3086
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v1-noBC.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v1-noBC
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-cA.pem
new file mode 100644
index 000000000..5147e4587
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsDCCAZqgAwIBAgIUG9+HDLQWRsQlo2lXC8I4+9uWrlYwCwYJKoZIhvcNAQEL
+MBcxFTATBgNVBAMMDGludC12Mi1CQy1jQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
+MTgwMjA1MDAwMDAwWjANMQswCQYDVQQDDAJlZTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQsD
+ggEBAJjwaeFl75mff+lYb8Gc15TfPZohz05jFR8g4MHuPePn92IpRYsPQfJL/Op4
+dYZJihih/G+1umck/TYExbX1KeY9QGVc6Bb2yVxwPf3t9yv0yhGsOqC055sf6Orl
+1qEgWcjGOnCW4wEe5Tft+K1+1l2J9OMgtcvNs0ctR65D8tdmyFBLQDhvnodaOYDn
+S6RNx9iNPT5jxQHZnBHL6oIwYgSf8xTAPS2+Z+xm4juKHy9T5vW7lujImDWQv+/V
+ugCKgsip92uKKIr+/KbNDXU2x541ewwUm4OxE0x+drHhV8al3VPsnk9VoS9o1Ul1
+aOouSF+BAz3e59YdoNXWPcf9F+M=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-cA.pem.certspec
new file mode 100644
index 000000000..5d3a65e65
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-cA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v2-BC-cA
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-not-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-not-cA.pem
new file mode 100644
index 000000000..4f7042bcf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-not-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtDCCAZ6gAwIBAgIULcr3aXyX5SxQEEPGtPM3p8VlT18wCwYJKoZIhvcNAQEL
+MBsxGTAXBgNVBAMMEGludC12Mi1CQy1ub3QtY0EwIhgPMjAxNTExMjgwMDAwMDBa
+GA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCZWUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcN
+AQELA4IBAQCBsDwvDLVDaEf6o3xzqy5BdF6AcfmqDZNLs1BmcH31yP7eTcXsYHyT
++qUorVz5m1lOfcBJkCQbMDRotZeie9kgQ6APZywD93mC2ELjP8+9WIERy70gPtEn
+L7LvTHT92gdj5tHzhbIsn2TvoGXOYYAH9uQ/5gn/3L74GUoZwMjGWufcqkOEHJJO
+kmrYgOTWy7B64kfuAXzqU2SbUlQ3lxb5ZVv86PPzqPf9JQGXODH/nAzAVq8L9Kdq
+iy0PNK759Xw/1EOpp6vWAMHja2LErji4CWWDmXx/mnvIj7QBPvVAuO0w5/PqrZuz
+i4n84WFh4FYDBUpW6l9Uvek7Zk6xNp1r
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-not-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-not-cA.pem.certspec
new file mode 100644
index 000000000..591a16aca
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-BC-not-cA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v2-BC-not-cA
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-noBC.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-noBC.pem
new file mode 100644
index 000000000..0612422f0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-noBC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUPQUSp52t9MpVcbwvzmrn0rnXe+0wCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC2ludC12Mi1ub0JDMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMA0xCzAJBgNVBAMMAmVlMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEASPKWPlQLYrodnYnFhtEdkne0AK3A/D8KlUrEbUl+SPbI/ORJONH362MSjsWZ
+RKqTz4fYdtqF43iIqlvYaZeLrkGSLTeJ2C+IAeOhiri3b8XjwFF+iXjIYGWnlhyH
+ollM3n7XOJSBOC4S6gMNfofuK7no4H78P82M5wFX6rOCCm9rxv8cvOO+SNlKkaEA
+IWy+taZcj4BOhgl+38VbTs+9ACG+FsLFru62twNQx59j3MbDbHfrIVzY47plHUPU
+jz9s/CCSkUA32ZvbF2rlFQQQf/8Z2oaW/xrWmp2eESLEd4F9NzY+Fvo4PY3k2kkt
+IzRZVoKot3yCAtzPJp0SJ2abgQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-noBC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-noBC.pem.certspec
new file mode 100644
index 000000000..7f99393cf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v2-noBC.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v2-noBC
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-cA.pem
new file mode 100644
index 000000000..ab530840e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsDCCAZqgAwIBAgIUaal9Ye64U6vI3odKwwGkoWeVLnYwCwYJKoZIhvcNAQEL
+MBcxFTATBgNVBAMMDGludC12My1CQy1jQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
+MTgwMjA1MDAwMDAwWjANMQswCQYDVQQDDAJlZTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQsD
+ggEBAG69rgBi4gPJVvu0KAmdgyadfG+89pgH6VyRlP2ZAb26E/UC2vf/fbhFPt1v
+kASTstsxrkmJeTc8aQXjpFqH2uDWoKDNmUmatzka7vFAjwEhKDLeBwihQhepJJCu
+e6Vm0ZnVNsfdXUc4xOdk9w2R91/cF/qxk8OTuB6oSLzpQ3rfvLAXa41GBDHQTQJJ
+R1Y6uYkJRJgyS6aIpZ2x5VCfhTlhKKYalKphZeBj7Ll29/vp04X/42102YpBdN+s
+h/8vqhdQNKFh5A3SvnWeNZTNRt8NizGqqGuv4yHmFPO7Gy+vDg7kj/hI1t+CBQy/
+kb3WFKNABDT7L1NY6kMUGiM5iZg=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-cA.pem.certspec
new file mode 100644
index 000000000..13af934f2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-cA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v3-BC-cA
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-not-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-not-cA.pem
new file mode 100644
index 000000000..4982b6454
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-not-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtDCCAZ6gAwIBAgIUDZZXSGXaQ/utX4RW88viJd7twPIwCwYJKoZIhvcNAQEL
+MBsxGTAXBgNVBAMMEGludC12My1CQy1ub3QtY0EwIhgPMjAxNTExMjgwMDAwMDBa
+GA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCZWUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcN
+AQELA4IBAQAgLJgacqqpseEVlZtg8EM79BOC74xpPk2ggXxlh8+eNc0x9E8yqUR9
++eGPbVpTfDhNO8f1EXHyclW7RSmfYPqZlOFUl0VrqBLF4nHmc3DlXy4xKpNxWrHR
+/dY6WMvfryLba5dNp/aLbVShgGR4o79YnKVioUk8m+Hf26s94Ekn4PQPE/LXAic7
+gvrGYG2V9AXxokuGqBPY08DqMUwYNjPcgctOsoyqZb0VsgxytKv4KGo1q8aEr7at
+9R8vc0bgp6isLU9pDH0LXvSljS1SCZsurDWsWfR+0j2OSFWCBgxvb5oqPc9Jutrb
+4SGvtpYijCq+6ygiRn9dN1JV0RHuGoRl
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-not-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-not-cA.pem.certspec
new file mode 100644
index 000000000..8539715a0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-BC-not-cA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v3-BC-not-cA
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-noBC.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-noBC.pem
new file mode 100644
index 000000000..65f4c3697
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-noBC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUOT2vbH70RwEQY4WI7uJiyJBo3yMwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC2ludC12My1ub0JDMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMA0xCzAJBgNVBAMMAmVlMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEAV1ofl/U7R48I9NqjR3h0ie37k2xQc28cqk2DF+320aO24r2t5JWgSBytewoq
+iCg54QZD7oqdq0JdkHxzNCId1WNFyVFe2+nTiomSJESa/e1Ukbc+vQe0xTqt9dJC
+0ygRdpa3OwNO/8DeYyVZe/XX44p4bLLbsunAr7HFcnWsKFGAOpd1yhEmB7QXW+w6
+xgL+TWmcFHq5FLezt93dFulUQcs394OoUdZ8qKTF0Ge9jZ7CZO3pvudTZ8skMYSY
+j3olnDyQ94tv/y1H8Kxn5chMGbFS4lf4QsRDIBJ6OpPKpEP/St+tY/7yQAHjtjmF
+6buVZsBqPRs39xMJMs2PePp7Cg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-noBC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-noBC.pem.certspec
new file mode 100644
index 000000000..a65e41cea
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v3-noBC.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v3-noBC
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-cA.pem
new file mode 100644
index 000000000..9405db2dd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsDCCAZqgAwIBAgIUJevhGs7hqJR5QVzZzE+05L+1S70wCwYJKoZIhvcNAQEL
+MBcxFTATBgNVBAMMDGludC12NC1CQy1jQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
+MTgwMjA1MDAwMDAwWjANMQswCQYDVQQDDAJlZTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQsD
+ggEBAFkfOzERPOpqPPPuPc+xawfkrg0jx7wktbNnws1FcgF6p0eHL+eDpoQ2DMfE
+jabozGSjj4ZQQ6Ai68gIThllDWMCHCSjLhlxHOPEFWDjeP0mTSdOZTulZxMdbIUm
+zRf+q6FI/2Tv2U7F807xMokMQgw+ndGISpSkKRPIl/PorWh5TU6eUazrrbyegHCW
+xPmNoDhU4SUkdcpe7qDKnbTOb7RYTyFBGU4eMKMA7L0ZqynKo7Wvs5+EWovQSha9
+qeeXdD0wvi2HI7jNXIsYJD5mC1Rocj47/wmppd30iNcIQJu8VNI4YkgS88Y+ogEt
+TzxFJMhZBB+H8Ub8x2Gz3qt4QnE=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-cA.pem.certspec
new file mode 100644
index 000000000..35a3a9ff3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-cA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v4-BC-cA
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-not-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-not-cA.pem
new file mode 100644
index 000000000..767219577
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-not-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtDCCAZ6gAwIBAgIUU3doWVdrXHM0k/ANaNuyVJhR8GwwCwYJKoZIhvcNAQEL
+MBsxGTAXBgNVBAMMEGludC12NC1CQy1ub3QtY0EwIhgPMjAxNTExMjgwMDAwMDBa
+GA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCZWUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcN
+AQELA4IBAQCGs+8b9J0JfOUVFuN15n65KqJadCjcxBn3qBUw5AIYzi10sIFVteG9
+LDN10s92aXwTVYSoVe6ZGM5cJ3MUezHeIrkNklCvsusRvoT4pEoDy/kTmLGLb5z6
+OwBEGYrSB5/jPtcstOBTN0FEbCc8XEGLEQymdB1detTDzmUbWseWvkEnBlf2EYMz
+BdbcE067feMtW9SLo/xCqCHmloEiZ1z8castW0X1tHU4y+T67jgMdE4wwVb5frTm
+8tgg8JPlJlWrtywdAcu2zTW7FiFnmLQ92NFjqIOeb8VybkgcTXX8FxiAbtYLbqpd
+JZ5fpJiTnslxKY1m23DQaG7Yl+Jkif0s
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-not-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-not-cA.pem.certspec
new file mode 100644
index 000000000..7627d3a8a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-BC-not-cA.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v4-BC-not-cA
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-noBC.pem b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-noBC.pem
new file mode 100644
index 000000000..30ee60821
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-noBC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZmgAwIBAgIUYz+f8vqMyWzBNKoQl03ncht2cIIwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC2ludC12NC1ub0JDMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMA0xCzAJBgNVBAMMAmVlMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOC
+AQEArnYzwre41yL4hGRL/xlHQMNsblZK89GB0tovUsHvWScxizomaBN7Nai8Y1JB
+U+6zXjMb3HP8h18Buxvuc0I/+RIUGRhxZ4PbSd/yi1yKaTL1smf5hVscbyMRajvp
+Ws+CBmuwPOcNwvJH4acul2ljySSKX50itQuaKMqjWLmNYPz0PET683QijtQjEre1
+oMIVdq/z438Sv1mdUtRIb38bLzR2PO919lu2WN8ZAI7pQTCLFTg7FdHao4R5QtXp
+n3zqzPgO1xgcvtgMWkeuqC1eUefJrD6+rn7mUFFtEwOzneNIb+xUuBgt5l33OTGn
+v5sHclUaB2LM0cqGtvVkNd3P0Q==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-noBC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-noBC.pem.certspec
new file mode 100644
index 000000000..a78033753
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ee_int-v4-noBC.pem.certspec
@@ -0,0 +1,2 @@
+issuer:int-v4-noBC
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_cert_version/generate.py b/security/manager/ssl/tests/unit/test_cert_version/generate.py
new file mode 100755
index 000000000..7e4747d63
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/generate.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# This file generates the certspec files for test_cert_version.js. The naming
+# convention for those files is generally of the form
+# "<subject-description>_<issuer-description>.pem.certspec". End-entity
+# certificates are generally called "ee". Intermediates are called
+# "int". The root CA is called "ca" and self-signed certificates are called
+# "ss".
+# In the case that the subject and issuer are the same, the redundant part is
+# not repeated.
+# If there is nothing particularly special about a certificate, it has no
+# description ("nothing particularly special" meaning the certificate is X509v3
+# and has or does not have the basic constraints extension as expected by where
+# it is in the hierarchy). Otherwise, the description includes its version and
+# details about the extension. If the extension is not present, the string
+# "noBC" is used. If it is present but the cA bit is not asserted, the string
+# "BC-not-cA" is used. If it is present with the cA bit asserted, the string
+# "BC-cA" is used.
+# For example, a v1 intermediate that does not have the extension that was
+# issued by the root CA has the name "int-v1-noBC_ca.pem.certspec".
+# A v4 end-entity that does have the extension but does not assert the cA bit
+# that was issued by the root CA has the name
+# "ee-v4-BC-not-cA_ca.pem.certspec".
+# An end-entity issued by a v3 intermediate with the extension that asserts the
+# cA bit has the name "ee_int-v3-BC-cA.pem.certspec".
+
+versions = {
+ 'v1': 1,
+ 'v2': 2,
+ 'v3': 3,
+ 'v4': 4
+}
+
+basicConstraintsTypes = {
+ 'noBC': '',
+ 'BC-not-cA': 'extension:basicConstraints:,',
+ 'BC-cA': 'extension:basicConstraints:cA,'
+}
+
+def writeCertspec(issuer, subject, fields):
+ filename = '%s_%s.pem.certspec' % (subject, issuer)
+ if issuer == subject:
+ filename = '%s.pem.certspec' % subject
+ with open(filename, 'w') as f:
+ f.write('issuer:%s\n' % issuer)
+ f.write('subject:%s\n' % subject)
+ for field in fields:
+ if len(field) > 0:
+ f.write('%s\n' % field)
+
+keyUsage = 'extension:keyUsage:keyCertSign,cRLSign'
+basicConstraintsCA = 'extension:basicConstraints:cA,'
+
+writeCertspec('ca', 'ca', [keyUsage, basicConstraintsCA])
+
+for versionStr, versionVal in versions.iteritems():
+ # intermediates
+ versionText = 'version:%s' % versionVal
+ for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
+ intermediateName = 'int-%s-%s' % (versionStr, basicConstraintsType)
+ writeCertspec('ca', intermediateName,
+ [keyUsage, versionText, basicConstraintsExtension])
+ writeCertspec(intermediateName, 'ee', [])
+
+ # end-entities
+ versionText = 'version:%s' % versionVal
+ for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
+ writeCertspec('ca', 'ee-%s-%s' % (versionStr, basicConstraintsType),
+ [versionText, basicConstraintsExtension])
+
+ # self-signed certificates
+ versionText = 'version:%s' % versionVal
+ for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
+ selfSignedName = 'ss-%s-%s' % (versionStr, basicConstraintsType)
+ writeCertspec(selfSignedName, selfSignedName,
+ [versionText, basicConstraintsExtension])
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-cA_ca.pem
new file mode 100644
index 000000000..26e57b926
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-cA_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyjCCAbQCFG9flwxK3L28b9SwsYwGidUsf/MtMAsGCSqGSIb3DQEBCzANMQsw
+CQYDVQQDDAJjYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAX
+MRUwEwYDVQQDDAxpbnQtdjEtQkMtY0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
+sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
+TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
+xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
+tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
+8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAsGA1UdDwQEAwIBBjAM
+BgNVHRMEBTADAQH/MAsGCSqGSIb3DQEBCwOCAQEAYnkJ8m2Q5ercVLL3DPZXrD/i
+zuIn7/ZhtNRrv/CGUOge36bk/6RfYN+rRadM9wHbKKgjXLgA4jDNhjdRXN3QlqKV
+5jxTJuLlu2vX9d81NmmhEk1cs9NMfkKdpXhOFR4nJvVfc0U1UqVpN4yf+U1x/CsT
+KJ2pporpPCIYUwnXiizRXNbUvZJ/GF2HMRZQn+ude87Rm0Q8ifD3yz7CZVKPf6Kk
+Sr9iJubTzLfKfJ1IkLe2yhvrbB5s00OW+kVnudjrFu7ZWKYVM2PJlF40zwYJl4Lr
+o99VmsPFOvBHOAZoV/iQljY2DgauwtBmsa1K8iEPc3osALFM6acD9J4NBTahKw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-cA_ca.pem.certspec
new file mode 100644
index 000000000..77f3ae914
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-cA_ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-v1-BC-cA
+extension:keyUsage:keyCertSign,cRLSign
+version:1
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-not-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-not-cA_ca.pem
new file mode 100644
index 000000000..59ffb040f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-not-cA_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzjCCAbgCFB/qdSZShwQLqEJWGZti66J8bY/MMAsGCSqGSIb3DQEBCzANMQsw
+CQYDVQQDDAJjYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAb
+MRkwFwYDVQQDDBBpbnQtdjEtQkMtbm90LWNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzALBgNVHQ8EBAMC
+AQYwDAYDVR0TBAUwAwEBADALBgkqhkiG9w0BAQsDggEBAEHdkfOCOr648UTiqsPG
+Q2bgBpfQR9q+sloaInyuhUkikrcVEFyDfX906yXpdAOd5vCof/1aC0Uj9rEOfGed
+qqRGELrBP8hJWlUdISOuwSsP9YzdvvDUXCHYK9P0v4vFKN0FPpQ5jXbRbxt2Hlof
+TvcDhd/IwRMT09bM6MuW/UCP7Amg60e9wNCYj+n3SpQcudlQwn3nsDrDeQfdaXqt
+6JEAr7wujeOaLiA0e+i1EG2qeYJ8khEbLjXxeHmuuW40W14rUGygvdv6fLflGvYH
+ZyHNi8pxFryfxet5S45pVPL0i2d0ebbYjOGBp5//CKeN6rwZsP32CMDgTp93lwjL
+ELM=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-not-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-not-cA_ca.pem.certspec
new file mode 100644
index 000000000..2a366535b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v1-BC-not-cA_ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-v1-BC-not-cA
+extension:keyUsage:keyCertSign,cRLSign
+version:1
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v1-noBC_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v1-noBC_ca.pem
new file mode 100644
index 000000000..4f11b699b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v1-noBC_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICuzCCAaUCFBkI5w3s6jLLXnulpMK+fY1ARXT4MAsGCSqGSIb3DQEBCzANMQsw
+CQYDVQQDDAJjYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAW
+MRQwEgYDVQQDDAtpbnQtdjEtbm9CQzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMPMA0wCwYDVR0PBAQDAgEGMAsG
+CSqGSIb3DQEBCwOCAQEAPLtcxQ6cE/ujKoes5ANvhdVSLvu9yLtV3nB0cFi/9JXj
+3duFxIiGyfvci0NdOlg1OQwbO/zTsCDW2zK/xL66QV5UtcEZAWatzI6/2/aqp1PF
++dXbMsieNsVyIjStexjxvEj5flwtA06P0u/i/bMXtEiIIUSwmZ/GPDIyBlcBaJjg
+vBwRXnbPYLE/zKqRz/7rsQvAbrSiGbjeLHTU5jcnXtafEmm9vSAY1fw4fq1Dyz6f
+OwPCdc945ENuo7N+gEMItYw7TKyS5ROmlqDSnhWvL3nrhv9HyxLHKC8MJwRrjKpU
+EocizMzyjzcjY3Gzdc0B3sBBrgcLMEcoFf1v+wrbdw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v1-noBC_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v1-noBC_ca.pem.certspec
new file mode 100644
index 000000000..63bf6ed73
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v1-noBC_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-v1-noBC
+extension:keyUsage:keyCertSign,cRLSign
+version:1
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-cA_ca.pem
new file mode 100644
index 000000000..ee4285cbf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-cA_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbmgAwIBAQIUT7iE9WTjWgXtMmDtZcXlv4QzJ8AwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBcxFTATBgNVBAMMDGludC12Mi1CQy1jQTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswCwYDVR0PBAQD
+AgEGMAwGA1UdEwQFMAMBAf8wCwYJKoZIhvcNAQELA4IBAQAU6AtsSDtT36xwdLKs
+KaiJNQjCrsqYzBYcRKyKHDiTm8naR4sLT27VRIhzPxsz149VF9iFriU+WEdelZSV
+9Ql3bXNX/02TRQxrRP0LMg/3JQq4PexJph2I93W6LQmsGsNgWqwzPInZfUoXu2nK
+wdRxPAGA30PXqzN7e2kGXzD2Nci8ynjsU6EqKwSW9XArD40DRoBJN6OiBwUo9Bem
+EsbVfytYX2bCPkjcFHk0TbhToSFmweGwAOcRO/A6+XM6pjd48kwA9H9CIx7g0NQ9
+q2TNLsvoS9aH7U3S53l8CyVu6hmKF1klQkkZAxa2Mz5KteLOxRxdLnsmRLZ7vwuT
+2tUU
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-cA_ca.pem.certspec
new file mode 100644
index 000000000..ca1bf67a7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-cA_ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-v2-BC-cA
+extension:keyUsage:keyCertSign,cRLSign
+version:2
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-not-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-not-cA_ca.pem
new file mode 100644
index 000000000..f4159d5aa
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-not-cA_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAb2gAwIBAQIUSwfORMpfA9q1z6/EWOfUSx66zNEwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBsxGTAXBgNVBAMMEGludC12Mi1CQy1ub3QtY0EwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAsGA1Ud
+DwQEAwIBBjAMBgNVHRMEBTADAQEAMAsGCSqGSIb3DQEBCwOCAQEAc4IWi7g4uc37
+S3NGcizKEZYsQdSzk4GwMxgX+mdWe2qqnJCer+E3dGrINEMb1blIaah4HGWFfLM5
+2XbBLnp0Jfj0ummvnAcZk5YVqixRgjr1RfzMavZOrCiGFbel4FAO7ht+ICB5AmbM
+W9SzE9z+yMg/bOHur2rbaqZzsQ1a3crBJjWvbGulYm7HYskQx99HPyrib5H3r7Xr
+H98haIpPn8hzYCZBb36iWfSSXvsfmGqGiAn2W2u+L/LwNMo8G3hpNB668myEmKe/
+D1Wdxg15KFLitsE9IaaIoMPQZw0Ir0/dKanAPSqG0hWw2Djw/S1yIwgoq9ylHxxn
+0fq+xxZJXA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-not-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-not-cA_ca.pem.certspec
new file mode 100644
index 000000000..fc28ff150
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v2-BC-not-cA_ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-v2-BC-not-cA
+extension:keyUsage:keyCertSign,cRLSign
+version:2
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v2-noBC_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v2-noBC_ca.pem
new file mode 100644
index 000000000..93d83a2b6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v2-noBC_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaqgAwIBAQIUK0Spe0lKn+U0xO5jDNCuI6z3d+UwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2ludC12Mi1ub0JDMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABow8wDTALBgNVHQ8EBAMC
+AQYwCwYJKoZIhvcNAQELA4IBAQAuydEs4UV5LclC5FsN97v3zL13tWT1+zgaHyxm
+fyGDfNcWXgha2Y2LFc5lqKwZSqMZEL1f5UUAS5Mft64oak7loWKmFrE4oyVRrpGd
+RnzOzmdtztmQxglYIIV4Am7c8pXUtwP7muWrd5myG9LZHwY9I6ZH+tjwV9QlSWaY
+fV+N1Js9auYTb1yhNVGIcRdmdbnutBn5rj+h1b/PsO8CPW4IHxHh3AW7hAnBLhF7
+lMneMbmyodHzpGJRCSjtklgNOG9cMvMoUabGrhVnYQzcTp/Qf8qlKvC51sNeamzj
+ZzUnaZWgU3holgbI6O/1g5uzRaMDAv2zGRPOsU8SMTINunv+
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v2-noBC_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v2-noBC_ca.pem.certspec
new file mode 100644
index 000000000..2d3fe59ff
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v2-noBC_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-v2-noBC
+extension:keyUsage:keyCertSign,cRLSign
+version:2
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-cA_ca.pem
new file mode 100644
index 000000000..a27e8058d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-cA_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbmgAwIBAgIUAaoaQ4IPqjRVOQz/4vo5JrDzcA4wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBcxFTATBgNVBAMMDGludC12My1CQy1jQTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswCwYDVR0PBAQD
+AgEGMAwGA1UdEwQFMAMBAf8wCwYJKoZIhvcNAQELA4IBAQBwyEbiIyk6KMwWZyq5
+F2BxTInFKwnup+Rpmbwa+8o6NzQwjJ1cWszSPiN4akCO5GchrrDulAM6/kRANriA
+5N+J+V5W0+Lr9Skl4kUBEDE0AWj41QW5YTrIli1bjFyfwKydP2almStnYOXmvDaL
+Znlcm81azW5gibGeiLdCMo2RNajW1C2CMZs0TFE1NVbnw85Oaq5/RcUqx8sQ5OyX
+5lkRGWoblzMUp7fY+fle+wgyyJdXSeSAp7SNJbm417SyEFTU2qx+6wqi6R5CE6M1
+R/uYGYH0SyXCGZ6Msng9w4ZAT7XX/ECEC9hfZqDRf/1XS21JOzz6F5y9hkh88Slk
+GwPj
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-cA_ca.pem.certspec
new file mode 100644
index 000000000..56fcb21a0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-cA_ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-v3-BC-cA
+extension:keyUsage:keyCertSign,cRLSign
+version:3
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-not-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-not-cA_ca.pem
new file mode 100644
index 000000000..a7cadbebd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-not-cA_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAb2gAwIBAgIUSZQ7USLXyTqZmjspcuxv8RjZtp4wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBsxGTAXBgNVBAMMEGludC12My1CQy1ub3QtY0EwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAsGA1Ud
+DwQEAwIBBjAMBgNVHRMEBTADAQEAMAsGCSqGSIb3DQEBCwOCAQEAEshHw+MsZRxQ
+2Ozv2sJHTwedcCks2jbm4T9D3/UbMfReMG1s4zjM84O7a1ZxV7SuudtfarwVK9EI
+6atRV4qLSAjZ3VfGjWo/1+rIN+LYTB10MZFefSVvh4BTr+vTEG9va0f0Q70KIwBU
+d9F1iOZiYKvuzmv8mTbVRXAU74CcyGJeyhaGm6+qv4VztdxrUB/fSMTR5lltDJZU
+MKTy3+n5fttP2mnwc5Za7A8Jn0Mqz2TVI2YI8CmCUdvaGqPdTcnQ0Xw31qEu4R9Z
+dzfcLQPZg05VqOTOZzZqr45qIqVhdnOO/rhziIaFPPFkyEejr1vjeqtZW2hiScjX
+h0t+rS7HEA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-not-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-not-cA_ca.pem.certspec
new file mode 100644
index 000000000..a2def8d32
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v3-BC-not-cA_ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-v3-BC-not-cA
+extension:keyUsage:keyCertSign,cRLSign
+version:3
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v3-noBC_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v3-noBC_ca.pem
new file mode 100644
index 000000000..9e342a0d7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v3-noBC_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaqgAwIBAgIUfcNfM4j7uUnlrqBNMfIcXy9g3zUwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2ludC12My1ub0JDMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABow8wDTALBgNVHQ8EBAMC
+AQYwCwYJKoZIhvcNAQELA4IBAQCIsW22mHe+LWhIQm6Ess8r6O68O7G8RW1ELeL5
+Kg+iFXnmRVuC3gK4LH1G1VNIsVj1tGXtYxCJiJ5I4Aybvd+26reA2dCeQRJ6Ja/Q
++RQ5UW2HcbV9E67wYvbvXQlUk5MoY9vOqHAKXksEGxUnqmg2t9K4kFXAe2q9/i2g
+syzV3EtbxADKW4mSLnLyC0AOmNcNB6Sc7/te69GY3BkDriJn5ayj0Xbio6qgfyY9
+jEAXPEnL6fggTB3XBUw3dlez9tweGLwjq4ei0dVymv+q+15qk7FmwJtRSGPYSU9C
+gS7yPOLt4WP14kU3BLV5pPMHgm6Ff+l3UMTBPaHuYnvEHMZW
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v3-noBC_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v3-noBC_ca.pem.certspec
new file mode 100644
index 000000000..b336397ab
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v3-noBC_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-v3-noBC
+extension:keyUsage:keyCertSign,cRLSign
+version:3
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-cA_ca.pem
new file mode 100644
index 000000000..a687058bc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-cA_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbmgAwIBAwIUF3WP7b7JOaJWcP3tKFhcerw7104wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBcxFTATBgNVBAMMDGludC12NC1CQy1jQTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswCwYDVR0PBAQD
+AgEGMAwGA1UdEwQFMAMBAf8wCwYJKoZIhvcNAQELA4IBAQA/+1qhIMJIE46IOGAX
+E6mqNDfKlgv3neuzz7LvO8BwDXKN5c899Y1fQAPG9vvH4x6LfibZuansSKuYlQuo
+ty3+9uD22ZMyva61re+zQQXasxBm+lQ+YqjuTQO9XYwWCcoiW1k9UgwY331Be59Q
+vb4G5MTkIK4IkfXLI1rXywcfYUL551YESILSrfB9YGyfQM87waniXMgYlTVMWjze
+xhf41flw23eA6DspXlIMDIphDjrsdlNLt6M8Kq8ZX2pWNv3bHRW2GXPFTujO3ZX7
+KtEoKDVnRRoLKZUGV800HRvxnxQHix21g7zOh+P7OROsLpqMy8JFyq48RzFbcjRL
+zxX+
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-cA_ca.pem.certspec
new file mode 100644
index 000000000..12b94e63a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-cA_ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-v4-BC-cA
+extension:keyUsage:keyCertSign,cRLSign
+version:4
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-not-cA_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-not-cA_ca.pem
new file mode 100644
index 000000000..ed8fd32d4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-not-cA_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAb2gAwIBAwIUVaZ2niPZ6DLRtuiwINlg8Jk1dZ4wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBsxGTAXBgNVBAMMEGludC12NC1CQy1ub3QtY0EwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAsGA1Ud
+DwQEAwIBBjAMBgNVHRMEBTADAQEAMAsGCSqGSIb3DQEBCwOCAQEAk9BrF+WBvw8N
+Mq2rS506ozxY6ns/n0rD+eOD6lsurV6naqZpu74jagfMqlLBIppFe93yV/epDkPa
+E84mDq6QT+smmosWlG4+HQ2+GnsNC3+savT5WXNCcLZCwWQeZWWndey2Bg0T/flN
+g+2bHUrtGtz+GxfMV2/fwXiC0AD3F/thrrupl4SrS6wcYlaA7RJbGx8y47u1W0Zw
+F0GL+cflyzoZOlXQrcXeCBCSFSQWlmyqOXKsXIHuPjPk4SVo7+IXH/4OQTpMFMVU
+77+brGacqro+d/G83wEMM1mBur2XFYmXRdVAhDOarM3abFcXF3+23xZtv9qRNMRt
+giMNReL6kQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-not-cA_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-not-cA_ca.pem.certspec
new file mode 100644
index 000000000..43a04f70f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v4-BC-not-cA_ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-v4-BC-not-cA
+extension:keyUsage:keyCertSign,cRLSign
+version:4
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v4-noBC_ca.pem b/security/manager/ssl/tests/unit/test_cert_version/int-v4-noBC_ca.pem
new file mode 100644
index 000000000..037046a8b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v4-noBC_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaqgAwIBAwIUFToW9dVGyhNcvbGEpVtHhT1WhgcwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBYxFDASBgNVBAMMC2ludC12NC1ub0JDMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABow8wDTALBgNVHQ8EBAMC
+AQYwCwYJKoZIhvcNAQELA4IBAQAkki/4bWRgG61BREyFJh6R94w2DBEH4J99Fvyu
+T8UaAxbi688qDuKmA7kCZpmtZKRna/d6UWCrU1kHOFpLtRBGcQIDFHAJYuuqsV45
+1tWQXkM/lpt/ZwV8yORiAzMrRgVup7krAolMsQkIK14pLwigwHFGRbZWsU7/dVhD
+JIwAazsl1PVBNYkxGG10GlMdLtXN2xj5aBuxLpOBNIa7l8HSUDS5xU8iO+vRG9Y/
+mMBPcMaQY87GOqTdNTVMZZlp/pLhSZsoMJc5Adm1qDTr5LX0fBcr3ljPoy+WLMOY
+/jSMhLoB+g3A5+N++ac9s4txNh3SSQ5kZ5F9p5z0h0nvfiGP
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/int-v4-noBC_ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/int-v4-noBC_ca.pem.certspec
new file mode 100644
index 000000000..4970d1e94
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/int-v4-noBC_ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-v4-noBC
+extension:keyUsage:keyCertSign,cRLSign
+version:4
diff --git a/security/manager/ssl/tests/unit/test_cert_version/moz.build b/security/manager/ssl/tests/unit/test_cert_version/moz.build
new file mode 100644
index 000000000..acea4142a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/moz.build
@@ -0,0 +1,61 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca.pem',
+# 'ee_int-v1-BC-cA.pem',
+# 'ee_int-v1-BC-not-cA.pem',
+# 'ee_int-v1-noBC.pem',
+# 'ee_int-v2-BC-cA.pem',
+# 'ee_int-v2-BC-not-cA.pem',
+# 'ee_int-v2-noBC.pem',
+# 'ee_int-v3-BC-cA.pem',
+# 'ee_int-v3-BC-not-cA.pem',
+# 'ee_int-v3-noBC.pem',
+# 'ee_int-v4-BC-cA.pem',
+# 'ee_int-v4-BC-not-cA.pem',
+# 'ee_int-v4-noBC.pem',
+# 'ee-v1-BC-cA_ca.pem',
+# 'ee-v1-BC-not-cA_ca.pem',
+# 'ee-v1-noBC_ca.pem',
+# 'ee-v2-BC-cA_ca.pem',
+# 'ee-v2-BC-not-cA_ca.pem',
+# 'ee-v2-noBC_ca.pem',
+# 'ee-v3-BC-cA_ca.pem',
+# 'ee-v3-BC-not-cA_ca.pem',
+# 'ee-v3-noBC_ca.pem',
+# 'ee-v4-BC-cA_ca.pem',
+# 'ee-v4-BC-not-cA_ca.pem',
+# 'ee-v4-noBC_ca.pem',
+# 'int-v1-BC-cA_ca.pem',
+# 'int-v1-BC-not-cA_ca.pem',
+# 'int-v1-noBC_ca.pem',
+# 'int-v2-BC-cA_ca.pem',
+# 'int-v2-BC-not-cA_ca.pem',
+# 'int-v2-noBC_ca.pem',
+# 'int-v3-BC-cA_ca.pem',
+# 'int-v3-BC-not-cA_ca.pem',
+# 'int-v3-noBC_ca.pem',
+# 'int-v4-BC-cA_ca.pem',
+# 'int-v4-BC-not-cA_ca.pem',
+# 'int-v4-noBC_ca.pem',
+# 'ss-v1-BC-cA.pem',
+# 'ss-v1-BC-not-cA.pem',
+# 'ss-v1-noBC.pem',
+# 'ss-v2-BC-cA.pem',
+# 'ss-v2-BC-not-cA.pem',
+# 'ss-v2-noBC.pem',
+# 'ss-v3-BC-cA.pem',
+# 'ss-v3-BC-not-cA.pem',
+# 'ss-v3-noBC.pem',
+# 'ss-v4-BC-cA.pem',
+# 'ss-v4-BC-not-cA.pem',
+# 'ss-v4-noBC.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-cA.pem
new file mode 100644
index 000000000..46f82cebf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa8CFG+MGH0v81ssRXWoQbbMgVkHEf6zMAsGCSqGSIb3DQEBCzAWMRQw
+EgYDVQQDDAtzcy12MS1CQy1jQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAWMRQwEgYDVQQDDAtzcy12MS1CQy1jQTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMQMA4wDAYDVR0T
+BAUwAwEB/zALBgkqhkiG9w0BAQsDggEBAAtZZ5v+5mleP10vnCziNlRqOprKwxmG
+t/tn5sOjQRxHMS6J/SV1zuIM0jkgubN785jj07QorkyTgxyNVumdUq3G0RutzGpq
+paJXYHg0UYJ22N6scGIwuXE/fOh58XNaFpVytGaZIeGAeFcG4lFEHIzOKmRBZAlu
+ba8ger2Vykmm9H7WdYdtUA35jKWNwkF1HABwbxrAFiMLSNt6AWDTYLgoyva77MWP
+6sAN7Vhs8fGqHvSTfwVb1xKPiEyj9R4OWFcyQIfwRrNL9N/9qIfSp0NeQd1duVcu
+MNQSQ/0fCir7rvaz8Wz24jJb+NaAvHpfdzPmvpoI7IuwPv87K2PgPPM=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-cA.pem.certspec
new file mode 100644
index 000000000..731396f03
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-cA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ss-v1-BC-cA
+subject:ss-v1-BC-cA
+version:1
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-not-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-not-cA.pem
new file mode 100644
index 000000000..5f9d30fba
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-not-cA.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbcCFDNyQtXuElhDbK7NjNVK30/fBucMMAsGCSqGSIb3DQEBCzAaMRgw
+FgYDVQQDDA9zcy12MS1CQy1ub3QtY0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowGjEYMBYGA1UEAwwPc3MtdjEtQkMtbm90LWNBMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVK
+tOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7N
+Q/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39Zgsr
+sCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxs
+l62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYl
+nauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAw
+DjAMBgNVHRMEBTADAQEAMAsGCSqGSIb3DQEBCwOCAQEACAgAx20D/LCFt+PpWXMJ
+6ZBaYaoLSZx6oDFeo+6zo4wjEyIhS+l5v5W4f+FnTL4h+DrugV2h2YlgoV2EeQSV
+z/aCd1Q9GG77ui8uGNTnA5iHBYefJFDMxB/n5gm1qJagfLwbQICdJoVEXvRvfrSj
+Y0y0qvzeFBI6tUZ5XwUdsigr6fto1tRHYpZORwJOWvy6m//NQxILBvRWnjsUDD/y
+Yt5yZWxf0/r9md8hyKMBXZ8BqS6xFxoezRLIC4hqhoJNFN3gkxlogFiSi8FtRa86
+ld7vO51lKA9LqtiYlCB/jReEhsE+kGpUspL4f9FXvvnCr7LLqsXI6VoSrCWmsOMP
+rg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-not-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-not-cA.pem.certspec
new file mode 100644
index 000000000..20d716d49
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-BC-not-cA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ss-v1-BC-not-cA
+subject:ss-v1-BC-not-cA
+version:1
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v1-noBC.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-noBC.pem
new file mode 100644
index 000000000..a117460d8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-noBC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsTCCAZsCFA+72QOdH75J3hB9qKX0pOJInjg5MAsGCSqGSIb3DQEBCzAVMRMw
+EQYDVQQDDApzcy12MS1ub0JDMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
+MDAwMDBaMBUxEzARBgNVBAMMCnNzLXYxLW5vQkMwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HH
+Jajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOr
+IMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQ
+sVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLA
+dTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQE
+LL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQEL
+A4IBAQA0Erbg1IXfPrT6ZHl2txIcza4gXrvKHu+Ahq0XIYvJBPVDvwWTQlktJGcq
+BDndGLOYIHkm5CyeOeCIkjGH/6EFg8jLjBrc2RGoaFmhvi9QuDP1DN/082DV69ql
+cJZSYX5usTMRuWECy8k3t8Mf2TqwoGEaTP7tF9chxItJUEjlkuZRbcLf22pb1Hby
+heEVm0m/JHelm1eQI5j0DySS+Am5OTxvCx2WXOyITN7KDHitWalu29DUHNOBLndb
+kMxCHLHLWicpkDrc9o5TRWR+UiQ8fucfaGCgGLK0RIC3AwMSFKmyky1Xx1d5pX5C
+9vfJsSHoJfm86RPkJ37ZRiN3zwJm
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v1-noBC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-noBC.pem.certspec
new file mode 100644
index 000000000..58d2f0d7f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v1-noBC.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ss-v1-noBC
+subject:ss-v1-noBC
+version:1
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-cA.pem
new file mode 100644
index 000000000..c23ff6607
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyjCCAbSgAwIBAQIUG6ex4GpeLkOdyG0kcXwahQ2TJgkwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3NzLXYyLUJDLWNBMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBYxFDASBgNVBAMMC3NzLXYyLUJDLWNBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAwDjAM
+BgNVHRMEBTADAQH/MAsGCSqGSIb3DQEBCwOCAQEAomxNmMoe4s7X2giV3QWVdOUg
+XHye6mFnfsFFZBAnJbYWAy9NcrmKMEReo0APujdZuZkx3LTokBW3A5jAfdeb0l3f
+vxkzgTBSd8XNDm/VnqpMf8ZABWEYpofiMV7fXq1lox2ePyCvh8Ksc22A2ceDy0r3
+gONnMeqRpfb8702R7ZaZzAba3S2kL63Ca40W+Ut1on9hkVxLBb6CM9HKnWl4AacE
+OPtJrJwrwYJKP5Xg3yIOwydHFSVPb9puiBqE+5Da9EcKH3FlXkuMbVcPLQNnQswV
+ThHdBRAZAyXzc/T6CraJiJX8jjFJjX0/JIwZ3LQR+nK2oQ6KoEy33xYi5Gvyqw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-cA.pem.certspec
new file mode 100644
index 000000000..8dbb3a65a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-cA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ss-v2-BC-cA
+subject:ss-v2-BC-cA
+version:2
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-not-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-not-cA.pem
new file mode 100644
index 000000000..2ba60c464
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-not-cA.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0jCCAbygAwIBAQIUBXBWOFiYgovlJC6xNnzLkhSbBi8wCwYJKoZIhvcNAQEL
+MBoxGDAWBgNVBAMMD3NzLXYyLUJDLW5vdC1jQTAiGA8yMDE1MTEyODAwMDAwMFoY
+DzIwMTgwMjA1MDAwMDAwWjAaMRgwFgYDVQQDDA9zcy12Mi1CQy1ub3QtY0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
+2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
+JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
+jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
+BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
+He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
+AAGjEDAOMAwGA1UdEwQFMAMBAQAwCwYJKoZIhvcNAQELA4IBAQAY8GDCVpMGM7xQ
+GjpedV3hiJ47d5ybVaJubldz082/5RhqRtfvZpC3RwzLQzkGsLvqxH87E6KJRHDq
+X5MkAZzuFv49dtQX5BXAiUSDbC33dLNX/+e75LZ7jo3CZQxaHNNu9tlXFiy+661c
+GH4FHDT8mvzDX5lJlmJ1fecPPndH/nnbcgcAVKZgi40xDx87MlrF7R23KXqbxFJ7
+cj8m7cS5t+LlNxCxR2vjPpfVGqA/LgTvOQPm1cn6zji0URDqxRZ+D/3m515lFWu4
+OkV7sf6iEgUo/2mtjvt6I/tbpqc5DKJRrRXXVJXQdXDGptdNIGt3jckOiUKYrLIU
+kzzOuL1s
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-not-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-not-cA.pem.certspec
new file mode 100644
index 000000000..2b8f4bcc5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-BC-not-cA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ss-v2-BC-not-cA
+subject:ss-v2-BC-not-cA
+version:2
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v2-noBC.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-noBC.pem
new file mode 100644
index 000000000..1cd6979a6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-noBC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtjCCAaCgAwIBAQIUAYdFdolsf3VTBZ0ZsXUBgHZHnHQwCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCnNzLXYyLW5vQkMwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowFTETMBEGA1UEAwwKc3MtdjItbm9CQzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhX
+bCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQ
+OCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9
+uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFb
+t+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhO
+NsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG
+9w0BAQsDggEBAJFhWwC68S3SAhj2d/wI3LhqlnFgaL0MYBENqhs4RhqUkhIzbQ1f
+6Jc78Gd275ftrR8tcZ4PlQYrJY/rJuLzfq0JL8gCjv4K0SS/l5+LKZE6wjmoVjbZ
+VZaErdkslU/lRczACBA08F7w+rHBQ6oj6pVaKXXbIZscduFvHentJENSyvgPqhOs
+X1pAxIT2klwAeYwajCm1UmjlXNtKSFJZHDG6qCf/ZPplXt/rRdH89t9r1lttZLNV
++eVzbYYcpjY25eOo87FAYOBG/8fjMt3XTs0WtlxnvFA8cieB+cJ7LyIO9TWasaWc
+YX2IonPVrXSUj4APt2tknTcHF/PIcx69diQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v2-noBC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-noBC.pem.certspec
new file mode 100644
index 000000000..7656115a8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v2-noBC.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ss-v2-noBC
+subject:ss-v2-noBC
+version:2
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-cA.pem
new file mode 100644
index 000000000..ea4a18024
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyjCCAbSgAwIBAgIUG8cSSK9riYlFB7ouvuMQGSlW+UcwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3NzLXYzLUJDLWNBMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBYxFDASBgNVBAMMC3NzLXYzLUJDLWNBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAwDjAM
+BgNVHRMEBTADAQH/MAsGCSqGSIb3DQEBCwOCAQEAf59Fuz/pD+aAq2EpVeVNNhNW
+ACZLNmzlM7xiodW2Nd5g9w521u58wzmMp7d8jIIzjG4Io3kpK35hcQQaacI7QzQf
+mOOtT2s4KtlpKmnm6X4eGHO5Wjyn7mkfZ/s75RP21CB9d5989Yz+eB2kBfXU0dja
+TBeFKoPnX+MMzucm9JMLhZ4YbxMXbuQOmm5wl4kq44aaQ8m6GsHNIwz5x0XPoCVN
+0VCUxF4f79+LBW7L7MlH1u+iaI82jemwMud2mymBy+nr+3K0mARqAhjjJzF2GEKX
+B8FL2Q2/fHubMK/UmLJQI0L9WS02nuafIGl20xOndFEaTLNKFjrrsCip5Updnw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-cA.pem.certspec
new file mode 100644
index 000000000..df822e99b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-cA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ss-v3-BC-cA
+subject:ss-v3-BC-cA
+version:3
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-not-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-not-cA.pem
new file mode 100644
index 000000000..f612c29fd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-not-cA.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0jCCAbygAwIBAgIUD1Zrxy5fGFnW0HiU7Wd4Lr2CuQwwCwYJKoZIhvcNAQEL
+MBoxGDAWBgNVBAMMD3NzLXYzLUJDLW5vdC1jQTAiGA8yMDE1MTEyODAwMDAwMFoY
+DzIwMTgwMjA1MDAwMDAwWjAaMRgwFgYDVQQDDA9zcy12My1CQy1ub3QtY0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
+2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
+JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
+jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
+BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
+He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
+AAGjEDAOMAwGA1UdEwQFMAMBAQAwCwYJKoZIhvcNAQELA4IBAQCSHxtOuFzFQjXj
+uYkrCHQ+7h7j5AZi3p3XZvuo8oxzbBb6vmwvTguRkeZzwgN+FWE8IhXMlqE+avh9
+hnDZOygI+w3gtfXtevlnh3ngnr85op4nJ2CJ0O5X6s8wRsX544mM8d8NxriP1tr0
+fB3Dq0Y8WkUkocdV/NuvTnw4gldDl67Imj2J6lYXDfLmCFQYKga1b+OTX/KOUXIy
+VsUwOX1aPY6PUO2IVdX8n/sY8NcGJkf37DxqgcE410GvGHJw4qOgjJxMT0/xDYP8
+FY8yiB/y/mWWw/W1+duWOUO0BfmYH+MrSduUb1IXM06DWZgTbECjcVaqLYnRjgR8
+/ARSmye4
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-not-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-not-cA.pem.certspec
new file mode 100644
index 000000000..0b2b57557
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-BC-not-cA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ss-v3-BC-not-cA
+subject:ss-v3-BC-not-cA
+version:3
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v3-noBC.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-noBC.pem
new file mode 100644
index 000000000..849fbcda2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-noBC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtjCCAaCgAwIBAgIUG/zabaMDrPkuXBAyLcu1A8K/9Q8wCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCnNzLXYzLW5vQkMwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowFTETMBEGA1UEAwwKc3MtdjMtbm9CQzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhX
+bCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQ
+OCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9
+uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFb
+t+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhO
+NsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG
+9w0BAQsDggEBAFzvJODJBLHGofBQQN0lF3DnB3LOcUMT7noPkAx/fTwjLaomazG+
+pvHOxQTUAXg4SHVQRM+z8y16FertnjVKRBdAQrdWzPFWYxdgafUBTXqpIbZFGbKY
+swQSBBrq6AhjNAx309Y9qW5RfOFer0KNWXV01892euHjL288n+Nn6Kzu2re/Bf29
++uqqpceA2oGgsB83Jcl6LxI2rmF6g38fBtL/TzDmNxcP1lrxUlehosm4sC79dSKJ
+ckbKWSl+IpMI4u3h2MNEOhK5Ip8T2gG0CBI0SZZt7iz4tu4h23KS8RYvQVrySTY7
+5Z2518kyyjVKuhaHcQRN3W/7egP24QRobL8=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v3-noBC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-noBC.pem.certspec
new file mode 100644
index 000000000..96314e51a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v3-noBC.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ss-v3-noBC
+subject:ss-v3-noBC
+version:3
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-cA.pem
new file mode 100644
index 000000000..01e952442
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-cA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyjCCAbSgAwIBAwIUH+0Y+pqW4DjsOBgkkQppZLmj5PcwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3NzLXY0LUJDLWNBMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBYxFDASBgNVBAMMC3NzLXY0LUJDLWNBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAwDjAM
+BgNVHRMEBTADAQH/MAsGCSqGSIb3DQEBCwOCAQEALzgRDh0qh5j+RMgGQcWEPwcB
+0BElZ/R2uZkLppQkFE++NXW/c55ze+58AL9SiE2KcvcuPXcawOutofca1d00msEd
+NIACsU4/R0di4OuxeZEG/3TMT9s45zNgIEScuHN9TG51DYMi+9weNjOohScutTa1
+SZzqxysC8sU6nvjaDKz2CUzp6f4Ihmrs8pf2yn5JGiyL8huPl55pQyjBfhP3kDB4
+w9XnuL3c10RutYpU6PjHYy7ISQRMCkMypTQauOdwlEnQZss8vo3Unb0INyYssHct
+X9owoNW3VZ1QRs5rbzDjhA5x+z9pOcabfnQCEnDaV+3r9bZmHIkQIFQMugJbfg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-cA.pem.certspec
new file mode 100644
index 000000000..54269184e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-cA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ss-v4-BC-cA
+subject:ss-v4-BC-cA
+version:4
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-not-cA.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-not-cA.pem
new file mode 100644
index 000000000..b876791f4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-not-cA.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0jCCAbygAwIBAwIUT5RKOqGvbweUZwI3IGU68VrjHL0wCwYJKoZIhvcNAQEL
+MBoxGDAWBgNVBAMMD3NzLXY0LUJDLW5vdC1jQTAiGA8yMDE1MTEyODAwMDAwMFoY
+DzIwMTgwMjA1MDAwMDAwWjAaMRgwFgYDVQQDDA9zcy12NC1CQy1ub3QtY0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
+2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
+JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
+jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
+BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
+He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
+AAGjEDAOMAwGA1UdEwQFMAMBAQAwCwYJKoZIhvcNAQELA4IBAQBuALYv+/5x11NR
+7e3rxtG5sT2+hUF63oeJMfGEzP1pBtTpokNKTSQSOzJ96816MTCBbHEjt5VEjYk6
+yj5Kswws38XWMOBv21t4HNYzrdUqVVVRJxfQ6waQN5uAgUS8Wo8tSSXN+pAQ9dpB
+GCMvhPaCmi0F601hU6RnpJNsgoIORMtwJupH11VY11W+zrqOhP1Jnob5x2IIakvD
+/HqSANIhpNjmCKgA5ZQqfFbs0AF/tNGqQ9ikGOBZqBP47sOo9c9FHfchcrq0u+D3
+N4OO0909F5lgb4RQ/g9prlR5CIYh/g1dWG7FPCRaYDPt4DySe26UE60+JBP2re2U
+NiSd3N/5
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-not-cA.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-not-cA.pem.certspec
new file mode 100644
index 000000000..3d6533531
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-BC-not-cA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ss-v4-BC-not-cA
+subject:ss-v4-BC-not-cA
+version:4
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v4-noBC.pem b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-noBC.pem
new file mode 100644
index 000000000..317319c72
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-noBC.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtjCCAaCgAwIBAwIUb9qH5069BVlQbXHC3yvfCnwPbAEwCwYJKoZIhvcNAQEL
+MBUxEzARBgNVBAMMCnNzLXY0LW5vQkMwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
+MDIwNTAwMDAwMFowFTETMBEGA1UEAwwKc3MtdjQtbm9CQzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhX
+bCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQ
+OCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9
+uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFb
+t+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhO
+NsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG
+9w0BAQsDggEBAGx6Hb+TuW/T3OAjH1ZgpUxfWqFthTXoIioS6VhSkUQHa0Ay6xc3
+ieaYhIzOS52IYbqLQLgyOLHb2TxMsmHltlnGAgpJrlnon/48OPkmYsUOA3XpqXfo
+KBiCr6QNK+wPunPKPA2stHsqykC1///Hjrz9G8ZibDH5ESu96vgMjxqkpI1bgRyS
+69XrzctGnwwLaXzhrsNPlP+D/VkSyhrRGih3AHXXdda6s5hqEu8yaSN0kP4oG7gL
+wZcbMRttpIW/ZvihypwUyHSgVsZFeuW8PnDzQF7QwMg88rIBExaTz1RQA9zF7Ft7
+AXbf39HewK1XfLnuZdtYlu5zZBz1Qc/7Q4M=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_cert_version/ss-v4-noBC.pem.certspec b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-noBC.pem.certspec
new file mode 100644
index 000000000..d02e04de5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_version/ss-v4-noBC.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ss-v4-noBC
+subject:ss-v4-noBC
+version:4
diff --git a/security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js
new file mode 100644
index 000000000..2c244aad7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js
@@ -0,0 +1,62 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Checks that invalid OID encodings are detected in the Cert Viewer Details tab.
+
+do_get_profile(); // Must be called before getting nsIX509CertDB
+const certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function certFromFile(filename) {
+ return constructCertFromFile(`test_certviewer_invalid_oids/${filename}.pem`);
+}
+
+function test(certFilename, expectedOIDText) {
+ let cert = certFromFile(certFilename);
+ let certDumpTree = Cc["@mozilla.org/security/nsASN1Tree;1"]
+ .createInstance(Ci.nsIASN1Tree);
+ certDumpTree.loadASN1Structure(cert.ASN1Structure);
+ let actualOIDText = certDumpTree.getDisplayData(9);
+
+ equal(actualOIDText, expectedOIDText,
+ "Actual and expected OID text should match");
+}
+
+function run_test() {
+ test("bug483440-attack2b",
+ "Object Identifier (2 5 4 Unknown) = www.bank.com\n" +
+ "OU = Hacking Division\n" +
+ "CN = www.badguy.com\nO = Badguy Inc\n");
+
+ test("bug483440-pk10oflo",
+ "Object Identifier (2 5 4 Unknown) = www.bank.com\n" +
+ "OU = Hacking Division\n" +
+ "CN = www.badguy.com\nO = Badguy Inc\n");
+
+ test("bug483440-attack7",
+
+ // Check 88 80 80 80 01, not leading, have to pass
+ "Object Identifier (2 5 4 2147483649) = attack1\n" +
+
+ // Check 90 80 80 80 01, not leading, have to fail
+ "Object Identifier (2 5 4 Unknown) = attack2\n" +
+
+ // Check 80 80 80 80 80, not leading, have to fail
+ "Object Identifier (2 5 4 Unknown) = attack3\n" +
+
+ // Check 81 81, trailing, have to fail
+ "Object Identifier (2 5 4 3 Unknown) = attack4\n" +
+
+ // Check FF FF FF 7F, not leading, have to pass
+ "Object Identifier (2 5 4 268435455) = attack5\n" +
+
+ // Check 80 leading, have to fail
+ "Object Identifier (Unknown 3) = attack6\n" +
+
+ // Check 14757 = 2*40 + 14677 leading single byte encoded as F325,
+ // have to pass
+ "Object Identifier (2 14677 4 3) = attack7\n");
+}
diff --git a/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack2b.pem b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack2b.pem
new file mode 100644
index 000000000..8adcf2ac1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack2b.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICKDCCAZGgAwIBAgIFAIyjFPowDQYJKoZIhvcNAQEFBQAwKDEXMBUGA1UEAwwO
+KgB3d3cubXlDQS5vcmcxDTALBgNVBAMTBG15Q0EwHhcNMDkwMzE0MTg0NzU2WhcN
+MTkwMzE0MTg0NzU2WjBhMRMwEQYDVQQKEwpCYWRndXkgSW5jMRcwFQYDVQQDEw53
+d3cuYmFkZ3V5LmNvbTEZMBcGA1UECxMQSGFja2luZyBEaXZpc2lvbjEWMBQGBFUE
+gAMTDHd3dy5iYW5rLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2YvL
+GgmF0OTLBKz0nYTvR+DlnZai7b2MqAIM9IUEpMfqzJPNYCsXziYXgHtr/do9ppJP
+BhDjeyIGEOSpgBqdkWItxlLopUHnf8VKwnDPPj4KkNyXuTLm60X/ph+/zrjTw+kU
+m+/kVYstgGMuTIoTuu7loxCqqeVlAgc5lzTpUhkCAwEAAaMlMCMwDAYDVR0TAQH/
+BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOBgQAKHl1G
+vaXftj5QPK3eIT6Q3fWuGKR39grlg5GL/WocPanYycOlm9zvT1Hx95cY6msIXSKp
+xycndJ02ODX35DDgolV6VHUsM9yoagk+eqs5kCqW2qiv3moIshL0yWVhuCobMA+E
+D3wHFCPqVU+igRdCrEQDxZHoFOR4J/DKHfGANg==
+-----END CERTIFICATE-----
diff --git a/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack7.pem b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack7.pem
new file mode 100644
index 000000000..778e7aced
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack7.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICljCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBkDERMA8GBPMlBAMTB2F0
+dGFjazcxEDAOBgOABAMTB2F0dGFjazYxEzARBgZVBP///38TB2F0dGFjazUxEjAQ
+BgVVBAOBgRMHYXR0YWNrNDEUMBIGB1UEgICAgIATB2F0dGFjazMxFDASBgdVBJCA
+gIABEwdhdHRhY2syMRQwEgYHVQSIgICAARMHYXR0YWNrMTAeFw0wOTA0MTMxNDAw
+MzdaFw0yOTA0MTMxNDAwMzdaMIGQMREwDwYE8yUEAxMHYXR0YWNrNzEQMA4GA4AE
+AxMHYXR0YWNrNjETMBEGBlUE////fxMHYXR0YWNrNTESMBAGBVUEA4GBEwdhdHRh
+Y2s0MRQwEgYHVQSAgICAgBMHYXR0YWNrMzEUMBIGB1UEkICAgAETB2F0dGFjazIx
+FDASBgdVBIiAgIABEwdhdHRhY2sxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQC77fQ1wrywBnVmr8XO0/78/qFOz+sjnMlpBvLx5UImittgMNSgEqNulRDbO0qG
+K4tlFF2sNsS7aOun6Cq7yl2+a8mIljmjzs+iwCLOEAkQTOM4RsdCosJVy/fjwmH1
+xI0uXt5cPkA0FM7B/IZSzWSC+2gY1+u1AhRJ35bXDhu92wIDAQABMA0GCSqGSIb3
+DQEBBQUAA4GBAFZitQjsQJ1+XsxKchBefilaHsi4oncc05P29IXcRbHI8wK2vNk8
+kkG2c6M4a4Rx1R4C3n99NwXH4vyNUbA9FuMSAdjaS3TW3zm8lKNCuIWGuI2Vvefy
++wNcCfb8B4AuP8pZOqqKsspgiBAE1EPPErnb7nMVLCnf+ts9ARXLBZTi
+-----END CERTIFICATE-----
diff --git a/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-pk10oflo.pem b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-pk10oflo.pem
new file mode 100644
index 000000000..7daef524b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-pk10oflo.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICMTCCAZqgAwIBAgIFAIyjFTAwDQYJKoZIhvcNAQEFBQAwKDEXMBUGA1UEAwwO
+KgB3d3cubXlDQS5vcmcxDTALBgNVBAMTBG15Q0EwHhcNMDkwMzE0MTg0ODI0WhcN
+MTkwMzE0MTg0ODI0WjBqMRMwEQYDVQQKEwpCYWRndXkgSW5jMRcwFQYDVQQDEw53
+d3cuYmFkZ3V5LmNvbTEZMBcGA1UECxMQSGFja2luZyBEaXZpc2lvbjEfMB0GDVUE
+goCAgICAgICAgAMTDHd3dy5iYW5rLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEA2YvLGgmF0OTLBKz0nYTvR+DlnZai7b2MqAIM9IUEpMfqzJPNYCsXziYX
+gHtr/do9ppJPBhDjeyIGEOSpgBqdkWItxlLopUHnf8VKwnDPPj4KkNyXuTLm60X/
+ph+/zrjTw+kUm+/kVYstgGMuTIoTuu7loxCqqeVlAgc5lzTpUhkCAwEAAaMlMCMw
+DAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUF
+AAOBgQBr+ekYoADBm6kbHBR1oc/6O9ZciRsTbxIAl3xjA3kNEeiUXXSoe+1dlt3Z
+7D6EaQztqR8usCW728J3vi8p/XxociK3r4aq0Sxu29gp21N1V/Um8y3ssI+Yt9Im
+oHlo5ikUXra5PtGAwi4FymrU5dWlHxYk1PlNP5nsvxdElPZnZA==
+-----END CERTIFICATE-----
diff --git a/security/manager/ssl/tests/unit/test_constructX509FromBase64.js b/security/manager/ssl/tests/unit/test_constructX509FromBase64.js
new file mode 100644
index 000000000..d44e249c2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_constructX509FromBase64.js
@@ -0,0 +1,69 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Checks that ConstructX509FromBase64() accepts valid input and rejects invalid
+// input.
+
+do_get_profile(); // Must be called before getting nsIX509CertDB
+const certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function excMessage(e) {
+ if (e.message) {
+ let msg = e.message;
+ if (e.data) {
+ msg = msg + ": " + e.data;
+ }
+ return msg;
+ }
+
+ return e.toString();
+}
+
+function testGood(data) {
+ try {
+ let cert = certDB.constructX509FromBase64(data.cert);
+ equal(cert.commonName, data.cn,
+ "Actual and expected commonName should match");
+ } catch (e) {
+ do_print(`Exception: ${excMessage(e)}`);
+ ok(false, `Should not have gotten an exception for "CN=${data.cn}"`);
+ }
+}
+
+function testBad(data) {
+ throws(() => certDB.constructX509FromBase64(data.input), data.result,
+ `Should get "${data.result}" for "${data.input}"`);
+}
+
+function run_test() {
+ const badCases = [
+ // Wrong type or too short
+ { input: null, result: /NS_ERROR_ILLEGAL_VALUE/ },
+ { input: "", result: /NS_ERROR_ILLEGAL_VALUE/ },
+ { input: "=", result: /NS_ERROR_ILLEGAL_VALUE/ },
+ { input: "==", result: /NS_ERROR_ILLEGAL_VALUE/ },
+ // Not base64
+ { input: "forty-four dead stone lions", result: /NS_ERROR_ILLEGAL_VALUE/ },
+ // Not a cert
+ { input: "Zm9ydHktZm91ciBkZWFkIHN0b25lIGxpb25z",
+ result: /NS_ERROR_FAILURE/ },
+ ];
+
+ // Real certs with all three padding levels
+ const goodCases = [
+ { cn: "A", cert: "MIHhMIGcAgEAMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNVBAMTAUEwHhcNMTEwMzIzMjMyNTE3WhcNMTEwNDIyMjMyNTE3WjAMMQowCAYDVQQDEwFBMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxANFm7ZCfYNJViaDWTFuMClX3+9u18VFGiyLfM6xJrxir4QVtQC7VUC/WUGoBUs9COQIDAQABMA0GCSqGSIb3DQEBBQUAAzEAx2+gIwmuYjJO5SyabqIm4lB1MandHH1HQc0y0tUFshBOMESTzQRPSVwPn77a6R9t" },
+ { cn: "Bo", cert: "MIHjMIGeAgEAMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAMTAkJvMB4XDTExMDMyMzIzMjYwMloXDTExMDQyMjIzMjYwMlowDTELMAkGA1UEAxMCQm8wTDANBgkqhkiG9w0BAQEFAAM7ADA4AjEA1FoSl9w9HqMqVgk2K0J3OTiRsgHeNsQdPUl6S82ME33gH+E56PcWZA3nse+fpS3NAgMBAAEwDQYJKoZIhvcNAQEFBQADMQAo/e3BvQAmygiATljQ68tWPoWcbMwa1xxAvpWTEc1LOvMqeDBinBUqbAbSmPhGWb4=" },
+ { cn: "Cid", cert: "MIHlMIGgAgEAMA0GCSqGSIb3DQEBBQUAMA4xDDAKBgNVBAMTA0NpZDAeFw0xMTAzMjMyMzI2MzJaFw0xMTA0MjIyMzI2MzJaMA4xDDAKBgNVBAMTA0NpZDBMMA0GCSqGSIb3DQEBAQUAAzsAMDgCMQDUUxlF5xKN+8KCSsR83sN+SRwJmZdliXsnBB7PU0OgbmOWN0u8yehRkmu39kN9tzcCAwEAATANBgkqhkiG9w0BAQUFAAMxAJ3UScNqRcjHFrNu4nuwRldZLJlVJvRYXp982V4/kYodQEGN4gJ+Qyj+HTsaXy5x/w==" }
+ ];
+
+ for (let badCase of badCases) {
+ testBad(badCase);
+ }
+ for (let goodCase of goodCases) {
+ testGood(goodCase);
+ }
+}
diff --git a/security/manager/ssl/tests/unit/test_content_signing.js b/security/manager/ssl/tests/unit/test_content_signing.js
new file mode 100644
index 000000000..99ea33a3a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing.js
@@ -0,0 +1,266 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// These tests ensure content signatures are working correctly.
+
+// First, we need to set up some data
+const PREF_SIGNATURE_ROOT = "security.content.signature.root_hash";
+
+const TEST_DATA_DIR = "test_content_signing/";
+
+const ONECRL_NAME = "oneCRL-signer.mozilla.org";
+const ABOUT_NEWTAB_NAME = "remotenewtab.content-signature.mozilla.org";
+
+function getSignatureVerifier() {
+ return Cc["@mozilla.org/security/contentsignatureverifier;1"]
+ .createInstance(Ci.nsIContentSignatureVerifier);
+}
+
+function setRoot(filename) {
+ let cert = constructCertFromFile(filename);
+ Services.prefs.setCharPref(PREF_SIGNATURE_ROOT, cert.sha256Fingerprint);
+}
+
+function loadChain(prefix, names) {
+ let chain = [];
+ for (let name of names) {
+ let filename = `${prefix}_${name}.pem`;
+ chain.push(readFile(do_get_file(filename)));
+ }
+ return chain;
+}
+
+function run_test() {
+ // set up some data
+ const DATA = readFile(do_get_file(TEST_DATA_DIR + 'test.txt'));
+ const GOOD_SIGNATURE = "p384ecdsa=" +
+ readFile(do_get_file(TEST_DATA_DIR + 'test.txt.signature'))
+ .trim();
+
+ const BAD_SIGNATURE = "p384ecdsa=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2r" +
+ "UWM4GJke4pE8ecHiXoi-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1G" +
+ "q25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L";
+
+ let remoteNewTabChain = loadChain(TEST_DATA_DIR + "content_signing",
+ ["remote_newtab_ee", "int", "root"]);
+
+ let oneCRLChain = loadChain(TEST_DATA_DIR + "content_signing",
+ ["onecrl_ee", "int", "root"]);
+
+ let oneCRLBadKeyChain = loadChain(TEST_DATA_DIR + "content_signing",
+ ["onecrl_wrong_key_ee", "int", "root"]);
+
+ let oneCRLRSAKeyChain = loadChain(TEST_DATA_DIR + "content_signing",
+ ["onecrl_RSA_ee", "int", "root"]);
+
+ let noSANChain = loadChain(TEST_DATA_DIR + "content_signing",
+ ["onecrl_no_SAN_ee", "int", "root"]);
+
+ // Check signature verification works without error before the root is set
+ let chain1 = oneCRLChain.join("\n");
+ let verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
+ "Before the root is set, signatures should fail to verify but not throw.");
+
+ setRoot(TEST_DATA_DIR + "content_signing_root.pem");
+
+ // Check good signatures from good certificates with the correct SAN
+ verifier = getSignatureVerifier();
+ ok(verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
+ "A OneCRL signature should verify with the OneCRL chain");
+ let chain2 = remoteNewTabChain.join("\n");
+ verifier = getSignatureVerifier();
+ ok(verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
+ ABOUT_NEWTAB_NAME),
+ "A newtab signature should verify with the newtab chain");
+
+ // Check a bad signature when a good chain is provided
+ chain1 = oneCRLChain.join("\n");
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, BAD_SIGNATURE, chain1, ONECRL_NAME),
+ "A bad signature should not verify");
+
+ // Check a good signature from cert with good SAN but a different key than the
+ // one used to create the signature
+ let badKeyChain = oneCRLBadKeyChain.join("\n");
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, badKeyChain,
+ ONECRL_NAME),
+ "A signature should not verify if the signing key is wrong");
+
+ // Check a good signature from cert with good SAN but a different key than the
+ // one used to create the signature (this time, an RSA key)
+ let rsaKeyChain = oneCRLBadKeyChain.join("\n");
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, rsaKeyChain,
+ ONECRL_NAME),
+ "A signature should not verify if the signing key is wrong (RSA)");
+
+ // Check a good signature from cert with good SAN but with chain missing root
+ let missingRoot = [oneCRLChain[0], oneCRLChain[1]].join("\n");
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, missingRoot,
+ ONECRL_NAME),
+ "A signature should not verify if the chain is incomplete (missing root)");
+
+ // Check a good signature from cert with good SAN but with no path to root
+ let missingInt = [oneCRLChain[0], oneCRLChain[2]].join("\n");
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, missingInt,
+ ONECRL_NAME),
+ "A signature should not verify if the chain is incomplete (missing int)");
+
+ // Check good signatures from good certificates with the wrong SANs
+ chain1 = oneCRLChain.join("\n");
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
+ ABOUT_NEWTAB_NAME),
+ "A OneCRL signature should not verify if we require the newtab SAN");
+
+ chain2 = remoteNewTabChain.join("\n");
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
+ ONECRL_NAME),
+ "A newtab signature should not verify if we require the OneCRL SAN");
+
+ // Check good signatures with good chains with some other invalid names
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ""),
+ "A signature should not verify if the SANs do not match an empty name");
+
+ let relatedName = "subdomain." + ONECRL_NAME;
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
+ relatedName),
+ "A signature should not verify if the SANs do not match a related name");
+
+ let randomName = "\xb1\x9bU\x1c\xae\xaa3\x19H\xdb\xed\xa1\xa1\xe0\x81\xfb" +
+ "\xb2\x8f\x1cP\xe5\x8b\x9c\xc2s\xd3\x1f\x8e\xbbN";
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, randomName),
+ "A signature should not verify if the SANs do not match a random name");
+
+ // check good signatures with chains that have strange or missing SANs
+ chain1 = noSANChain.join("\n");
+ verifier = getSignatureVerifier();
+ ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
+ ONECRL_NAME),
+ "A signature should not verify if the SANs do not match a supplied name");
+
+ // Check malformed signature data
+ chain1 = oneCRLChain.join("\n");
+ let bad_signatures = [
+ // wrong length
+ "p384ecdsa=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2rUWM4GJke4pE8ecHiXoi-" +
+ "7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L==",
+ // incorrectly encoded
+ "p384ecdsa='WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2rUWM4GJke4pE8ecHiXoi" +
+ "-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L=",
+ // missing directive
+ "other_directive=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2rUWM4GJke4pE8ec" +
+ "HiXoi-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L",
+ // actually sha256 with RSA
+ "p384ecdsa=XS_jiQsS5qlzQyUKaA1nAnQn_OvxhvDfKybflB8Xe5gNH1wNmPGK1qN-jpeTfK" +
+ "6ob3l3gCTXrsMnOXMeht0kPP3wLfVgXbuuO135pQnsv0c-ltRMWLe56Cm4S4Z6E7WWKLPWaj" +
+ "jhAcG5dZxjffP9g7tuPP4lTUJztyc4d1z_zQZakEG7R0vN7P5_CaX9MiMzP4R7nC3H4Ba6yi" +
+ "yjlGvsZwJ_C5zDQzWWs95czUbMzbDScEZ_7AWnidw91jZn-fUK3xLb6m-Zb_b4GAqZ-vnXIf" +
+ "LpLB1Nzal42BQZn7i4rhAldYdcVvy7rOMlsTUb5Zz6vpVW9LCT9lMJ7Sq1xbU-0g=="
+ ];
+ for (let badSig of bad_signatures) {
+ throws(() => {
+ verifier = getSignatureVerifier();
+ verifier.verifyContentSignature(DATA, badSig, chain1, ONECRL_NAME);
+ }, /NS_ERROR/, `Bad or malformed signature "${badSig}" should be rejected`);
+ }
+
+ // Check malformed and missing certificate chain data
+ let chainSuffix = [oneCRLChain[1], oneCRLChain[2]].join("\n");
+ let badChains = [
+ // no data
+ "",
+ // completely wrong data
+ "blah blah \n blah",
+ ];
+
+ let badSections = [
+ // data that looks like PEM but isn't
+ "-----BEGIN CERTIFICATE-----\nBSsPRlYp5+gaFMRIczwUzaioRfteCjr94xyz0g==\n",
+ "-----BEGIN CERTIFICATE-----\nBSsPRlYp5+gaFMRIczwUzaioRfteCjr94xyz0g==\n-----END CERTIFICATE-----",
+ // data that will start to parse but won't base64decode
+ "-----BEGIN CERTIFICATE-----\nnon-base64-stuff\n-----END CERTIFICATE-----",
+ // data with garbage outside of PEM sections
+ "this data is garbage\n-----BEGIN CERTIFICATE-----\nnon-base64-stuff\n" +
+ "-----END CERTIFICATE-----",
+ ];
+
+ for (let badSection of badSections) {
+ // ensure we test each bad section on its own...
+ badChains.push(badSection);
+ // ... and as part of a chain with good certificates
+ badChains.push(badSection + '\n' + chainSuffix);
+ }
+
+ for (let badChain of badChains) {
+ throws(() => {
+ verifier = getSignatureVerifier();
+ verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, badChain,
+ ONECRL_NAME);
+ }, /NS_ERROR/, `Bad chain data starting "${badChain.substring(0, 80)}" ` +
+ "should be rejected");
+ }
+
+ // Check the streaming interface works OK when a good chain / data
+ // combination is provided
+ chain1 = oneCRLChain.join("\n");
+ verifier = getSignatureVerifier();
+ verifier.createContext("", GOOD_SIGNATURE, chain1, ONECRL_NAME);
+ verifier.update(DATA);
+ ok(verifier.end(),
+ "A good signature should verify using the stream interface");
+
+ // Check that the streaming interface works with multiple update calls
+ verifier = getSignatureVerifier();
+ verifier.createContext("", GOOD_SIGNATURE, chain1, ONECRL_NAME);
+ for (let c of DATA) {
+ verifier.update(c);
+ }
+ ok(verifier.end(),
+ "A good signature should verify using multiple updates");
+
+ // Check that the streaming interface works with multiple update calls and
+ // some data provided in CreateContext
+ verifier = getSignatureVerifier();
+ let start = DATA.substring(0, 5);
+ let rest = DATA.substring(start.length);
+ verifier.createContext(start, GOOD_SIGNATURE, chain1, ONECRL_NAME);
+ for (let c of rest) {
+ verifier.update(c);
+ }
+ ok(verifier.end(),
+ "A good signature should verify using data in CreateContext and updates");
+
+ // Check that a bad chain / data combination fails
+ verifier = getSignatureVerifier();
+ verifier.createContext("", GOOD_SIGNATURE, chain1, ONECRL_NAME);
+ ok(!verifier.end(),
+ "A bad signature should fail using the stream interface");
+
+ // Check that re-creating a context throws ...
+ verifier = getSignatureVerifier();
+ verifier.createContext("", GOOD_SIGNATURE, chain1, ONECRL_NAME);
+
+ // ... firstly, creating a context explicitly
+ throws(() => {
+ verifier.createContext(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME);
+ }, /NS_ERROR/, "Ensure a verifier cannot be re-used with createContext");
+
+ // ... secondly, by calling verifyContentSignature
+ throws(() => {
+ verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME);
+ }, /NS_ERROR/, "Ensure a verifier cannot be re-used with verifyContentSignature");
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_int.pem b/security/manager/ssl/tests/unit/test_content_signing/content_signing_int.pem
new file mode 100644
index 000000000..f58505cd3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_int.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0TCCAbugAwIBAgIUPcKbBQpKwTzrrlqzM+d3z5DWiNUwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBExDzANBgNVBAMMBmludC1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMlMCMwDAYDVR0TBAUwAwEB/zAT
+BgNVHSUEDDAKBggrBgEFBQcDAzALBgkqhkiG9w0BAQsDggEBADDPjITgz8joxLRW
+wpLxELKSgO/KQ6iAXztjMHq9ovT7Fy0fqBnQ1mMVFr+sBXLgtUCM45aip6PjhUXc
+zs5Dq5STg+kz7qtmAjEQvOPcyictbgdu/K7+uMhXQhlzhOgyW88Uk5vrAezNTc/e
+TvSmWp1FcgVAfaeMN/90nzD1KIHoUt7zqZIz9ub8jXPVzQNZq4vh33smZhmbdTdV
+DaHUyef5cR1VTEGB+L1qzUIQqpHmD4UkMNP1nYedWfauiQhRt6Ql3rJSCRuEvsOA
+iBTJlwai/EFwfyfHkOV2GNgv+A5wHHEjBtF5c4PCxQEL5Vw+mfZHLsDVqF3279ZY
+lQ6jQ9g=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_int.pem.certspec b/security/manager/ssl/tests/unit/test_content_signing/content_signing_int.pem.certspec
new file mode 100644
index 000000000..4134a73c6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_int.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-CA
+extension:basicConstraints:cA,
+extension:extKeyUsage:codeSigning
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_RSA_ee.pem b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_RSA_ee.pem
new file mode 100644
index 000000000..fbd0d7980
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_RSA_ee.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8DCCAdqgAwIBAgIUeWWcI0wMEtNxrf9r/WvrV4Y5DFQwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HH
+Jajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOr
+IMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQ
+sVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLA
+dTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQE
+LL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjPTA7MBMGA1UdJQQM
+MAoGCCsGAQUFBwMDMCQGA1UdEQQdMBuCGW9uZUNSTC1zaWduZXIubW96aWxsYS5v
+cmcwCwYJKoZIhvcNAQELA4IBAQBTTQDoiUsS4p1kfxxqOaL1vUTZyVEDKqiKq1W0
+2smYooB7KrL4yG5zKCwVKXpRlOHG/933jrEWo0SRacY09Qdj/VL1VdPpF6HbQHNc
++znwW4bGZFqtQozlHCYn6+1+3vOI4Y82RfczvqgaJK9rJ4PLuvdZbjAddW79KKdP
+0JEsrMzroPGjgAr/iudYAR4lnqYUxpe878O8ncWtKD3jontIxiC58nzgYZBSMCVw
+R/T9WwO2XFGGZ3y0DvO02svVfOAF7P8smV/cD7ACgwI0udG9JDwrd3fyMIh92lbU
+bIVcCdPNWlFZKJNP8WULSbde4p6WKX1tqnXSDdSZ3b0et4T6
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_RSA_ee.pem.certspec b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_RSA_ee.pem.certspec
new file mode 100644
index 000000000..b69737823
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_RSA_ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-CA
+subject:ee-int-CA
+extension:extKeyUsage:codeSigning
+extension:subjectAlternativeName:oneCRL-signer.mozilla.org
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_ee.pem b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_ee.pem
new file mode 100644
index 000000000..999885dcf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_ee.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICQjCCASygAwIBAgIUeWWcI0wMEtNxrf9r/WvrV4Y5DFQwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtgjiUt5LcTLajOmOgxU05q
+nAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalxA74oiM/wAvBa9xof3cyD
+dKpuqc6jPTA7MBMGA1UdJQQMMAoGCCsGAQUFBwMDMCQGA1UdEQQdMBuCGW9uZUNS
+TC1zaWduZXIubW96aWxsYS5vcmcwCwYJKoZIhvcNAQELA4IBAQAdPgCR5gCHDNv/
+RXgLEcsGDS/kvBpVilsz6+DQpg/9tfDoMb4QOM/BDXqrm3ndt6mBs61cImvd3R29
+47Kej5a/BlFHqdM4Il2iqmjb7CfICAtnQ46dxGamQwr4fR8iD7Etlc71bcygsSL9
+u4CvD1pUTm2xyDfLMAy9phkI6RouvSnt5hk8MI7q1x6RCfJDflU1EdGdeJyOajeD
+fYAW6kanTkcjnOkpBCQrfK2xY27OVgWqw/yoBUHrtxDHIV5cE9+SckF5gTP9JbNq
+MjATfQx6XeLC8TbtuhK4Vo5RLfbKzP74748ko9qwKRK3F5hGOqFBaCxyTX7jVblS
+Td7ydc86
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_ee.pem.certspec b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_ee.pem.certspec
new file mode 100644
index 000000000..2034a7299
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int-CA
+subject:ee-int-CA
+subjectKey:secp384r1
+extension:extKeyUsage:codeSigning
+extension:subjectAlternativeName:oneCRL-signer.mozilla.org
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_no_SAN_ee.pem b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_no_SAN_ee.pem
new file mode 100644
index 000000000..725374c14
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_no_SAN_ee.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICHDCCAQagAwIBAgIUNVa2/jSdRUf8hvS8AEu+NWYfnwkwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtgjiUt5LcTLajOmOgxU05q
+nAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalxA74oiM/wAvBa9xof3cyD
+dKpuqc6jFzAVMBMGA1UdJQQMMAoGCCsGAQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEA
+h0470fGH1d3Gmeu1LCTH44p7FRvTx/+MR7X8Ava3wzl593jpLlBd0vJY6JWL7z4u
+kfnSAvTh2S96Dx3jPv0dZLUTHSyTQAWsWmnD2lyjQ/SIoFIE+NewJLdoEqcWflbh
+Q49IIIsTC3OfUIYa1dxhhOpYNtj2esWM7JePnVIxk3+G8QYUfnFIEutZvXaBjAib
+6dk4NZncXZjMTMOm9VvgbCP7gGie8k+30Q0Y7mRAQQxbU9HIWv/9tUzLw7qR5ZyV
+1eIP8w00ReO8Jmk7Tfq9xRmIMBlDymM8IBh1Khi/0vvrhgCHEXTjrVsjFQZ2JYvB
+Qn8GjIS109A7WVE8xhUbMQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_no_SAN_ee.pem.certspec b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_no_SAN_ee.pem.certspec
new file mode 100644
index 000000000..fc0874be0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_no_SAN_ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-CA
+subject:ee-int-CA
+subjectKey:secp384r1
+extension:extKeyUsage:codeSigning
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_wrong_key_ee.pem b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_wrong_key_ee.pem
new file mode 100644
index 000000000..91f5e2dea
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_wrong_key_ee.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICJTCCAQ+gAwIBAgIUeWWcI0wMEtNxrf9r/WvrV4Y5DFQwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwWTATBgcqhkjOPQIBBggqhkjO
+PQMBBwNCAARPv7u7YeD4+bGmClmshwTi7AULQj489y6SPyxPeUtFXCpp0jNFbDbE
+EZ0HBuAO7cjRk5DXmRt7LQejBOqgSqbAoz0wOzATBgNVHSUEDDAKBggrBgEFBQcD
+AzAkBgNVHREEHTAbghlvbmVDUkwtc2lnbmVyLm1vemlsbGEub3JnMAsGCSqGSIb3
+DQEBCwOCAQEAZdHYo1BBgUO2sRvPIC3AQz+7MIdEFHoOZapM7eDK+G/4mnIEj5z5
+XW/n5hLop160K4hr+kUcW63XxisuuOBBvclnE9dgg0Sb0rFvJCVz7t1D4QHwWdou
+Sd0wXXTT+zeh40KPt2LSS6rT37o8TI1VTE7XkjfXGufKDQHk08sKEDgyab6Hy8gz
+eVcm2sMv+hwaMvFTjUws4o7zvcTqEvTa+4KxyySYDXB29jcKu60Sdjcm4hlNgJjU
+tQZTTV+k+yjg8oQKuNM0YWiKisJO/HtkHLTUyHwjiY+OV2krzoPCHvmUeSOhf2Gk
+bdOy6AgcCgqmjOFiCmWMJMKb7EvXfvVMXQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_wrong_key_ee.pem.certspec b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_wrong_key_ee.pem.certspec
new file mode 100644
index 000000000..f5cb96226
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_onecrl_wrong_key_ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int-CA
+subject:ee-int-CA
+subjectKey:secp256r1
+extension:extKeyUsage:codeSigning
+extension:subjectAlternativeName:oneCRL-signer.mozilla.org
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_remote_newtab_ee.pem b/security/manager/ssl/tests/unit/test_content_signing/content_signing_remote_newtab_ee.pem
new file mode 100644
index 000000000..7bac9e8c7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_remote_newtab_ee.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICUzCCAT2gAwIBAgIUJ1BtYqWRwUsVaZCGPp9eTHIC04QwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtgjiUt5LcTLajOmOgxU05q
+nAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalxA74oiM/wAvBa9xof3cyD
+dKpuqc6jTjBMMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDUGA1UdEQQuMCyCKnJlbW90
+ZW5ld3RhYi5jb250ZW50LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzALBgkqhkiG9w0B
+AQsDggEBALiLck6k50ok9ahVq45P3feY1PeUXcIYZkJd8aPDYM+0kfg5+JyJBykA
+mtHWPE1QQjs7VRMfaLfu04E4UJMI2V1AON1qtgR9BQLctW85KFACg2omfiCKwJh0
+5Q8cxBFx9BpNMayqLJwHttB6oluxZFTB8CL/hfpbYpHz1bMEDCVSRP588YBrc8mV
+OLqzQK+k3ewwGvfD6SvXmTny37MxqwxdTPFJNnpqzKAsQIvz8Skic9BkA1NFk0Oq
+lsKKoiibbOCmwS9XY/laAkBaC3winuhciYAC0ImAopZ4PBCU0AOHGrNbhZXWYQxt
+uHBj34FqvIRCqgM06JCEwN0ULgix4kI=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_remote_newtab_ee.pem.certspec b/security/manager/ssl/tests/unit/test_content_signing/content_signing_remote_newtab_ee.pem.certspec
new file mode 100644
index 000000000..44fa64518
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_remote_newtab_ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int-CA
+subject:ee-int-CA
+subjectKey:secp384r1
+extension:extKeyUsage:codeSigning
+extension:subjectAlternativeName:remotenewtab.content-signature.mozilla.org
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_root.pem b/security/manager/ssl/tests/unit/test_content_signing/content_signing_root.pem
new file mode 100644
index 000000000..b1ac172b1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_root.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUKRLJoCmk0A6PHrNc8CxFn//4BYcwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoyUwIzAMBgNVHRMEBTADAQH/MBMGA1Ud
+JQQMMAoGCCsGAQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAABgMK6EyVIXTjD5qaxPO
+DWz6yREACmAQBcowKWvfhwgi27DPSXyFGDbzTPEo+7RrIcXJkVAhLouGT51fCwTZ
+zb6Sgf6ztX7VSppY9AT4utvlZKP1xQ5WhIYsMtdHCHLHIkRjeWyoBEfUx50UXNLK
+Snl+A02GKYWiX+TLLg2DPN2s7v/mm8NLMQNgUlL7KakB2FHFyPa8otPpL4llg7UJ
+iBTVQ0c3JoiVbwZaY1Z8QinfMXUrTK9egUC4BAcId1dE8glzA5RRlw1fTLWpGApt
+hUmbDnl9N2a9NhGX323ypNzIATexafipzWe7bc4u/+bFdrUqnKUoEka73pZBdHdA
+FQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_content_signing/content_signing_root.pem.certspec b/security/manager/ssl/tests/unit/test_content_signing/content_signing_root.pem.certspec
new file mode 100644
index 000000000..f5e387b0c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/content_signing_root.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:extKeyUsage:codeSigning
diff --git a/security/manager/ssl/tests/unit/test_content_signing/moz.build b/security/manager/ssl/tests/unit/test_content_signing/moz.build
new file mode 100644
index 000000000..83e797900
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/moz.build
@@ -0,0 +1,19 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'content_signing_int.pem',
+# 'content_signing_onecrl_RSA_ee.pem',
+# 'content_signing_onecrl_ee.pem',
+# 'content_signing_onecrl_no_SAN_ee.pem',
+# 'content_signing_onecrl_wrong_key_ee.pem',
+# 'content_signing_remote_newtab_ee.pem',
+# 'content_signing_root.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_content_signing/pysign.py b/security/manager/ssl/tests/unit/test_content_signing/pysign.py
new file mode 100644
index 000000000..c68c45b52
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/pysign.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+Create an ECDSA signature on the P-384 curve using the SHA-384 hash of data from
+stdin. The key used for the signature is the secp384r1Encoded key used in pykey
+and pycert.
+
+The certificates for the content signature tests make use of this program.
+You can use pysign.py like this:
+
+cat test.txt | python pysign.py > test.txt.signature
+"""
+
+import base64
+import binascii
+import ecc
+import pykey
+
+from sys import stdin
+
+data = stdin.read()
+
+key = ecc.Key.Key.decode(binascii.unhexlify(pykey.ECCKey.secp384r1Encoded))
+sig = key.sign("Content-Signature:\00" + data, 'sha384')
+print base64.b64encode(sig).replace('+', '-').replace('/', '_')
diff --git a/security/manager/ssl/tests/unit/test_content_signing/test.txt b/security/manager/ssl/tests/unit/test_content_signing/test.txt
new file mode 100644
index 000000000..2daac1cb0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/test.txt
@@ -0,0 +1 @@
+This is a test file to test content-signature verification with a PKI.
diff --git a/security/manager/ssl/tests/unit/test_content_signing/test.txt.signature b/security/manager/ssl/tests/unit/test_content_signing/test.txt.signature
new file mode 100644
index 000000000..e61398147
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_content_signing/test.txt.signature
@@ -0,0 +1 @@
+hSvmvvA7_QLedDsjRJGBevqLwjPILx1EtWSPP4A0fepaWWPuuZRB8VfDT2j07bKDacRsbmJjmvg_R4CpKmnoWF8-2w5lSszlFFDqYSvQVQxpKhu-HMM_qquu_l0KecQ2
diff --git a/security/manager/ssl/tests/unit/test_datasignatureverifier.js b/security/manager/ssl/tests/unit/test_datasignatureverifier.js
new file mode 100644
index 000000000..0479c4d3f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_datasignatureverifier.js
@@ -0,0 +1,193 @@
+"use strict";
+
+const keys = [
+// RSA key
+"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj" +
+"Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD" +
+"NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf" +
+"awB/zH4KaPiY3vnrzQIDAQAB",
+
+// RSA key
+"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHe69VsjNCwnGF9YGZLgnobp3D" +
+"c1KgWzpbT+f12vVKkV3YBpA9KMVMy6wpxlDjvLJjfp/0HvaH7aaz/7kgxZw70Y60" +
+"LaJtkAcl1ZVAxS2lQKRTAzZ0RhoTSI1xVqGTjiQakgVdUeghtnqqwp5o1inZv3Qh" +
+"nUOMNPyAV8zGt+ZQHQIDAQAB",
+
+// Invalid key data ("foobar" base 64 encoded)
+"Zm9vYmFy"
+];
+
+const data = [
+"Test data for data signature verifier",
+"The quick brown fox jumps over the lazy dog..."
+];
+
+const signatures = [
+// Key 0, Data 0, MD2 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBAgUAA4GBALe3hO76UCpI8b1/oJUCIPmC6AbnMAMlAqo7" +
+"pc3TaWmU9wISWmXSrwNmr/QQNjWDn4nzQn8/K/Ac+tszaXib6fVLKA1a6e+/E0qE" +
+"OIKFwUiDWCkGDgxM8aYiTgoSZub/5rokgse+ivuCRSVTv9mSxRzKwj+Cvp1EjKCT" +
+"iIl3nnTh",
+
+// Key 0, Data 0, MD5 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBBAUAA4GBAGGb2QkA8LcA+QZj1SoVFmMpVTd9P5Ac0Rjb" +
+"ldouMmngztMV/dxymVKCpknqelhsxTQ/zaqGZ4KKzcIffJa9jXi5XUD8XzDIKcFE" +
+"dQvti8oUNDPb6l1ybETI8LKh2ywyBCSZ/Q5BwUeS9nfx+4cAnu9YZf29SGljit+Y" +
+"XLPKZ+of",
+
+// Key 0, Data 0, SHA1 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBBQUAA4GBAHcl6tqR5yjTDUJ5NiLOdIB4I6/C/rS2WW5a" +
+"7MVhYYhBgaZyGaem4LLT/REloOOLwPNMcmSEpwexqMSATbl9AAoJPq/wO3l4cZpO" +
+"tDkLlafsiwnqK156YvHp50zUq5Os28d6Bq/Nl2qjH1yizwlIEo0o9qo8Cq6QK3j2" +
+"MdFCopgk",
+
+// Key 0, Data 0, SHA256 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBCwUAA4GBAAOtDvzWwbYK7zLUz0F3e3wmkL1YWXuD/GzQ" +
+"LgwOg6VWtn9v54M9nfv/+iX+m4udzIwHZU7utYM31vtwqRC36l0QKo2VMbiLySX+" +
+"uHnSK40Kk4SfBvMF1wuz6BQ8ia8uTjPPfC764dB1N7gQdgdRevLTrh2EU6+DLmSS" +
+"Sm1QJm9/",
+
+// Key 0, Data 0, SHA384 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBDAUAA4GBAMWB3DskcGuGXpi3TO2Pm0g915EIvm5aOeXQ" +
+"sbs0ZGOwPyzYN1kKOmEpGHMeRhcIIBcF80ZC5N6dsTxeMGkFGOqhvB/HNl7gXMqF" +
+"OA8mG9vAcwfMeJlY4H5WbYD8bUn72UbIuS+sURLvWVhuIFBYPHHU7KVUaGAWl0rp" +
+"hCa4Dk37",
+
+// Key 0, Data 0, SHA512 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBDQUAA4GBAFkm61zH8Y0J5PA4GtOvoZA6w/SzHg5jFP11" +
+"gmXki81VgKwLF7Gyj4wRBX7Q9c8cNrNeoGZb12NUUxlR+u6J6VxcosVPKrCz7Xfj" +
+"LPi6+A1dNV5eH2B6tZR6wIiEatAWNIXxQZEJbj9BWefRFq6NnKhR5A/MEPnrZyoR" +
+"Da3YsDV3",
+
+// Key 0, Data 1, MD2 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBAgUAA4GBAJjwosJK6jV9Bt6HhrFn7+48LRhamjWjzs7a" +
+"cf5D/GTuul6aQQvQJ4Lt26KTyh3VglaQJFToH0Ik/fR1lOJS3tCPr1RRH06cKZgK" +
+"haoUaGR8rmtn678wX067q7ACmKPeqmgj71pHm7O5YgN3z45iAazbUHP4erdbFUf9" +
+"4rOr3L2f",
+
+// Key 0, Data 1, MD5 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBBAUAA4GBAC0EAoHWTb4CC+gw7fs5zMaZw7PWoDH1rXMD" +
+"dKoMBDmAW1EXZTfUGUTv0ga3VzuPJKuHHZOFVyFDnt4qFrefzzWs17LiPpN+yVgo" +
+"6vBnpXLeIp7D9n94bz56gv9NZZmy02XQVKDaRc3E4JBC7Ze7RAHuKtWuZRTUKF86" +
+"VXakwW3a",
+
+// Key 0, Data 1, SHA1 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBBQUAA4GBABkClr0Ot3aXBKYIiARdwpX8etDQO/Eqjxe8" +
+"pJyaqwj/P+x8j9/CbtJKJJTxvYmV9AhdgLPgoWjcTkfvqKdb1vpKKbV30QC/TEnu" +
+"ON+66MJgkwrZw6NCDyBRgMTjf4FWR75Ot1DLuu3+7uCswKCJe8la0HMm/AcqUzu1" +
+"SKOPMseI",
+
+// Key 0, Data 1, SHA256 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBCwUAA4GBAE2cIr6Uzo7RISkGgCA5m4K8s9+0iHwzr2u/" +
+"3ICUrTPe4RY2g9RLd6qkwaHD101LW5TQw71fhePIxfWHEhWtTCLS5DnGiucxfGKW" +
+"47gOBJIYf0DG7o5N4lA99j2Zuj+V+yjAcLfq7Su5FwASbD30KqCue1/F03qdXUxj" +
+"ciJeGo2b",
+
+// Key 0, Data 1, SHA384 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBDAUAA4GBAK+JfKJNBjw2d2iXT/pe9xMXPkLSkf+gjG2i" +
+"F7B0kBvMGyOVxuvQ4TCx+NFhAUevQugDHgBMkmAieg8mApcWWFWQ+8rbdUFv/hD7" +
+"fHW+QukMgcfLMquh0GtDuoM8ZKFBBvwnPGLLUh+ZMy8fEOjjH+s6bQQSpf072SSJ" +
+"K+Uo8DG2",
+
+// Key 0, Data 1, SHA512 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBDQUAA4GBAEEvDpyBssG0qFfRamNwkwSjhqYRVFdIa6+E" +
+"xfxdRqW/nxN5HuzFA8aajgSMXX0YFWPXV7OuVjCCJfZWhq7kQpTy96AmI/04rVdr" +
+"9gc5mc2tdLl3Yk/Qd+Xq8WYcQIZ5Ewyo7sr8eKtVhtEM8OtPR54FO2s1pkZwJdVf" +
+"ymMzHBoE",
+
+// Key 1, Data 0, MD5 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBBAUAA4GBAAIzLho2i5jfJ5SPPV/u2gUuefzhjEAsUhlL" +
+"Nir4FKhNzB2DZNbME9DtgNvdmZd00IjydYlaJ0dnLiMigXIaRJsyncYazULZdY6i" +
+"i7oP6llbXbszSTbHGolr5kQ+6cZPBBATOkJ+wekDdlvh5cZ+B0Lux4LevUDlGWAy" +
+"uR7bqrc5",
+
+// Key 1, Data 0, SHA512 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBDQUAA4GBABsjF8K/SIaY3KTeIGpPEwl1+ZXLKBaHxlRT" +
+"b37PhorSfqW1KFjquCEASUUeFwCQ14uUIBaRQV2haRGA0dRpuWr4zrWZMcDKOsmX" +
+"r5XRvcti9/lNqoIID/Mq0tKtS6aVFZpoHIrwbXpV4hV+BRGhaPxV3RBzEIzM7bWJ" +
+"tN3JY9+1",
+
+// Key 1, Data 1, MD5 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBBAUAA4GBAIAxRPXDAT2LBcOo7yTNr5uIZbPW9rkSX0Ba" +
+"h4sq6YRcxlnohaE2VO0CLGXFNwaBihhkkp+2dA76EvbMo/+O9XTWwroqtWWwvmxs" +
+"tWK6HvwYKnGFKOOZMOjNjmXjk446UVvxYCbU+NPM1LZTewT1/UpPWWRowF/lwX7m" +
+"SnT8d2ds",
+
+// Key 1, Data 1, SHA512 hash algorithm
+"MIGTMA0GCSqGSIb3DQEBDQUAA4GBAF0+XYD/r0Annz1GJ24GTkAlWY/OixCSV6Ix" +
+"OMM7P2d/jgOP+ICKIpxqaSE0CbkLiegUiidIOWvFqDxQJWlAAukDUWISGFfJMFxX" +
+"3jzJ0bBfeNY/1Qo8jMQopcNco/NlNgoSKAUOBtk31aFgNoVC3kWUk6pO97KEiJ+e" +
+"bQp9Z2/M",
+
+// Invalid signature data ("foobar" base 64 encoded)
+"Zm9vYmFy"
+];
+
+const tests = [
+// Data Signature Key Expected Throws
+// Pass cases
+ [0, 0, 0, true, false], //0
+ [0, 1, 0, true, false], //1
+ [0, 2, 0, true, false], //2
+ [0, 3, 0, true, false], //3
+ [0, 4, 0, true, false], //4
+ [0, 5, 0, true, false], //5
+ [1, 6, 0, true, false], //6
+ [1, 7, 0, true, false], //7
+ [1, 8, 0, true, false], //8
+ [1, 9, 0, true, false], //9
+ [1, 10, 0, true, false], //10
+ [1, 11, 0, true, false], //11
+ [0, 12, 1, true, false], //12
+ [0, 13, 1, true, false], //13
+ [1, 14, 1, true, false], //14
+ [1, 15, 1, true, false], //15
+// Incorrect data cases
+ [1, 0, 0, false, false], //16
+ [1, 1, 0, false, false], //17
+ [1, 2, 0, false, false], //18
+ [1, 3, 0, false, false], //19
+ [1, 4, 0, false, false], //20
+ [1, 5, 0, false, false], //21
+ [0, 6, 0, false, false], //22
+ [0, 7, 0, false, false], //23
+ [0, 8, 0, false, false], //24
+ [0, 9, 0, false, false], //25
+ [0, 10, 0, false, false], //26
+ [0, 11, 0, false, false], //27
+// Incorrect key cases
+ [0, 1, 1, false, false], //28
+ [0, 5, 1, false, false], //29
+ [1, 7, 1, false, false], //30
+ [1, 11, 1, false, false], //31
+ [0, 12, 0, false, false], //32
+ [0, 13, 0, false, false], //33
+ [1, 14, 0, false, false], //34
+ [1, 15, 0, false, false], //35
+// Invalid data cases
+ [0, 0, 2, false, true], //36
+ [0, 1, 2, false, true], //37
+ [0, 16, 0, false, true], //38
+ [1, 16, 0, false, true], //39
+];
+
+function run_test() {
+ let verifier = Cc["@mozilla.org/security/datasignatureverifier;1"]
+ .createInstance(Ci.nsIDataSignatureVerifier);
+
+ for (let testCase of tests) {
+ let testShouldThrow = testCase[4];
+ if (testShouldThrow) {
+ throws(() => {
+ verifier.verifyData(data[testCase[0]], signatures[testCase[1]],
+ keys[testCase[2]]);
+ }, /NS_ERROR_FAILURE/, `Test "${testCase}" should throw`);
+ } else {
+ let result = verifier.verifyData(data[testCase[0]],
+ signatures[testCase[1]],
+ keys[testCase[2]]);
+ equal(result, testCase[3],
+ `Actual and expected result should match for test "${testCase}"`);
+ }
+ }
+}
diff --git a/security/manager/ssl/tests/unit/test_der.js b/security/manager/ssl/tests/unit/test_der.js
new file mode 100644
index 000000000..674e939d9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_der.js
@@ -0,0 +1,219 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests DER.jsm functionality.
+
+var { DER } = Cu.import("resource://gre/modules/psm/DER.jsm", {});
+
+function run_simple_tests() {
+ throws(() => new DER.DER("this is not an array"), /invalid input/,
+ "should throw given non-array input");
+ throws(() => new DER.DER([0, "invalid input", 1]), /invalid input/,
+ "should throw given non-byte data (string case)");
+ throws(() => new DER.DER([31, 1, {}]), /invalid input/,
+ "should throw given non-byte data (object case)");
+ throws(() => new DER.DER([0.1, 3, 1]), /invalid input/,
+ "should throw given non-byte data (non-integer case)");
+ throws(() => new DER.DER([1, 3, -1]), /invalid input/,
+ "should throw given non-byte data (negative integer case)");
+ throws(() => new DER.DER([1, 300, 79]), /invalid input/,
+ "should throw given non-byte data (large integer case)");
+
+ let testReadByte = new DER.DER([0x0a, 0x0b]);
+ equal(testReadByte.readByte(), 0x0a, "should read 0x0a");
+ equal(testReadByte.readByte(), 0x0b, "should read 0x0b");
+ throws(() => testReadByte.readByte(), /data truncated/,
+ "reading more data than is available should fail");
+
+ let testReadBytes = new DER.DER([0x0c, 0x0d, 0x0e]);
+ deepEqual(testReadBytes.readBytes(3), [0x0c, 0x0d, 0x0e],
+ "should read correct sequence of bytes");
+
+ let testReadNegativeBytes = new DER.DER([0xff, 0xaf]);
+ throws(() => testReadNegativeBytes.readBytes(-4), /invalid length/,
+ "reading a negative number of bytes should fail");
+
+ let testReadZeroBytes = new DER.DER([]);
+ equal(testReadZeroBytes.readBytes(0).length, 0,
+ "reading zero bytes should result in a zero-length array");
+
+ let testReadTooManyBytes = new DER.DER([0xab, 0xcd, 0xef]);
+ throws(() => testReadTooManyBytes.readBytes(4), /data truncated/,
+ "reading too many bytes should fail");
+
+ let testSEQUENCE = new DER.DER([0x30, 0x01, 0x01]);
+ let content = testSEQUENCE.readTagAndGetContents(DER.SEQUENCE);
+ equal(content.length, 1, "content should have length 1");
+ equal(content[0], 1, "value of content should be [1]");
+ ok(testSEQUENCE.atEnd(), "testSEQUENCE should be at the end of its input");
+ testSEQUENCE.assertAtEnd();
+
+ // The length purports to be 4 bytes, but there are only 2 available.
+ let truncatedSEQUENCE = new DER.DER([0x30, 0x04, 0x00, 0x00]);
+ throws(() => truncatedSEQUENCE.readTagAndGetContents(DER.SEQUENCE),
+ /data truncated/, "should get 'data truncated' error");
+
+ // With 2 bytes of content, there is 1 remaining after reading the content.
+ let extraDataSEQUENCE = new DER.DER([0x30, 0x02, 0xab, 0xcd, 0xef]);
+ content = extraDataSEQUENCE.readTagAndGetContents(DER.SEQUENCE);
+ equal(content.length, 2, "content should have length 2");
+ deepEqual(content, [0xab, 0xcd], "value of content should be [0xab, 0xcd]");
+ ok(!extraDataSEQUENCE.atEnd(),
+ "extraDataSEQUENCE should not be at the end of its input");
+ throws(() => extraDataSEQUENCE.assertAtEnd(), /extra data/,
+ "should get 'extra data' error");
+
+ // The length of 0x81 0x01 is invalid because it could be encoded as just
+ // 0x01, which is shorter.
+ let invalidLengthSEQUENCE1 = new DER.DER([0x30, 0x81, 0x01, 0x00]);
+ throws(() => invalidLengthSEQUENCE1.readTagAndGetContents(DER.SEQUENCE),
+ /invalid length/, "should get 'invalid length' error");
+
+ // Similarly, 0x82 0x00 0x01 could be encoded as just 0x01, which is shorter.
+ let invalidLengthSEQUENCE2 = new DER.DER([0x30, 0x82, 0x00, 0x01, 0x00]);
+ throws(() => invalidLengthSEQUENCE2.readTagAndGetContents(DER.SEQUENCE),
+ /invalid length/, "should get 'invalid length' error");
+
+ // Lengths requiring 4 bytes to encode are not supported.
+ let unsupportedLengthSEQUENCE = new DER.DER([0x30, 0x83, 0x01, 0x01, 0x01]);
+ throws(() => unsupportedLengthSEQUENCE.readTagAndGetContents(DER.SEQUENCE),
+ /unsupported length/, "should get 'unsupported length' error");
+
+ // Indefinite lengths are not supported (and aren't DER anyway).
+ let unsupportedASN1SEQUENCE = new DER.DER([0x30, 0x80, 0x01, 0x00, 0x00]);
+ throws(() => unsupportedASN1SEQUENCE.readTagAndGetContents(DER.SEQUENCE),
+ /unsupported asn.1/, "should get 'unsupported asn.1' error");
+
+ let unexpectedTag = new DER.DER([0x31, 0x01, 0x00]);
+ throws(() => unexpectedTag.readTagAndGetContents(DER.SEQUENCE),
+ /unexpected tag/, "should get 'unexpected tag' error");
+
+ let readTLVTestcase = new DER.DER([0x02, 0x03, 0x45, 0x67, 0x89]);
+ let bytes = readTLVTestcase.readTLV();
+ deepEqual(bytes, [0x02, 0x03, 0x45, 0x67, 0x89],
+ "bytes read with readTLV should be equal to expected value");
+
+ let peekTagTestcase = new DER.DER([0x30, 0x01, 0x00]);
+ ok(peekTagTestcase.peekTag(DER.SEQUENCE),
+ "peekTag should return true for peeking with a SEQUENCE at a SEQUENCE");
+ ok(!peekTagTestcase.peekTag(DER.SET),
+ "peekTag should return false for peeking with a SET at a SEQUENCE");
+ peekTagTestcase.readTLV();
+ ok(!peekTagTestcase.peekTag(DER.SEQUENCE),
+ "peekTag should return false for peeking at a DER with no more data");
+
+ let tlvChoiceTestcase = new DER.DER([0x31, 0x02, 0xaa, 0xbb]);
+ let tlvChoiceContents = tlvChoiceTestcase.readTLVChoice([DER.NULL, DER.SET]);
+ deepEqual(tlvChoiceContents, [0x31, 0x02, 0xaa, 0xbb],
+ "readTLVChoice should return expected bytes");
+
+ let tlvChoiceNoMatchTestcase = new DER.DER([0x30, 0x01, 0xff]);
+ throws(() => tlvChoiceNoMatchTestcase.readTLVChoice([DER.NULL, DER.SET]),
+ /unexpected tag/,
+ "readTLVChoice should throw if no matching tag is found");
+}
+
+function run_bit_string_tests() {
+ let bitstringDER = new DER.DER([0x03, 0x04, 0x03, 0x01, 0x02, 0xf8]);
+ let bitstring = bitstringDER.readBIT_STRING();
+ equal(bitstring.unusedBits, 3, "BIT STRING should have 3 unused bits");
+ deepEqual(bitstring.contents, [0x01, 0x02, 0xf8],
+ "BIT STRING should have expected contents");
+
+ let bitstringTooManyUnusedBits = new DER.DER([0x03, 0x02, 0x08, 0x00]);
+ throws(() => bitstringTooManyUnusedBits.readBIT_STRING(),
+ /invalid BIT STRING encoding/,
+ "BIT STRING with too many unused bits should throw");
+
+ // A BIT STRING must have the unused bits byte, and so its length must be at
+ // least one.
+ let bitstringMissingUnusedBits = new DER.DER([0x03, 0x00]);
+ throws(() => bitstringMissingUnusedBits.readBIT_STRING(),
+ /invalid BIT STRING encoding/,
+ "BIT STRING with missing unused bits (and no contents) should throw");
+
+ // The minimal BIT STRING is 03 01 00 (zero bits of padding and zero bytes of
+ // content).
+ let minimalBitstringDER = new DER.DER([0x03, 0x01, 0x00]);
+ let minimalBitstring = minimalBitstringDER.readBIT_STRING();
+ equal(minimalBitstring.unusedBits, 0,
+ "minimal BIT STRING should have 0 unused bits");
+ equal(minimalBitstring.contents.length, 0,
+ "minimal BIT STRING should have empty contents");
+
+ // However, a BIT STRING with zero bytes of content can't have any padding,
+ // because that makes no sense.
+ let noContentsPaddedBitstringDER = new DER.DER([0x03, 0x01, 0x03]);
+ throws(() => noContentsPaddedBitstringDER.readBIT_STRING(),
+ /invalid BIT STRING encoding/,
+ "BIT STRING with no contents with non-zero padding should throw");
+}
+
+function run_compound_tests() {
+ let derBytes =
+ [ 0x30, 0x1a, // SEQUENCE
+ 0x02, 0x02, 0x77, 0xff, // INTEGER
+ 0x06, 0x03, 0x2b, 0x01, 0x01, // OBJECT IDENTIFIER
+ 0x30, 0x07, // SEQUENCE
+ 0x05, 0x00, // NULL
+ 0x02, 0x03, 0x45, 0x46, 0x47, // INTEGER
+ 0x30, 0x06, // SEQUENCE
+ 0x02, 0x02, 0x00, 0xff, // INTEGER
+ 0x05, 0x00 ]; // NULL
+ let der = new DER.DER(derBytes);
+ let contents = new DER.DER(der.readTagAndGetContents(DER.SEQUENCE));
+ let firstINTEGER = contents.readTagAndGetContents(DER.INTEGER);
+ deepEqual(firstINTEGER, [0x77, 0xff],
+ "first INTEGER should have expected value");
+ let oid = contents.readTagAndGetContents(DER.OBJECT_IDENTIFIER);
+ deepEqual(oid, [0x2b, 0x01, 0x01],
+ "OBJECT IDENTIFIER should have expected value");
+
+ let firstNested = new DER.DER(contents.readTagAndGetContents(DER.SEQUENCE));
+ let firstNestedNULL = firstNested.readTagAndGetContents(DER.NULL);
+ equal(firstNestedNULL.length, 0,
+ "first nested NULL should have expected value (empty array)");
+ let firstNestedINTEGER = firstNested.readTagAndGetContents(DER.INTEGER);
+ deepEqual(firstNestedINTEGER, [0x45, 0x46, 0x47],
+ "first nested INTEGER should have expected value");
+ firstNested.assertAtEnd();
+
+ let secondNested = new DER.DER(contents.readTagAndGetContents(DER.SEQUENCE));
+ let secondNestedINTEGER = secondNested.readTagAndGetContents(DER.INTEGER);
+ deepEqual(secondNestedINTEGER, [0x00, 0xff],
+ "second nested INTEGER should have expected value");
+ let secondNestedNULL = secondNested.readTagAndGetContents(DER.NULL);
+ equal(secondNestedNULL.length, 0,
+ "second nested NULL should have expected value (empty array)");
+ secondNested.assertAtEnd();
+
+ contents.assertAtEnd();
+ der.assertAtEnd();
+
+ let invalidDERBytes =
+ [ 0x30, 0x06, // SEQUENCE
+ 0x30, 0x02, // SEQUENCE
+ 0x02, 0x01, // INTEGER (missing data)
+ 0x05, 0x00, // NULL
+ 0x00, 0x00 ]; // (extra data)
+ let invalidDER = new DER.DER(invalidDERBytes);
+ let invalidContents = new DER.DER(
+ invalidDER.readTagAndGetContents(DER.SEQUENCE));
+ let invalidContentsContents = new DER.DER(
+ invalidContents.readTagAndGetContents(DER.SEQUENCE));
+ throws(() => invalidContentsContents.readTagAndGetContents(DER.INTEGER),
+ /data truncated/, "should throw due to missing data");
+ let nestedNULL = invalidContents.readTagAndGetContents(DER.NULL);
+ equal(nestedNULL.length, 0, "nested NULL should have expected value");
+ invalidContents.assertAtEnd();
+ throws(() => invalidDER.assertAtEnd(), /extra data/,
+ "should throw due to extra data");
+}
+
+function run_test() {
+ run_simple_tests();
+ run_bit_string_tests();
+ run_compound_tests();
+}
diff --git a/security/manager/ssl/tests/unit/test_enterprise_roots.js b/security/manager/ssl/tests/unit/test_enterprise_roots.js
new file mode 100644
index 000000000..de1b3a529
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_enterprise_roots.js
@@ -0,0 +1,58 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+// Tests enterprise root certificate support. When configured to do so, the
+// platform will attempt to find and import enterprise root certificates. This
+// feature is specific to Windows.
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+
+function check_no_enterprise_roots_imported(certDB, dbKey = undefined) {
+ let enterpriseRoots = certDB.getEnterpriseRoots();
+ equal(enterpriseRoots, null, "should not have imported any enterprise roots");
+ if (dbKey) {
+ let cert = certDB.findCertByDBKey(dbKey);
+ // If the garbage-collector hasn't run, there may be reachable copies of
+ // imported enterprise root certificates. If so, they shouldn't be trusted
+ // to issue TLS server auth certificates.
+ if (cert) {
+ ok(!certDB.isCertTrusted(cert, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL),
+ "previously-imported enterprise root shouldn't be trusted to issue " +
+ "TLS server auth certificates");
+ }
+ }
+}
+
+function check_some_enterprise_roots_imported(certDB) {
+ let enterpriseRoots = certDB.getEnterpriseRoots();
+ notEqual(enterpriseRoots, null, "should have imported some enterprise roots");
+ let enumerator = enterpriseRoots.getEnumerator();
+ let foundNonBuiltIn = false;
+ let savedDBKey = null;
+ while (enumerator.hasMoreElements()) {
+ let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
+ if (!cert.isBuiltInRoot && !savedDBKey) {
+ foundNonBuiltIn = true;
+ savedDBKey = cert.dbKey;
+ do_print("saving dbKey from " + cert.commonName);
+ }
+ }
+ ok(foundNonBuiltIn, "should have found non-built-in root");
+ return savedDBKey;
+}
+
+function run_test() {
+ let certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ Services.prefs.setBoolPref("security.enterprise_roots.enabled", false);
+ check_no_enterprise_roots_imported(certDB);
+ Services.prefs.setBoolPref("security.enterprise_roots.enabled", true);
+ let savedDBKey = check_some_enterprise_roots_imported(certDB);
+ Services.prefs.setBoolPref("security.enterprise_roots.enabled", false);
+ check_no_enterprise_roots_imported(certDB, savedDBKey);
+}
diff --git a/security/manager/ssl/tests/unit/test_ev_certs.js b/security/manager/ssl/tests/unit/test_ev_certs.js
new file mode 100644
index 000000000..d4aabd888
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs.js
@@ -0,0 +1,356 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+// Tests that end-entity certificates that should successfully verify as EV
+// (Extended Validation) do so and that end-entity certificates that should not
+// successfully verify as EV do not. Also tests related situations (e.g. that
+// failure to fetch an OCSP response results in no EV treatment).
+//
+// A quick note about the certificates in these tests: generally, an EV
+// certificate chain will have an end-entity with a specific policy OID followed
+// by an intermediate with the anyPolicy OID chaining to a root with no policy
+// OID (since it's a trust anchor, it can be omitted). In these tests, the
+// specific policy OID is 1.3.6.1.4.1.13769.666.666.666.1.500.9.1 and is
+// referred to as the test OID. In order to reflect what will commonly be
+// encountered, the end-entity of any given test path will have the test OID
+// unless otherwise specified in the name of the test path. Similarly, the
+// intermediate will have the anyPolicy OID, again unless otherwise specified.
+// For example, for the path where the end-entity does not have an OCSP URI
+// (referred to as "no-ocsp-ee-path-{ee,int}", the end-entity has the test OID
+// whereas the intermediate has the anyPolicy OID.
+// For another example, for the test OID path ("test-oid-path-{ee,int}"), both
+// the end-entity and the intermediate have the test OID.
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+do_register_cleanup(() => {
+ Services.prefs.clearUserPref("network.dns.localDomains");
+ Services.prefs.clearUserPref("security.OCSP.enabled");
+});
+
+Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
+Services.prefs.setIntPref("security.OCSP.enabled", 1);
+addCertFromFile(certdb, "test_ev_certs/evroot.pem", "CTu,,");
+addCertFromFile(certdb, "test_ev_certs/non-evroot-ca.pem", "CTu,,");
+
+const SERVER_PORT = 8888;
+
+function failingOCSPResponder() {
+ return getFailingHttpServer(SERVER_PORT, ["www.example.com"]);
+}
+
+class EVCertVerificationResult {
+ constructor(testcase, expectedPRErrorCode, expectedEV, resolve,
+ ocspResponder) {
+ this.testcase = testcase;
+ this.expectedPRErrorCode = expectedPRErrorCode;
+ this.expectedEV = expectedEV;
+ this.resolve = resolve;
+ this.ocspResponder = ocspResponder;
+ }
+
+ verifyCertFinished(prErrorCode, verifiedChain, hasEVPolicy) {
+ equal(prErrorCode, this.expectedPRErrorCode,
+ `${this.testcase} should have expected error code`);
+ equal(hasEVPolicy, this.expectedEV,
+ `${this.testcase} should result in expected EV status`);
+ this.ocspResponder.stop(this.resolve);
+ }
+}
+
+function asyncTestEV(cert, expectedPRErrorCode, expectedEV,
+ expectedOCSPRequestPaths, ocspResponseTypes = undefined)
+{
+ let now = Date.now() / 1000;
+ return new Promise((resolve, reject) => {
+ let ocspResponder = expectedOCSPRequestPaths.length > 0
+ ? startOCSPResponder(SERVER_PORT, "www.example.com",
+ "test_ev_certs",
+ expectedOCSPRequestPaths,
+ expectedOCSPRequestPaths.slice(),
+ null, ocspResponseTypes)
+ : failingOCSPResponder();
+ let result = new EVCertVerificationResult(cert.subjectName,
+ expectedPRErrorCode, expectedEV,
+ resolve, ocspResponder);
+ certdb.asyncVerifyCertAtTime(cert, certificateUsageSSLServer, 0,
+ "ev-test.example.com", now, result);
+ });
+}
+
+function ensureVerifiesAsEV(testcase) {
+ let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
+ addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
+ let expectedOCSPRequestPaths = gEVExpected
+ ? [ `${testcase}-int`, `${testcase}-ee` ]
+ : [ `${testcase}-ee` ];
+ return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected,
+ expectedOCSPRequestPaths);
+}
+
+function ensureVerifiesAsEVWithNoOCSPRequests(testcase) {
+ let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
+ addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
+ return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected, []);
+}
+
+function ensureVerifiesAsDV(testcase, expectedOCSPRequestPaths = undefined) {
+ let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
+ addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
+ return asyncTestEV(cert, PRErrorCodeSuccess, false,
+ expectedOCSPRequestPaths ? expectedOCSPRequestPaths
+ : [ `${testcase}-ee` ]);
+}
+
+function ensureVerificationFails(testcase, expectedPRErrorCode) {
+ let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
+ addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
+ return asyncTestEV(cert, expectedPRErrorCode, false, []);
+}
+
+function verifyWithFlags_LOCAL_ONLY_and_MUST_BE_EV(testcase, expectSuccess) {
+ let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
+ addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
+ let now = Date.now() / 1000;
+ let expectedErrorCode = SEC_ERROR_POLICY_VALIDATION_FAILED;
+ if (expectSuccess && gEVExpected) {
+ expectedErrorCode = PRErrorCodeSuccess;
+ }
+ return new Promise((resolve, reject) => {
+ let ocspResponder = failingOCSPResponder();
+ let result = new EVCertVerificationResult(
+ cert.subjectName, expectedErrorCode, expectSuccess && gEVExpected,
+ resolve, ocspResponder);
+ let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY |
+ Ci.nsIX509CertDB.FLAG_MUST_BE_EV;
+ certdb.asyncVerifyCertAtTime(cert, certificateUsageSSLServer, flags,
+ "ev-test.example.com", now, result);
+ });
+}
+
+function ensureNoOCSPMeansNoEV(testcase) {
+ return verifyWithFlags_LOCAL_ONLY_and_MUST_BE_EV(testcase, false);
+}
+
+function ensureVerifiesAsEVWithFLAG_LOCAL_ONLY(testcase) {
+ return verifyWithFlags_LOCAL_ONLY_and_MUST_BE_EV(testcase, true);
+}
+
+function ensureOneCRLSkipsOCSPForIntermediates(testcase) {
+ let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
+ addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
+ return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected,
+ [ `${testcase}-ee` ]);
+}
+
+function verifyWithDifferentOCSPResponseTypes(testcase, responses, expectEV) {
+ let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
+ addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
+ let expectedOCSPRequestPaths = gEVExpected
+ ? [ `${testcase}-int`, `${testcase}-ee` ]
+ : [ `${testcase}-ee` ];
+ let ocspResponseTypes = gEVExpected ? responses : responses.slice(1);
+ return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected && expectEV,
+ expectedOCSPRequestPaths, ocspResponseTypes);
+}
+
+function ensureVerifiesAsEVWithOldIntermediateOCSPResponse(testcase) {
+ return verifyWithDifferentOCSPResponseTypes(
+ testcase, [ "longvalidityalmostold", "good" ], true);
+}
+
+function ensureVerifiesAsDVWithOldEndEntityOCSPResponse(testcase) {
+ return verifyWithDifferentOCSPResponseTypes(
+ testcase, [ "good", "longvalidityalmostold" ], false);
+}
+
+function ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse(testcase) {
+ return verifyWithDifferentOCSPResponseTypes(
+ testcase, [ "good", "ancientstillvalid" ], false);
+}
+
+// These should all verify as EV.
+add_task(function* plainExpectSuccessEVTests() {
+ yield ensureVerifiesAsEV("anyPolicy-int-path");
+ yield ensureVerifiesAsEV("test-oid-path");
+ yield ensureVerifiesAsEV("cabforum-oid-path");
+ yield ensureVerifiesAsEV("cabforum-and-test-oid-ee-path");
+ yield ensureVerifiesAsEV("test-and-cabforum-oid-ee-path");
+ yield ensureVerifiesAsEV("reverse-order-oids-path");
+ // In this case, the end-entity has both the CA/B Forum OID and the test OID
+ // (in that order). The intermediate has the CA/B Forum OID. Since the
+ // implementation uses the first EV policy it encounters in the end-entity as
+ // the required one, this successfully verifies as EV.
+ yield ensureVerifiesAsEV("cabforum-and-test-oid-ee-cabforum-oid-int-path");
+});
+
+// These fail for various reasons to verify as EV, but fallback to DV should
+// succeed.
+add_task(function* expectDVFallbackTests() {
+ yield ensureVerifiesAsDV("anyPolicy-ee-path");
+ yield ensureVerifiesAsDV("non-ev-root-path");
+ yield ensureVerifiesAsDV("no-ocsp-ee-path",
+ gEVExpected ? [ "no-ocsp-ee-path-int" ] : []);
+ yield ensureVerifiesAsDV("no-ocsp-int-path");
+ // In this case, the end-entity has the test OID and the intermediate has the
+ // CA/B Forum OID. Since the CA/B Forum OID is not treated the same as the
+ // anyPolicy OID, this will not verify as EV.
+ yield ensureVerifiesAsDV("test-oid-ee-cabforum-oid-int-path");
+ // In this case, the end-entity has both the test OID and the CA/B Forum OID
+ // (in that order). The intermediate has only the CA/B Forum OID. Since the
+ // implementation uses the first EV policy it encounters in the end-entity as
+ // the required one, this fails to verify as EV.
+ yield ensureVerifiesAsDV("test-and-cabforum-oid-ee-cabforum-oid-int-path");
+});
+
+// Test that removing the trust bits from an EV root causes verifications
+// relying on that root to fail (and then test that adding back the trust bits
+// causes the verifications to succeed again).
+add_task(function* evRootTrustTests() {
+ clearOCSPCache();
+ let evroot = certdb.findCertByNickname("evroot");
+ do_print("untrusting evroot");
+ certdb.setCertTrust(evroot, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.UNTRUSTED);
+ yield ensureVerificationFails("test-oid-path", SEC_ERROR_UNKNOWN_ISSUER);
+ do_print("re-trusting evroot");
+ certdb.setCertTrust(evroot, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL);
+ yield ensureVerifiesAsEV("test-oid-path");
+});
+
+// Test that if FLAG_LOCAL_ONLY and FLAG_MUST_BE_EV are specified, that no OCSP
+// requests are made (this also means that nothing will verify as EV).
+add_task(function* localOnlyMustBeEVTests() {
+ clearOCSPCache();
+ yield ensureNoOCSPMeansNoEV("anyPolicy-ee-path");
+ yield ensureNoOCSPMeansNoEV("anyPolicy-int-path");
+ yield ensureNoOCSPMeansNoEV("non-ev-root-path");
+ yield ensureNoOCSPMeansNoEV("no-ocsp-ee-path");
+ yield ensureNoOCSPMeansNoEV("no-ocsp-int-path");
+ yield ensureNoOCSPMeansNoEV("test-oid-path");
+});
+
+
+// Under certain conditions, OneCRL allows us to skip OCSP requests for
+// intermediates.
+add_task(function* oneCRLTests() {
+ clearOCSPCache();
+
+ // enable OneCRL OCSP skipping - allow staleness of up to 30 hours
+ Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds",
+ 108000);
+ // set the blocklist-background-update-timer value to the recent past
+ Services.prefs.setIntPref("services.blocklist.onecrl.checked",
+ Math.floor(Date.now() / 1000) - 1);
+ Services.prefs.setIntPref(
+ "app.update.lastUpdateTime.blocklist-background-update-timer",
+ Math.floor(Date.now() / 1000) - 1);
+
+ yield ensureOneCRLSkipsOCSPForIntermediates("anyPolicy-int-path");
+ yield ensureOneCRLSkipsOCSPForIntermediates("no-ocsp-int-path");
+ yield ensureOneCRLSkipsOCSPForIntermediates("test-oid-path");
+
+ clearOCSPCache();
+ // disable OneCRL OCSP Skipping (no staleness allowed)
+ Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds", 0);
+ yield ensureVerifiesAsEV("anyPolicy-int-path");
+ // Because the intermediate in this case is missing an OCSP URI, it will not
+ // validate as EV, but it should fall back to DV.
+ yield ensureVerifiesAsDV("no-ocsp-int-path");
+ yield ensureVerifiesAsEV("test-oid-path");
+
+ clearOCSPCache();
+ // enable OneCRL OCSP skipping - allow staleness of up to 30 hours
+ Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds",
+ 108000);
+ // set the blocklist-background-update-timer value to the more distant past
+ Services.prefs.setIntPref("services.blocklist.onecrl.checked",
+ Math.floor(Date.now() / 1000) - 108080);
+ Services.prefs.setIntPref(
+ "app.update.lastUpdateTime.blocklist-background-update-timer",
+ Math.floor(Date.now() / 1000) - 108080);
+ yield ensureVerifiesAsEV("anyPolicy-int-path");
+ yield ensureVerifiesAsDV("no-ocsp-int-path");
+ yield ensureVerifiesAsEV("test-oid-path");
+
+ clearOCSPCache();
+ // test that setting "security.onecrl.via.amo" results in the correct
+ // OCSP behavior when services.blocklist.onecrl.checked is in the distant past
+ // and blacklist-background-update-timer is recent
+ Services.prefs.setBoolPref("security.onecrl.via.amo", false);
+ // enable OneCRL OCSP skipping - allow staleness of up to 30 hours
+ Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds",
+ 108000);
+ // set the blocklist-background-update-timer value to the recent past
+ // (services.blocklist.onecrl.checked defaults to 0)
+ Services.prefs.setIntPref(
+ "app.update.lastUpdateTime.blocklist-background-update-timer",
+ Math.floor(Date.now() / 1000) - 1);
+
+ yield ensureVerifiesAsEV("anyPolicy-int-path");
+ yield ensureVerifiesAsDV("no-ocsp-int-path");
+ yield ensureVerifiesAsEV("test-oid-path");
+
+ clearOCSPCache();
+ // test that setting "security.onecrl.via.amo" results in the correct
+ // OCSP behavior when services.blocklist.onecrl.checked is recent
+ Services.prefs.setBoolPref("security.onecrl.via.amo", false);
+ // enable OneCRL OCSP skipping - allow staleness of up to 30 hours
+ Services.prefs.setIntPref("security.onecrl.maximum_staleness_in_seconds",
+ 108000);
+ // now set services.blocklist.onecrl.checked to a recent value
+ Services.prefs.setIntPref("services.blocklist.onecrl.checked",
+ Math.floor(Date.now() / 1000) - 1);
+ yield ensureOneCRLSkipsOCSPForIntermediates("anyPolicy-int-path");
+ yield ensureOneCRLSkipsOCSPForIntermediates("no-ocsp-int-path");
+ yield ensureOneCRLSkipsOCSPForIntermediates("test-oid-path");
+
+ Services.prefs.clearUserPref("security.onecrl.via.amo");
+ Services.prefs.clearUserPref("security.onecrl.maximum_staleness_in_seconds");
+ Services.prefs.clearUserPref("services.blocklist.onecrl.checked");
+ Services.prefs.clearUserPref(
+ "app.update.lastUpdateTime.blocklist-background-update-timer");
+});
+
+// Prime the OCSP cache and then ensure that we can validate certificates as EV
+// without hitting the network. There's two cases here: one where we simply
+// validate like normal and then check that the network was never accessed and
+// another where we use flags to mandate that the network not be used.
+add_task(function* ocspCachingTests() {
+ clearOCSPCache();
+
+ yield ensureVerifiesAsEV("anyPolicy-int-path");
+ yield ensureVerifiesAsEV("test-oid-path");
+
+ yield ensureVerifiesAsEVWithNoOCSPRequests("anyPolicy-int-path");
+ yield ensureVerifiesAsEVWithNoOCSPRequests("test-oid-path");
+
+ yield ensureVerifiesAsEVWithFLAG_LOCAL_ONLY("anyPolicy-int-path");
+ yield ensureVerifiesAsEVWithFLAG_LOCAL_ONLY("test-oid-path");
+});
+
+// Old-but-still-valid OCSP responses are accepted for intermediates but not
+// end-entity certificates (because of OCSP soft-fail this results in DV
+// fallback).
+add_task(function* oldOCSPResponseTests() {
+ clearOCSPCache();
+
+ yield ensureVerifiesAsEVWithOldIntermediateOCSPResponse("anyPolicy-int-path");
+ yield ensureVerifiesAsEVWithOldIntermediateOCSPResponse("test-oid-path");
+
+ clearOCSPCache();
+ yield ensureVerifiesAsDVWithOldEndEntityOCSPResponse("anyPolicy-int-path");
+ yield ensureVerifiesAsDVWithOldEndEntityOCSPResponse("test-oid-path");
+
+ clearOCSPCache();
+ yield ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse(
+ "anyPolicy-int-path");
+ yield ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse("test-oid-path");
+});
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-ee.pem
new file mode 100644
index 000000000..16c8578ba
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-ee.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAj2gAwIBAgIUdTRdmHF1nt5GeEIkzoOGqryTsYEwCwYJKoZIhvcNAQEL
+MCAxHjAcBgNVBAMMFWFueVBvbGljeS1lZS1wYXRoLWludDAiGA8yMDE1MTEyODAw
+MDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAfMR0wGwYDVQQDDBRhbnlQb2xpY3ktZWUt
+cGF0aC1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbW
+Qf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pk
+cQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHT
+AjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3
+ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jh
+s3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHV
+A6zaGAo17Y0CAwEAAaOBhTCBgjBNBggrBgEFBQcBAQRBMD8wPQYIKwYBBQUHMAGG
+MWh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9hbnlQb2xpY3ktZWUtcGF0aC1l
+ZS8wEQYDVR0gBAowCDAGBgRVHSAAMB4GA1UdEQQXMBWCE2V2LXRlc3QuZXhhbXBs
+ZS5jb20wCwYJKoZIhvcNAQELA4IBAQCc4ivLkr+56RCJVvd+Rf/LccwmQAPVUSkF
+wE7UsIhzQAUbQSHZcNaNMTI1HmhpysH0FLbxDoIo26L7xQAuBDJ23Vqot15Iizg/
+anfFUFGf2ZWs6R37m1s9VaCUONX/+vpOrPQgqTIGRu7KCWiXw1EgbBsxuRmUDl8S
+gxYf1Bv5kTdKo7Bmns3kErlqQn4d42uCl/LEtXi7r3hUHN8VfcmFeN1JjHzVbTg0
+KaLmKVTmF8emaJZFcZrPL3ijrseoqfgpw620pq7Yl6QW68d49l/RvjKrf02UmTut
+0048te+z2fmKe/yrTDLiMIQ8gJMiocg2YU0TB7G4b2Y6dsp4A/Mh
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-ee.pem.certspec
new file mode 100644
index 000000000..a9175c32e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:anyPolicy-ee-path-int
+subject:anyPolicy-ee-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/anyPolicy-ee-path-ee/
+extension:certificatePolicies:any
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-int.pem
new file mode 100644
index 000000000..bcab0c65a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-int.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDQDCCAiqgAwIBAgIUD6vIeK5yuQLyDr+zHpbaW+0wD3EwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAgMR4wHAYDVQQDDBVhbnlQb2xpY3ktZWUtcGF0aC1pbnQwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erk
+NUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwC
+fs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1m
+CyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTM
+HGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m
+1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGj
+gYAwfjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjBOBggrBgEFBQcBAQRCMEAw
+PgYIKwYBBQUHMAGGMmh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9hbnlQb2xp
+Y3ktZWUtcGF0aC1pbnQvMBEGA1UdIAQKMAgwBgYEVR0gADALBgkqhkiG9w0BAQsD
+ggEBADc8HhaxO180zcQ2zVqrD7h42/c3KQKf5hcfqdVfcQjcca14TbXuPzVGFa9v
++Qrwf/YCPY95Gt/a4DIU3gX33dCceGTe7psvKN0hivLiRgubCnoGKR20Aig2TmMh
+OPoRHvPw1wIR74WEijENVPs8SnMVEoK31Xkj/XgX6v3MhTb5GPDHrgOcrHV1+jtq
+Ko4LJwLR0HlkUC+vH70uQf8f/Nz1lPqJiRlh9Vn2t4RQDag2ILDBdH+lo1vJjezH
+mizIIpbJQfOEakpWhIrBg1M/6WjfqPK6VBejWqAs75WMNNQ8NKiuPbhY+N6PKj/8
+S6XMJ95yBEzu06da061MBelmcQU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-int.pem.certspec
new file mode 100644
index 000000000..c49f6c4bc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-ee-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:anyPolicy-ee-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/anyPolicy-ee-path-int/
+extension:certificatePolicies:any
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-ee.pem
new file mode 100644
index 000000000..d68714416
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-ee.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDZDCCAk6gAwIBAgIUSyt03+W1sNq92wKRpi8je9wO0iAwCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmFueVBvbGljeS1pbnQtcGF0aC1pbnQwIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowIDEeMBwGA1UEAwwVYW55UG9saWN5LWlu
+dC1wYXRoLWVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABo4GUMIGRME4GCCsGAQUFBwEBBEIwQDA+BggrBgEFBQcw
+AYYyaHR0cDovL3d3dy5leGFtcGxlLmNvbTo4ODg4L2FueVBvbGljeS1pbnQtcGF0
+aC1lZS8wHwYDVR0gBBgwFjAUBhIrBgEEAetJhRqFGoUaAYN0CQEwHgYDVR0RBBcw
+FYITZXYtdGVzdC5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBADg1ogV4XMjH
+vcAxesEyvOWWvxsqNHh1aIovsVzYSTiIrHw8uLsP9ZQ8lyESXwIjGDIj2889k3pa
+KifGDAWhakTs8GLaHwwU8Qpu5EF/5QrLhniz9mIeo+jkP0icn81tUhb5k+s46+q3
+7zcJFbQxCFxRROLEZk+ZX/cVqZYXgZKtXELHei4Log0j8kaMAGoTR+/x+dbXTX+o
+wnNUXGDrY8KpSZdQZw1bvp0pHYDYPE5nt9t8eg94oE/3nGFkho4Jh8fJmxSbnUQY
+FBZQ2ySM/I8H9Cz0b1CX+aQK4uVLH0LtHKe2uF4xeYcfgp9KfcmztDLHNYhQXTnx
+WZxgHyA+BmU=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-ee.pem.certspec
new file mode 100644
index 000000000..1c643c2f9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:anyPolicy-int-path-int
+subject:anyPolicy-int-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/anyPolicy-int-path-ee/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-int.pem
new file mode 100644
index 000000000..b4a54cebc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-int.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDQjCCAiygAwIBAgIUTejPNCi+ZldwCAjvftiELTX+uBAwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAhMR8wHQYDVQQDDBZhbnlQb2xpY3ktaW50LXBhdGgtaW50MIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq
+5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SSc
+An7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39
+ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYk
+zBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3u
+JtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQAB
+o4GBMH8wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwTwYIKwYBBQUHAQEEQzBB
+MD8GCCsGAQUFBzABhjNodHRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgvYW55UG9s
+aWN5LWludC1wYXRoLWludC8wEQYDVR0gBAowCDAGBgRVHSAAMAsGCSqGSIb3DQEB
+CwOCAQEAZSGuT569hIFwu/Us43pVEaZr7G2ZLiU40GkBlSKb/bTaTx96TBLZlaNR
+twUhF1/A3GW5lThUGUsG0QliX9JCWpi2xkpOGT3de3l+lG9IMAWU+nsNKqJCkssd
+R31IsyUMQii9BRmecHAIQRtHC6qS4no1ihu3w5aouVFhvsL+A5Te8ZEzDpiwR+2k
++urptl3fbl9jY5SnzCkVJtO6DFYq4S/PmiYa/hxhWHq3m6vi7/NKrYI6/ujIlC1a
+Q+/1146/SNT72PBxwsE6pMNYP65U4KZpXnAPHqtUvz3qx25ARQPX9N36EPJcWXOJ
+mxqiK2IShzSnwPTtRLW0v33qWMT41A==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-int.pem.certspec
new file mode 100644
index 000000000..5f5adacc7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/anyPolicy-int-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:anyPolicy-int-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/anyPolicy-int-path-int/
+extension:certificatePolicies:any
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem
new file mode 100644
index 000000000..5bbfba9e0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqugAwIBAgIUP6b4yk51KguhcdxInOQFqDVQnyEwCwYJKoZIhvcNAQEL
+MD0xOzA5BgNVBAMMMmNhYmZvcnVtLWFuZC10ZXN0LW9pZC1lZS1jYWJmb3J1bS1v
+aWQtaW50LXBhdGgtaW50MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMDwxOjA4BgNVBAMMMWNhYmZvcnVtLWFuZC10ZXN0LW9pZC1lZS1jYWJmb3J1
+bS1vaWQtaW50LXBhdGgtZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24a
+hvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7t
+FYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+o
+N9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0d
+JdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4
+s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjgbkwgbYwagYIKwYBBQUHAQEEXjBcMFoG
+CCsGAQUFBzABhk5odHRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgvY2FiZm9ydW0t
+YW5kLXRlc3Qtb2lkLWVlLWNhYmZvcnVtLW9pZC1pbnQtcGF0aC1lZS8wKAYDVR0g
+BCEwHzAHBgVngQwBATAUBhIrBgEEAetJhRqFGoUaAYN0CQEwHgYDVR0RBBcwFYIT
+ZXYtdGVzdC5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBAAfSIEX8CSplrc33
+aoWe2NEuQMunJNSHhUk+M00k+4nTTCClTNC7YW8tcNdZ6aliPBVGVN23Sv0lrs08
+lCS04wk+/Dtm45bQ+dhklADIofvyMzhHXTYK6hqN1eXQ+0cMrvZc+A9t7xi/V/J5
+f4e2Vf15UEsjDjILrBxpNvUzJu9XBmpMA2tFwrG5p+PyUlK945umfjqLObd8pLU0
+NK/Wf3uT3Q/ZrsaTf9xFT/+723pweyHCqPK0SbV4CcAVgXnmQVhi25rgZPsNskM4
+rRQ3oKKCdlEX5U1usc4+1H9IPunVK4Q0tsW0Anvnn284ShRM+7k2WxhC9HyGc5K9
+Jcn8jeY=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem.certspec
new file mode 100644
index 000000000..c72237e45
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:cabforum-and-test-oid-ee-cabforum-oid-int-path-int
+subject:cabforum-and-test-oid-ee-cabforum-oid-int-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/cabforum-and-test-oid-ee-cabforum-oid-int-path-ee/
+extension:certificatePolicies:2.23.140.1.1,1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem
new file mode 100644
index 000000000..95c8be6cd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmagAwIBAgIUO7XOeVsNdvHXnjEwzmBWRhwYLVcwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjA9MTswOQYDVQQDDDJjYWJmb3J1bS1hbmQtdGVzdC1vaWQtZWUtY2Fi
+Zm9ydW0tb2lkLWludC1wYXRoLWludDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBnzCBnDAMBgNVHRMEBTADAQH/
+MAsGA1UdDwQEAwIBBjBrBggrBgEFBQcBAQRfMF0wWwYIKwYBBQUHMAGGT2h0dHA6
+Ly93d3cuZXhhbXBsZS5jb206ODg4OC9jYWJmb3J1bS1hbmQtdGVzdC1vaWQtZWUt
+Y2FiZm9ydW0tb2lkLWludC1wYXRoLWludC8wEgYDVR0gBAswCTAHBgVngQwBATAL
+BgkqhkiG9w0BAQsDggEBAKuq7oEHz2AZ1kD2Y6xx1twwhGa1Iii+l0SjOw3fr6w4
+264nVoCSK8unI0DBXFj4xv3ugKSiYqqV2EFaJUOXcVK8ofq03GSwVKEos5HVHYx9
+A/nVmvxNnIc7wdaHlrWOc0wdWHSUx3s9Gtt2L3XXZ7qhtvv4CGABVphP7cZDewZX
++06/A/js8sHcKCeQp+o6RlqsCRJpJO0t2i7sP0TDGAFKOj86mXG1Bii+1R9W8FzU
+IcQZYJV1ht4l32zndRVR2anhHxY+sqZBC4+Tn2Hph6FsnVvV7q5iedyV2NAkQ+xA
+DJFsUOokGNad1xn8gR3eFWvz/Zp3M1+UAO7jakZKiIA=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem.certspec
new file mode 100644
index 000000000..92ebdb37f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:cabforum-and-test-oid-ee-cabforum-oid-int-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/cabforum-and-test-oid-ee-cabforum-oid-int-path-int/
+extension:certificatePolicies:2.23.140.1.1
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-ee.pem
new file mode 100644
index 000000000..1ccb37723
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-ee.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnigAwIBAgIUDTSMnfcFGBwaZXHlyI/kKWHPyXkwCwYJKoZIhvcNAQEL
+MCwxKjAoBgNVBAMMIWNhYmZvcnVtLWFuZC10ZXN0LW9pZC1lZS1wYXRoLWludDAi
+GA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjArMSkwJwYDVQQDDCBj
+YWJmb3J1bS1hbmQtdGVzdC1vaWQtZWUtcGF0aC1lZTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBqDCBpTBZBggr
+BgEFBQcBAQRNMEswSQYIKwYBBQUHMAGGPWh0dHA6Ly93d3cuZXhhbXBsZS5jb206
+ODg4OC9jYWJmb3J1bS1hbmQtdGVzdC1vaWQtZWUtcGF0aC1lZS8wKAYDVR0gBCEw
+HzAHBgVngQwBATAUBhIrBgEEAetJhRqFGoUaAYN0CQEwHgYDVR0RBBcwFYITZXYt
+dGVzdC5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBABb8sKuyt3smMp0C8iMc
+aJm3zuS5Rjwv1h7Nd8E/eSOA14p/V62DWFNdF13Apxy6DsZOb2O5uyKYrZ/7A/8i
+ipCwhpC8Fv3fcfBW6nSkQfzxNSYQ9AwBAYs2JTEc2/MRX3U7o6qbxVpVyQu4QYA5
+QU8HlPsq87Ai6wC32M2+BdHlu5y0Qv5MnXYlahJbpABmEKwGZ4eSo1A5IKBZbClV
+y+VvmInHMv/P3bi27SBGhLMT/ohHWJ0gmjxWmbSgU+LkyPdsTm7kfFYM83C6o9S7
+MCNFNLMXwfIKLrDPpayWHPlQeYS3r0ywsSF6stm8lKUwPvp+YL/dVB2+SdKf+idt
+kus=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-ee.pem.certspec
new file mode 100644
index 000000000..36f80e017
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:cabforum-and-test-oid-ee-path-int
+subject:cabforum-and-test-oid-ee-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/cabforum-and-test-oid-ee-path-ee/
+extension:certificatePolicies:2.23.140.1.1,1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-int.pem
new file mode 100644
index 000000000..7f6ac062f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-int.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkOgAwIBAgIUY/r3cjSLbcqZBXaLaZ3P+1fOgVowCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAsMSowKAYDVQQDDCFjYWJmb3J1bS1hbmQtdGVzdC1vaWQtZWUtcGF0
+aC1pbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAGjgY0wgYowDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwWgYI
+KwYBBQUHAQEETjBMMEoGCCsGAQUFBzABhj5odHRwOi8vd3d3LmV4YW1wbGUuY29t
+Ojg4ODgvY2FiZm9ydW0tYW5kLXRlc3Qtb2lkLWVlLXBhdGgtaW50LzARBgNVHSAE
+CjAIMAYGBFUdIAAwCwYJKoZIhvcNAQELA4IBAQAW1rhYpmdW1ZyMbwBmUZmgUQt2
+Ux66oSK0sIV4r9A6jkh0CiWBSycfINVVXZIwpr+Nf3Ahgk+i9Y2GGrXhG73VPpt1
+G1onjO4lA+BIk/mn7KiewPMEiyyhxr0KAo1xlQlv38XbWtrhUERPiO1F0SCH0eR1
+X0Zz+jIxwl11moFyYtyclD8PLTMoXK2WlAfg0dBbY3VO0KFpb4m0XI9XM2Uj/7SI
+tENZ8G3udR/4D7rDtSxlFwNxoL4keB+CFLyDJeUt+3yzM3vlmpfk4kNQiNAiMwHI
+zxpqnKTG7myxPscGJV2V9PtUftet8b779e3k4xOxYGbSO2wmjjH1Y0cCbM/w
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-int.pem.certspec
new file mode 100644
index 000000000..79ae7ae80
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-and-test-oid-ee-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:cabforum-and-test-oid-ee-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/cabforum-and-test-oid-ee-path-int/
+extension:certificatePolicies:any
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-ee.pem
new file mode 100644
index 000000000..d0ccbac0a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-ee.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAj6gAwIBAgIUd4mge/NQNkIIbQbJ3HKDOf/OPIIwCwYJKoZIhvcNAQEL
+MCAxHjAcBgNVBAMMFWNhYmZvcnVtLW9pZC1wYXRoLWludDAiGA8yMDE1MTEyODAw
+MDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAfMR0wGwYDVQQDDBRjYWJmb3J1bS1vaWQt
+cGF0aC1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbW
+Qf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pk
+cQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHT
+AjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3
+ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jh
+s3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHV
+A6zaGAo17Y0CAwEAAaOBhjCBgzBNBggrBgEFBQcBAQRBMD8wPQYIKwYBBQUHMAGG
+MWh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9jYWJmb3J1bS1vaWQtcGF0aC1l
+ZS8wEgYDVR0gBAswCTAHBgVngQwBATAeBgNVHREEFzAVghNldi10ZXN0LmV4YW1w
+bGUuY29tMAsGCSqGSIb3DQEBCwOCAQEAUIxXzjuDVuDBhhzc3js1G/R4nfZwOfjB
+e3FXx8ayy5SzfYnH7hPadAUKQTFVwmMYg3rOKza0/FmOstv/k/EF7DYhti0jmLHs
+vXBzPp5Py0YYX56Dcu56khagh/SBBXvrb8/1ew4a39+4QRQ5c0q8dv6Jlyl2MS9f
+gfZ+LhNelFDV0TCnHV2kMMSBVxUuPzxEmZdUP3nSLar0uHfr86tf/B5v88PWFvbE
+APWxGSK8IZRqoEFRa+E4uFI77rBCi/xAMmz3j+a7Yn+Jwk/erLA8S1EqxaNJfbit
+Z33ZtK6A113HhL7H3HG7b60S/wOHHtZC6SwZKgKe31thRjw5yowokA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-ee.pem.certspec
new file mode 100644
index 000000000..86fd9aca3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:cabforum-oid-path-int
+subject:cabforum-oid-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/cabforum-oid-path-ee/
+extension:certificatePolicies:2.23.140.1.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-int.pem
new file mode 100644
index 000000000..e377615fa
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-int.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAiugAwIBAgIUXUOtQK+aJ2J+V0n3URZbsU6P6CEwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAgMR4wHAYDVQQDDBVjYWJmb3J1bS1vaWQtcGF0aC1pbnQwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erk
+NUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwC
+fs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1m
+CyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTM
+HGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m
+1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGj
+gYEwfzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjBOBggrBgEFBQcBAQRCMEAw
+PgYIKwYBBQUHMAGGMmh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9jYWJmb3J1
+bS1vaWQtcGF0aC1pbnQvMBIGA1UdIAQLMAkwBwYFZ4EMAQEwCwYJKoZIhvcNAQEL
+A4IBAQBzhdaDee1NHVryrmDv4qRvpNX08ogylFYwBfmEZWSbBMTO0znLIzk34/AR
+UpHq1AaeirhGTB9jh6j1jzMAI284J9pgstl9Hy+SmmIzk3KLsD5A4vCepBKKgAJO
+1XP3ie4L0/Ra1b7aSF7GlhJH7niIGnfOGwvRYem/ckcbS0DsLhZvTgYKJ0oIkgJH
+SvEhhL/Npf4/77G1+CHykXTR2tIyQM/HwUm+kurcRw0bf548T77hQpgKNW5aieNE
+TJA1ISYEa7el3WBBOc73b68V7M5ph5DXegi7a5xbMpjn5efCBvE2UUS9KETBVuxc
+tkinQaqkzDlPr+5PFByURXyz45C/
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-int.pem.certspec
new file mode 100644
index 000000000..343307164
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/cabforum-oid-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:cabforum-oid-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/cabforum-oid-path-int/
+extension:certificatePolicies:2.23.140.1.1
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/evroot.key b/security/manager/ssl/tests/unit/test_ev_certs/evroot.key
new file mode 100644
index 000000000..a756a0705
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/evroot.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC1SYlcnQAQjRGh
++Z+HqePRpdtd+uzxiNpXv2QTaI8s5HIs/xCQOMF0Ask6Kkc9vShq7T/c02PPWikU
+dwG92BjXYVv5NWvV08gzaqqMCXE2igbDzURhuT5RQk4XRLsuqtRqqzjOGWghlh+H
+cUoWY2k/CXYc301roSXqzse+Jw04j3ifbN94rjFE7SjEXnkpOGOnoipImAo2pA5y
+1XnJuSXf+MeTNi/9aJenwXVMXpfJZ8Pq3RquiqLMzjSKAWm4Diii1wwalgxvM18t
+oJubZD9av7pJ6Kqpgelg4n2HSAvdVd2UF/oYUJ+7VUzPgaQ5fouoEoo0vfJ4ZcGJ
+5XNPsikFAgMBAAECggEBAJg9VPlNb0x26yPW+T14UjUwz3Ow0WJUxueBdo1F9VaB
+0dAvsr0qrGq8HDiYYJNcUqDY9BSCAQOUd4MUHYZL/zCANjilwBUlcK6dGPPYyhY+
++0dbDd3zLn4W7HVl5rteAlxBxcZuV6A87eVUIh+DBFNHosTEUcPc5Ha3h84MBXJE
+vp4E7xMRjbuz1eCmzIcCnq/Upp7ZsUdZsV452KmITlb1TS+asBPw0V8xipq2svc9
+HsPJ/idK6JQxoQZAvniZsAEcXlCToYNHCGid4QBjTaveYPvWqu+joz3zSh829gwE
+MDa3SNHJ7pjEAxoK/sYO/aCpkL5ST1YU6sT9s0pS+VECgYEA6twssz5f8co3a72V
+vWoXd9LPT6xHVF6S0RpiCbnV5N7UeDRYHBabPIhHQqCeoYdQXBylVBTY0ltJdjLV
+7CqqBSM0MPrUmJJ3en1o4Dj1YaO4lp5gsKJj3vv9pIqbD/OdlbyIsVJnyK3pe1EH
+lI5B5DMknYf32xCdXXRYTYa8wdcCgYEAxZrldqIWRwJI2USlW56b+TKZ2jQexW5V
+jrqCGrzhv1e3nPQR0pBMd0+duh8VGF9gewV0oIIF1uwotmo21jQjLqry/qN1Yauv
+nWRLaNs4yZZMuMluwKxh66ZNBbRGVC9COXb1rN5OzJVTbS31eJVPk/DP2cWPt4ui
+p23VrChNyIMCgYEAwdLvOQYzHFKspkgR+f5CW+somDIvs9tRAyzo1+n8MiQL6SAZ
+zySA/NXjKYNxJxGLKlmhv+BsiD46REfz8DHNmuvQuNNo/Hl0DSzOjq2zJN9/CR6v
+4VZDYdVJILAbBHEjDl5H2T+O0zljxRe8T8ePbYsfnrqFvM7bcDMCZQjbYoUCgYEA
+hSG421aU376ASjFfnvybZSdcVJCs8qNFbWXm5hC/n2R/xnUB1PV3LyMqxwzN75/C
+pt+kFcfEG2r8evnQfDygP37ZPAnwuZ8sMEQ0Mi8QcXCbvBuqTJFXX6apWeB9SZaV
+bZXiK1eTi25HyNUf/t/Jv4iM4NGj5CtlqJvtS5HT5fUCgYEA3El7BrkgyL4LAHe3
+mOl37vdEqQ7Cxdfmy7IkSPrHLagaMxgODYoC6DFGDH/H/TphL3uZMLYbeZ+OkI5j
+LpugQJtqpwsDo7p4dCYmO1vVhD34R27bXRT2qGE+uvW5zVykL1+9KALgjk5J5XCf
+UVFRDKpassHG6z7+kpXRbowlyRY=
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/evroot.key.keyspec b/security/manager/ssl/tests/unit/test_ev_certs/evroot.key.keyspec
new file mode 100644
index 000000000..1a3d76a55
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/evroot.key.keyspec
@@ -0,0 +1 @@
+ev
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/evroot.pem b/security/manager/ssl/tests/unit/test_ev_certs/evroot.pem
new file mode 100644
index 000000000..cd2fd7ed8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/evroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUW9j5PS8YoKgynZdYa9i2Kwexnp8wCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MDEwMTAwMDAwMFoYDzIwMzUwMTAx
+MDAwMDAwWjARMQ8wDQYDVQQDDAZldnJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC1SYlcnQAQjRGh+Z+HqePRpdtd+uzxiNpXv2QTaI8s5HIs/xCQ
+OMF0Ask6Kkc9vShq7T/c02PPWikUdwG92BjXYVv5NWvV08gzaqqMCXE2igbDzURh
+uT5RQk4XRLsuqtRqqzjOGWghlh+HcUoWY2k/CXYc301roSXqzse+Jw04j3ifbN94
+rjFE7SjEXnkpOGOnoipImAo2pA5y1XnJuSXf+MeTNi/9aJenwXVMXpfJZ8Pq3Rqu
+iqLMzjSKAWm4Diii1wwalgxvM18toJubZD9av7pJ6Kqpgelg4n2HSAvdVd2UF/oY
+UJ+7VUzPgaQ5fouoEoo0vfJ4ZcGJ5XNPsikFAgMBAAGjHTAbMAwGA1UdEwQFMAMB
+Af8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAO1EZ134zXCiYSMixYSVP
+gAXWdR8zvaeS8UF0Xihle6nBdtkcmhiMgxXecMv7P7xO/U/wz5NAyJ1cvqaxrPbn
+8bekVCCsAAae6mVJIsVeuLtg3f89Qmx6KF6By2NI5R/AX5gxs0V9Tvjp9NfpIWh9
+I0BO0/REmq+CxKWjO6Loq0JA/QRW1jnD3XLitJ9QiCfnLqgUAG8JnkhG/JtpcJC3
+91SluwhVw+8i7caDOgHZGvjBEycyje0iyDLybaVjv2PpyuQx8H6hDzTGd2bNDl22
+fZ0FsOYCH6TJPx7nsCJCQ8/jGsRAGPxbItwSpTQJegKVaJ9s2dOAreJdkQFSIEo+
+3g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/evroot.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/evroot.pem.certspec
new file mode 100644
index 000000000..3121f3486
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/evroot.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:evroot
+subjectKey:ev
+issuerKey:ev
+validity:20150101-20350101
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/moz.build b/security/manager/ssl/tests/unit/test_ev_certs/moz.build
new file mode 100644
index 000000000..286097c1c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/moz.build
@@ -0,0 +1,48 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'anyPolicy-ee-path-ee.pem',
+# 'anyPolicy-ee-path-int.pem',
+# 'anyPolicy-int-path-ee.pem',
+# 'anyPolicy-int-path-int.pem',
+# 'cabforum-and-test-oid-ee-cabforum-oid-int-path-ee.pem',
+# 'cabforum-and-test-oid-ee-cabforum-oid-int-path-int.pem',
+# 'cabforum-and-test-oid-ee-path-ee.pem',
+# 'cabforum-and-test-oid-ee-path-int.pem',
+# 'cabforum-oid-path-ee.pem',
+# 'cabforum-oid-path-int.pem',
+# 'evroot.pem',
+# 'no-ocsp-ee-path-ee.pem',
+# 'no-ocsp-ee-path-int.pem',
+# 'no-ocsp-int-path-ee.pem',
+# 'no-ocsp-int-path-int.pem',
+# 'non-ev-root-path-ee.pem',
+# 'non-ev-root-path-int.pem',
+# 'non-evroot-ca.pem',
+# 'reverse-order-oids-path-ee.pem',
+# 'reverse-order-oids-path-int.pem',
+# 'test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem',
+# 'test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem',
+# 'test-and-cabforum-oid-ee-path-ee.pem',
+# 'test-and-cabforum-oid-ee-path-int.pem',
+# 'test-oid-ee-cabforum-oid-int-path-ee.pem',
+# 'test-oid-ee-cabforum-oid-int-path-int.pem',
+# 'test-oid-path-ee.pem',
+# 'test-oid-path-int.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
+#
+#test_keys = (
+# 'evroot.key',
+# 'test-oid-path-int.key',
+#)
+#
+#for test_key in test_keys:
+# GeneratedTestKey(test_key)
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-ee.pem
new file mode 100644
index 000000000..bdb27bc87
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-ee.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfagAwIBAgIUX8e03l3JoXPCHh9CMl58PfYnzkowCwYJKoZIhvcNAQEL
+MB4xHDAaBgNVBAMME25vLW9jc3AtZWUtcGF0aC1pbnQwIhgPMjAxNTExMjgwMDAw
+MDBaGA8yMDE4MDIwNTAwMDAwMFowHTEbMBkGA1UEAwwSbm8tb2NzcC1lZS1wYXRo
+LWVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62
+iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHql
+WqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosq
+Qe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+
+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8i
+b2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoY
+CjXtjQIDAQABo0MwQTAfBgNVHSAEGDAWMBQGEisGAQQB60mFGoUahRoBg3QJATAe
+BgNVHREEFzAVghNldi10ZXN0LmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOCAQEA
+ciXsc2FRYi4E0cofGtumXR2SzIitXdAXUwSvXz6407BEYIFOv/DnDr+EmpDF7a/Y
+rd+7ewODY19FYjw4tcsWY3Yz1key68TFn+BuudyGwuTS2Uq3wQTkP0PMtBNQLQ0S
+qZRjH5wJkqn/WSeuYqv4f5bTu2fgfloiCAfKA3Pisrmg0iJ5O7k0QN3QhiCkgbab
+LzmssU/YpiS8KwbUPIC5cmt/Y2OLMI4R3GMdNKEm+ykJ79mNysGahtFP8klfcOk4
+F4GYQu1Rmb+sNXvMnFMh5TkforL4rqv/ItGcQx3mvtAhtpZAI65O+oURoXmaQdN1
+6DUFil8O/ybcKph4NE5P0w==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-ee.pem.certspec
new file mode 100644
index 000000000..ece1cf816
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:no-ocsp-ee-path-int
+subject:no-ocsp-ee-path-ee
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-int.pem
new file mode 100644
index 000000000..77f66fa60
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-int.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDOzCCAiWgAwIBAgIUX0+dCnv5fVmpIQhV708UOhoqNBcwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAeMRwwGgYDVQQDDBNuby1vY3NwLWVlLXBhdGgtaW50MIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVK
+tOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7N
+Q/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39Zgsr
+sCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxs
+l62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYl
+nauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABo34w
+fDAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjBMBggrBgEFBQcBAQRAMD4wPAYI
+KwYBBQUHMAGGMGh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9uby1vY3NwLWVl
+LXBhdGgtaW50LzARBgNVHSAECjAIMAYGBFUdIAAwCwYJKoZIhvcNAQELA4IBAQBW
+nipIWEgiTZ1MNbN/1+lrhxExtkFdF6nzD3ob1Gsc2oJ3tCa2Oq7uUT6AMJ7aGPz/
+XnFkl6hmzLP0EyVR9un/nL9gkynGFsHzl7OFndE4SriD9ynAdNA1lPE2+gRqYhN4
+O2RxZx+Q61jWmWvPxUi/ihX9EVxYNOwrlu4t1K0G5HhFKMaXnx8dQFLxYGW8y9BF
+4c/Met9ocpV+p2b5kaiqEigZWzg14/jjeVkrFggycZOrfjwKOU5ICYY0Ap87yFT0
+ilefvG6syp+1swrM2yKwQIRpfDDjNi0ZxoKkzQ8bENuC6u0okcQs/rttlfRFqkl7
+g+aKagJNH0XrpaNPTsM9
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-int.pem.certspec
new file mode 100644
index 000000000..5eb952a9a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-ee-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:no-ocsp-ee-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/no-ocsp-ee-path-int/
+extension:certificatePolicies:any
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-ee.pem
new file mode 100644
index 000000000..19b8e6bd1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-ee.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXjCCAkigAwIBAgIUU04Uw7andDfJBFPO0TwReJsY/VowCwYJKoZIhvcNAQEL
+MB8xHTAbBgNVBAMMFG5vLW9jc3AtaW50LXBhdGgtaW50MCIYDzIwMTUxMTI4MDAw
+MDAwWhgPMjAxODAyMDUwMDAwMDBaMB4xHDAaBgNVBAMME25vLW9jc3AtaW50LXBh
+dGgtZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAGjgZIwgY8wTAYIKwYBBQUHAQEEQDA+MDwGCCsGAQUFBzABhjBo
+dHRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgvbm8tb2NzcC1pbnQtcGF0aC1lZS8w
+HwYDVR0gBBgwFjAUBhIrBgEEAetJhRqFGoUaAYN0CQEwHgYDVR0RBBcwFYITZXYt
+dGVzdC5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBADN46jobibbTxmEdbvG6
+JS8+vofUrsLIWfEfagl9R+i5Ix33sJRHF+4yrFN1DT7Eg7LJV+cGJh4wyOf0sgJR
+LIjQxjIQadvCnEezhrZ7j0TUCZqV9iiO7O/ROo3qgwH8nCrl6qnKQA18FGyJttni
+DFGkR1PyvMc3CAPcDfdGODVRLWgQUXtFNOdRrG9IKI2BCAMLr3sItW7aJ9BiO6ow
+hqg3XdHUn4kzVbuGuiJsg60oSxNYawKd4oYg2yQctgSVHg/3ZFRDO02ntxUppoem
+uQtB+4qHaZgk7m8OFKMQlbq48rpkPHRLIBdIRJJc8WKj+XNsVrezzoU37XE2AFPp
+dhI=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-ee.pem.certspec
new file mode 100644
index 000000000..623057e9e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:no-ocsp-int-path-int
+subject:no-ocsp-int-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/no-ocsp-int-path-ee/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-int.pem
new file mode 100644
index 000000000..cd496900b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-int.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7jCCAdigAwIBAgIUfbT9i6G6QnOCLGdEg6DChw0RBrwwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAfMR0wGwYDVQQDDBRuby1vY3NwLWludC1wYXRoLWludDCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
+SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYL
+K7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwc
+bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
+JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMw
+MC4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwEQYDVR0gBAowCDAGBgRVHSAA
+MAsGCSqGSIb3DQEBCwOCAQEAb9WQQmnK6eJUDK/ez/oEKfGxVSw/J6KlPCwHbUtC
+JQ6smyBs8E4eq1buQxtRkRDMIsDifSsnCiVXQaMwNR7V+AbJiDl3bU+1lmUtWcP+
+2khUqafvD29OHFcP0EyJ5i4icPJd5/7Kx6rXuTn8avV8oe+Ugq4H0yL7lliL+jvZ
+efcLNaeNT5E4jFj2l0cOoWBDdZ2Y8r6cHYDjWxOq1xi8vg4iDNGZKYuyeGwxf9fl
+gNG9rUyFxs/kv6pQSiREc4OtqkI9tw3L5wf6UrfZ3553BgfSZX6XdVdWpcGZaetd
+rm21WF9oMb5F3PJsUgf/Ustee38VcYO1DVbnEIVumQ3qlQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-int.pem.certspec
new file mode 100644
index 000000000..548241de3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-int-path-int.pem.certspec
@@ -0,0 +1,6 @@
+issuer:evroot
+subject:no-ocsp-int-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:certificatePolicies:any
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-ee.pem
new file mode 100644
index 000000000..ffb8a6d3b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-ee.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXjCCAkigAwIBAgIUD597e4LEXa+njJfkqWZ9MlmV2PgwCwYJKoZIhvcNAQEL
+MB8xHTAbBgNVBAMMFG5vbi1ldi1yb290LXBhdGgtaW50MCIYDzIwMTUxMTI4MDAw
+MDAwWhgPMjAxODAyMDUwMDAwMDBaMB4xHDAaBgNVBAMME25vbi1ldi1yb290LXBh
+dGgtZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAGjgZIwgY8wTAYIKwYBBQUHAQEEQDA+MDwGCCsGAQUFBzABhjBo
+dHRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgvbm9uLWV2LXJvb3QtcGF0aC1lZS8w
+HwYDVR0gBBgwFjAUBhIrBgEEAetJhRqFGoUaAYN0CQEwHgYDVR0RBBcwFYITZXYt
+dGVzdC5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBAJ3Cc5jhMe0FBvQ1y0dT
+/Jj5VYqFfaYpEEHu3vWfOQ0miY07FjTZmbEmuNGs1pSKuGOpqQwpX97TxIPUH1l+
+31vZqHy4wWhZI7Vt38baPlY1I0+fVb+85+WeBQfgiTMUF2Or/cfj1NtHAzTNOmyb
+/H5/41oBydLVLRRh9NQmas3meEtnv1j/TYCuZM+UA31pJIr063kAB2U+vSuVWbSc
+gN0Xeq88d3IKW8M02+OQtPGqGwcYnyZgkKjr9ndjB4irRn5yoC/2ruhJEuGw1k84
+zfuArdbfYlNJaPzyWKpPQChA3I7CaYRFwCJ3+8nKTliDiTPuTba/zxisRLIv9ZX+
+FYA=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-ee.pem.certspec
new file mode 100644
index 000000000..9895732b1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:non-ev-root-path-int
+subject:non-ev-root-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/non-ev-root-path-ee/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-int.pem
new file mode 100644
index 000000000..2223a424c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-int.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDRDCCAi6gAwIBAgIUbeCcNZk/68aHlCaLR0Mgh09gK9MwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDW5vbi1ldnJvb3QtY2EwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowHzEdMBsGA1UEAwwUbm9uLWV2LXJvb3QtcGF0aC1pbnQw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAGjfzB9MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGME0GCCsGAQUFBwEB
+BEEwPzA9BggrBgEFBQcwAYYxaHR0cDovL3d3dy5leGFtcGxlLmNvbTo4ODg4L25v
+bi1ldi1yb290LXBhdGgtaW50LzARBgNVHSAECjAIMAYGBFUdIAAwCwYJKoZIhvcN
+AQELA4IBAQAo5g/5usQqBIfpaeOFV5X8om69PQdcyke2/hWuTBXciSCZ0VhpgloL
+p4EBdh72UZ+HNqiuQ7oKEOBYeA02k11TqZ6kokurabpZjcwrlbkqGSpf+afhK8DK
+lhJdXa9WLBZuY87YPXA0pnpAEQMiDchJAa/gG3Qg2yvtEYAYH+MJT3jIMbYlXeep
+aLNdcG6E0ByrFYAQCi0WIEvwv7krCEliRgp/a1k+s6V84lNkeBzqfflygOXBXPTY
+ws9sg6RxeYBFL3YNU63jonzWfcp9dMusL/Jwdak0r/iwQoSfQGm6X8spjHFKnXUm
+Fp/ccMKeWAZl8mQYisK0vQwlclxfPFeO
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-int.pem.certspec
new file mode 100644
index 000000000..5ce035ae1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root-path-int.pem.certspec
@@ -0,0 +1,6 @@
+issuer:non-evroot-ca
+subject:non-ev-root-path-int
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/non-ev-root-path-int/
+extension:certificatePolicies:any
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.pem b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.pem
new file mode 100644
index 000000000..b7560f2dc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAcWgAwIBAgIUGeBAgifObFMlBPIYGTQEPMZ7W9YwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDW5vbi1ldnJvb3QtY2EwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowGDEWMBQGA1UEAwwNbm9uLWV2cm9vdC1jYTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
+SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYL
+K7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwc
+bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
+JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMd
+MBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQCz
+X8XmbNmo5v9uMdsHOc7656UJPBX01AkXTAvR9Ny+rCIC70R520o2u43TLcLO3S5e
+KkTzqtQUovzMEmbH543Z/7rgQVsd99YrDd24wLpX439D/PJlsx6gBkBiiqJ+8GfG
+uGdHTW8ov7fvx20dWlZxdjQXrHdkP8wf0X2VfLC/4PI8fzpWY8LqpJ9GSoKYtBKE
+nxSxNr/SJTeEzSUwbNOh1KU4TuYh/GMsZKP5T+08OpTBuFHbcvsOqvyWXSEjRjwf
+PmC95zA2ucn57OmFc+CLcnYsmOd5B6Uc/LzWiOIOLtKpslcJz3xB6+2hEv7LnHUp
+LKCBs95/9OOqJxO/jYhf
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.pem.certspec
new file mode 100644
index 000000000..7b61447a8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:non-evroot-ca
+subject:non-evroot-ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-ee.pem
new file mode 100644
index 000000000..8bfe3c24c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-ee.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmagAwIBAgIUb0DaaKRK60LnPyfYQvv3fv7MDNUwCwYJKoZIhvcNAQEL
+MCYxJDAiBgNVBAMMG3JldmVyc2Utb3JkZXItb2lkcy1wYXRoLWludDAiGA8yMDE1
+MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAlMSMwIQYDVQQDDBpyZXZlcnNl
+LW9yZGVyLW9pZHMtcGF0aC1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAab
+bhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmts
+Du0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhI
+H6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8
+rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kX
+Mbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBojCBnzBTBggrBgEFBQcBAQRHMEUw
+QwYIKwYBBQUHMAGGN2h0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9yZXZlcnNl
+LW9yZGVyLW9pZHMtcGF0aC1lZS8wKAYDVR0gBCEwHzAHBgVngQwBATAUBhIrBgEE
+AetJhRqFGoUaAYN0CQEwHgYDVR0RBBcwFYITZXYtdGVzdC5leGFtcGxlLmNvbTAL
+BgkqhkiG9w0BAQsDggEBAFHaYdZpIkhnlR8HeiLgSVXhhOh+51dJCMQPGa5GA09W
+90/Tct1J28/7DfVUjdvzX80bWTUkbrEsB12qYPJm+d3B3YSqAS2NHWp7eHwMmTbe
+F3Hxqvu+maLCX/fm7X8t5vCugKrqbbmIMBZ8mrNasR8B3tKIPBFZOt4p+lUfM3rL
+qm7CmQ6OheMcq4pblx6LJMt3CCMPdzyPm6+3Gw9mvBaCXU9exrV1QxxSg8hEpWLw
+/ue3cLx9D6zDITlZZxUXJZOegvKFuVit2JIAv6l2zVIp9IzNnANF2oIOOyVMPP4+
+vDRJTKVchp6fxORk2sCexiEHf6pqj2kmUSMdbsSWxsQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-ee.pem.certspec
new file mode 100644
index 000000000..31e3e69e5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:reverse-order-oids-path-int
+subject:reverse-order-oids-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/reverse-order-oids-path-ee/
+extension:certificatePolicies:2.23.140.1.1,1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-int.pem
new file mode 100644
index 000000000..105064c6d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-int.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDZDCCAk6gAwIBAgIUY0aJPcvdA0d7Xu3Ph5O2pk4D5tYwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAmMSQwIgYDVQQDDBtyZXZlcnNlLW9yZGVyLW9pZHMtcGF0aC1pbnQw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAGjgZ4wgZswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwVAYIKwYBBQUH
+AQEESDBGMEQGCCsGAQUFBzABhjhodHRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgv
+cmV2ZXJzZS1vcmRlci1vaWRzLXBhdGgtaW50LzAoBgNVHSAEITAfMBQGEisGAQQB
+60mFGoUahRoBg3QJATAHBgVngQwBATALBgkqhkiG9w0BAQsDggEBADCsEQZgIoiq
+5XqNnz400S/+sVaHPKl+Zh2mtQiKq2hbIre7rYsO6KISoh52DuAZgrjAd7vbn38g
+8iPCZ2qaytaAZzy8UiUuZK4R5pow0aGEbq6AdtHu40lSUsfQ+a0rj7E0zOyGQjVl
+PrKlAirzX4YkMyYH0trSvOZgwwIsroIfYhXnxJpqo9fW900z+JUGSWTQbA1tFHPN
+9OsM4zyFepbZUqWtf2RZMME63JgUFy3Uvk2vHolEX9OGAegUx7hX0nHIdBCLa5GC
+W2Y99olh0T+bk7aULnwAXFmJozIWdpkLmUeNcjWuGvQAniHIm2YhOxg0BVs43VRK
+t2759N2s5Lk=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-int.pem.certspec
new file mode 100644
index 000000000..a2b523073
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/reverse-order-oids-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:reverse-order-oids-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/reverse-order-oids-path-int/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1,2.23.140.1.1
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem
new file mode 100644
index 000000000..1fe162bc7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwTCCAqugAwIBAgIUC4dd0cUXmrLGZVPePwZkFohfd2kwCwYJKoZIhvcNAQEL
+MD0xOzA5BgNVBAMMMnRlc3QtYW5kLWNhYmZvcnVtLW9pZC1lZS1jYWJmb3J1bS1v
+aWQtaW50LXBhdGgtaW50MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMDwxOjA4BgNVBAMMMXRlc3QtYW5kLWNhYmZvcnVtLW9pZC1lZS1jYWJmb3J1
+bS1vaWQtaW50LXBhdGgtZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24a
+hvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7t
+FYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+o
+N9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0d
+JdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4
+s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjgbkwgbYwagYIKwYBBQUHAQEEXjBcMFoG
+CCsGAQUFBzABhk5odHRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgvdGVzdC1hbmQt
+Y2FiZm9ydW0tb2lkLWVlLWNhYmZvcnVtLW9pZC1pbnQtcGF0aC1lZS8wKAYDVR0g
+BCEwHzAUBhIrBgEEAetJhRqFGoUaAYN0CQEwBwYFZ4EMAQEwHgYDVR0RBBcwFYIT
+ZXYtdGVzdC5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBALBmgZSBw+XV/TrF
+oSJ1IG5kK1en9TYe+8baPhnoPXODSLfO11ljh69VVVgSOexbuEZ0/8g4BOYKjfZ8
+rZxMgBsBbK0lmDcsKsfE4+JVP8YcZ9xK9PTtNSEpLCv0pOaSs0cyhk/VIrlKnK/v
+oEqvrcTKpezU8lgfRnG+e3riFfjMhMNZn1oGaPPgHNF0CAU29qdVvkrPySsWIeVk
+WbOCh5XfaDZqmSwYWWn7AbVeiCs07bzd0R14/KY1gxVYsoiy/1uSG7QQj82cIt75
+sJja57AGHVtwd43829RYPhNgcDOorSCfErZ5HPQBM75y2Nlsc4f7P6DBrJ8m+Q0E
+5+i3niw=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem.certspec
new file mode 100644
index 000000000..edac2fc1a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:test-and-cabforum-oid-ee-cabforum-oid-int-path-int
+subject:test-and-cabforum-oid-ee-cabforum-oid-int-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/test-and-cabforum-oid-ee-cabforum-oid-int-path-ee/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1,2.23.140.1.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem
new file mode 100644
index 000000000..ce757742d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmagAwIBAgIUKz60qRXEfxjvGay98Cp6DRZMIywwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjA9MTswOQYDVQQDDDJ0ZXN0LWFuZC1jYWJmb3J1bS1vaWQtZWUtY2Fi
+Zm9ydW0tb2lkLWludC1wYXRoLWludDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
+nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
+wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
+4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
+yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
+j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBnzCBnDAMBgNVHRMEBTADAQH/
+MAsGA1UdDwQEAwIBBjBrBggrBgEFBQcBAQRfMF0wWwYIKwYBBQUHMAGGT2h0dHA6
+Ly93d3cuZXhhbXBsZS5jb206ODg4OC90ZXN0LWFuZC1jYWJmb3J1bS1vaWQtZWUt
+Y2FiZm9ydW0tb2lkLWludC1wYXRoLWludC8wEgYDVR0gBAswCTAHBgVngQwBATAL
+BgkqhkiG9w0BAQsDggEBAKgWYdHF4n8WXZ9ZYtEZDF9YYh8jI/KMjKK52jqyvh7u
+Hxbv9SJe6H0sDqKvoIisRzv4QSMoS2QTHUalFgEXAexPK75mpITiCnShpUx+QFnR
+fFjG2Gy4ffC+vxuVThpJtut3SD/a7RAyYc6wP1hjohrtvJdOTmMWIZ7spA/BQaCz
+XxiSreJQiNvbuCImC4t9s95xpwcyTD7yWQD2BrJJP69eM/afkF5lKenAVvQhTKa+
+FT/Br5yVyf8lMgjdYK5FljZGJViy7O4KqoUmttgOttFv9EhcqfbGD/Kh6dJ8aJlD
+sHAjNsHzyyPij28pN5zmXiKtjuvh4L8juZYVePWG0Fw=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem.certspec
new file mode 100644
index 000000000..68dfd0057
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-cabforum-oid-int-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:test-and-cabforum-oid-ee-cabforum-oid-int-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/test-and-cabforum-oid-ee-cabforum-oid-int-path-int/
+extension:certificatePolicies:2.23.140.1.1
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-ee.pem
new file mode 100644
index 000000000..ab86be7d9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-ee.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnigAwIBAgIUfYDrsxuoLVA2xXI6wiQM1Ho1ekcwCwYJKoZIhvcNAQEL
+MCwxKjAoBgNVBAMMIXRlc3QtYW5kLWNhYmZvcnVtLW9pZC1lZS1wYXRoLWludDAi
+GA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjArMSkwJwYDVQQDDCB0
+ZXN0LWFuZC1jYWJmb3J1bS1vaWQtZWUtcGF0aC1lZTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBqDCBpTBZBggr
+BgEFBQcBAQRNMEswSQYIKwYBBQUHMAGGPWh0dHA6Ly93d3cuZXhhbXBsZS5jb206
+ODg4OC90ZXN0LWFuZC1jYWJmb3J1bS1vaWQtZWUtcGF0aC1lZS8wKAYDVR0gBCEw
+HzAUBhIrBgEEAetJhRqFGoUaAYN0CQEwBwYFZ4EMAQEwHgYDVR0RBBcwFYITZXYt
+dGVzdC5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBAGxfWJtZkbvUXRKb6ZEw
+2gq44URxeB9DuLfLd1qfEINW+NzhXhyd6BZ7ytLMIQjB55MKc3EM1ZNiU59C+BkV
+IYQF41p5SqKw7Niq4IcnaAGOfCrvZuRJYhU3jxIeLGLI42jk6yuvg/OZjJ61pi0W
+x4CSC3gSJ0oRh/Yg9ZRKo7goNRjH5/UmSGTRF8XqL8+zwTDmUlscON4jKHgZW3iE
+01FUS/haX3S/tUHe8cvu0BGrnhlfUvAr8lMeNIV1B89JYyLdwPi4Ce8prOzRQzqp
+u1jEu2e62t19SaB3PWyTbDHks6RygVrDdIzZ6dtJUmbl7d8Z7VVuvMNGSq6O+inR
+vk4=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-ee.pem.certspec
new file mode 100644
index 000000000..affbd8745
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:test-and-cabforum-oid-ee-path-int
+subject:test-and-cabforum-oid-ee-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/test-and-cabforum-oid-ee-path-ee/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1,2.23.140.1.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-int.pem
new file mode 100644
index 000000000..e508339df
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-int.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkOgAwIBAgIUW3yHLCNMorwxWwyF6vrFuNsEdAQwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAsMSowKAYDVQQDDCF0ZXN0LWFuZC1jYWJmb3J1bS1vaWQtZWUtcGF0
+aC1pbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAGjgY0wgYowDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwWgYI
+KwYBBQUHAQEETjBMMEoGCCsGAQUFBzABhj5odHRwOi8vd3d3LmV4YW1wbGUuY29t
+Ojg4ODgvdGVzdC1hbmQtY2FiZm9ydW0tb2lkLWVlLXBhdGgtaW50LzARBgNVHSAE
+CjAIMAYGBFUdIAAwCwYJKoZIhvcNAQELA4IBAQAXnGkBYTc9jiL1YE4teF+ZRxfk
+Tf2AteJYk53suuAUtQ3xgG4UWY9KHIMF/HLT+ZN3SAsJNgAgg/zBLNaTvt6C52hb
+TUtfW/803g1AUmHAhWg5lruffYpRnKNJdsi6IvWAQec5EDGT8hwq6F28VmgDr3RT
+Je/jgBNzVSifYKQm89f1TJWvdDqWSam0b2ags8l0UPzqHI+GzAn7E2KWamnCXWfD
+BZE9VA/KNc13I/K2tv5zZ/m/LKnTUeSS9qCKCWNjZGI0UIChVcie1t4NJbUf8IUD
+VyUYTm3Z5rO4PUzcR1q8CWzqgb0aKUoq60BWjnr+eipsE0dmc+9OGVAGh3me
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-int.pem.certspec
new file mode 100644
index 000000000..11630b4b4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-and-cabforum-oid-ee-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:test-and-cabforum-oid-ee-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/test-and-cabforum-oid-ee-path-int/
+extension:certificatePolicies:any
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-ee.pem
new file mode 100644
index 000000000..d130202d7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-ee.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDkTCCAnugAwIBAgIUZXXAUcIl4AT9QKUpEiBvQEk7MZswCwYJKoZIhvcNAQEL
+MDAxLjAsBgNVBAMMJXRlc3Qtb2lkLWVlLWNhYmZvcnVtLW9pZC1pbnQtcGF0aC1p
+bnQwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowLzEtMCsGA1UE
+AwwkdGVzdC1vaWQtZWUtY2FiZm9ydW0tb2lkLWludC1wYXRoLWVlMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVK
+tOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7N
+Q/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39Zgsr
+sCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxs
+l62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYl
+nauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABo4Gj
+MIGgMF0GCCsGAQUFBwEBBFEwTzBNBggrBgEFBQcwAYZBaHR0cDovL3d3dy5leGFt
+cGxlLmNvbTo4ODg4L3Rlc3Qtb2lkLWVlLWNhYmZvcnVtLW9pZC1pbnQtcGF0aC1l
+ZS8wHwYDVR0gBBgwFjAUBhIrBgEEAetJhRqFGoUaAYN0CQEwHgYDVR0RBBcwFYIT
+ZXYtdGVzdC5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEBACBZnkQzVzZgGJRb
+CMAhvJSq9tWlaze1wTsCTo9YJu4/Np2MHdOZqh66saV+6KcNpmuibGwC516ooO9B
+OUBXq3fGurYwMuSQmONQ+i8eDIRDGJHrhSPqlEvZzW5tOMzUMgf8e1YeIVIEy4bz
+KEbDyc7o4fXpVewOqeD52TdR6RmJjXpbGDlSEqWoH6idvvnIMRuXAwTP3BWtZfRd
+w0RM+sEUozTeM1IuWQWe2wJtugLULxroMGJzjyyW0xBPGtrWqi3rdMdz8bKgV0qz
+LOC5OClY9gvEScjBS46RwahMLj5gK8K0Cxoqicx87it/mKrh0/IuJAZLHd/MMzAJ
+eF525sY=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-ee.pem.certspec
new file mode 100644
index 000000000..bd0f955ad
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:test-oid-ee-cabforum-oid-int-path-int
+subject:test-oid-ee-cabforum-oid-int-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/test-oid-ee-cabforum-oid-int-path-ee/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-int.pem
new file mode 100644
index 000000000..60f9e2855
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-int.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDYjCCAkygAwIBAgIUT58S8MhTFBFpWcGoT3Ni9HEDT6IwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAwMS4wLAYDVQQDDCV0ZXN0LW9pZC1lZS1jYWJmb3J1bS1vaWQtaW50
+LXBhdGgtaW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABo4GSMIGPMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEG
+MF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAYZCaHR0cDovL3d3dy5leGFtcGxl
+LmNvbTo4ODg4L3Rlc3Qtb2lkLWVlLWNhYmZvcnVtLW9pZC1pbnQtcGF0aC1pbnQv
+MBIGA1UdIAQLMAkwBwYFZ4EMAQEwCwYJKoZIhvcNAQELA4IBAQBwXLEGvl0aJ3Wf
+nVJoV9EzL+df9oY0IBpZVpkNSyWQ+111lKMftznJct+mJsuAf23PcHJtUwSWQzaS
+W5DTzF32B6FiPPqS2N8v1eIIM/fjNdZXrMEFGfR5MwwoU4IPwjvIgoFT2LGv9PvP
+82o5PcEurK/HEhWCvn2r1rLAi1sr0sjd/yHJ6otwweWf6U6fREqzoVqB0HxhbToH
+BgR/YmTrFFCvUar/zwH6/G0ZMkJR98q7XairdCDgjlwY6Nk6gXR2noMMHwFeJP+h
+QCkXy2/w6332rmEHzokU3z/p0Y3NtEHK8n0+LIxg6akVovHTvLVJy+THUGQjPe0B
+pxlHKwek
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-int.pem.certspec
new file mode 100644
index 000000000..37d4d133a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-ee-cabforum-oid-int-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:test-oid-ee-cabforum-oid-int-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/test-oid-ee-cabforum-oid-int-path-int/
+extension:certificatePolicies:2.23.140.1.1
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-ee.pem b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-ee.pem
new file mode 100644
index 000000000..67e14e875
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-ee.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj+gAwIBAgIUBR6mXmzAxA30s74v94EkKkcvL/AwCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEXRlc3Qtb2lkLXBhdGgtaW50MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMBsxGTAXBgNVBAMMEHRlc3Qtb2lkLXBhdGgtZWUw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAGjgY8wgYwwSQYIKwYBBQUHAQEEPTA7MDkGCCsGAQUFBzABhi1odHRwOi8v
+d3d3LmV4YW1wbGUuY29tOjg4ODgvdGVzdC1vaWQtcGF0aC1lZS8wHwYDVR0gBBgw
+FjAUBhIrBgEEAetJhRqFGoUaAYN0CQEwHgYDVR0RBBcwFYITZXYtdGVzdC5leGFt
+cGxlLmNvbTALBgkqhkiG9w0BAQsDggEBAKMkVA1VZlzajbBFNqwzSGfUipM1TzqH
+YjumITzJSBESfRZPfrtTEFtelfHUVq9Oh4oO8e2RPAgECw/tchZcJW4oYT2+wi1h
+rcHK8DutOC5rMpM3HP0tQlSCVtnb5maF9y/Z7mXrYKB3bYsA5gG022b/w91aiA6a
+MJqhRe8uv5dA1+SVMjgdJTDn+x8TBBwZlmoPSd2I21mC0C2URXRRZkTM1ZRZWnFQ
+brZ94cwfshjpONjPglOiM0p+uVSKhatnP3EqjfQVaTow7+RNPyHXNnaTsgz03j3w
+tnNRDhYZuSZzNZcugylGzt/U9nbE5B2VVjFuAw9DuCeUnPUm0EGxwF4=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-ee.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-ee.pem.certspec
new file mode 100644
index 000000000..a9d62c65e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-ee.pem.certspec
@@ -0,0 +1,5 @@
+issuer:test-oid-path-int
+subject:test-oid-path-ee
+extension:authorityInformationAccess:http://www.example.com:8888/test-oid-path-ee/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
+extension:subjectAlternativeName:ev-test.example.com
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.key b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.key
new file mode 100644
index 000000000..8af23e068
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAECggEBAJ7LzjhhpFTsseD+j4XdQ8kvWCXOLpl4hNDhqUnaosWs
+VZskBFDlrJ/gw+McDu+mUlpl8MIhlABO4atGPd6e6CKHzJPnRqkZKcXmrD2IdT9s
+JbpZeec+XY+yOREaPNq4pLDN9fnKsF8SM6ODNcZLVWBSXn47kq18dQTPHcfLAFeI
+r8vh6Pld90AqFRUw1YCDRoZOs3CqeZVqWHhiy1M3kTB/cNkcltItABppAJuSPGgz
+iMnzbLm16+ZDAgQceNkIIGuHAJy4yrrK09vbJ5L7kRss9NtmA1hb6a4Mo7jmQXqg
+SwbkcOoaO1gcoDpngckxW2KzDmAR8iRyWUbuxXxtlEECgYEA3W4dT//r9o2InE0R
+TNqqnKpjpZN0KGyKXCmnF7umA3VkTVyqZ0xLi8cyY1hkYiDkVQ12CKwn1Vttt0+N
+gSfvj6CQmLaRR94GVXNEfhg9Iv59iFrOtRPZWB3V4HwakPXOCHneExNx7O/JznLp
+xD3BJ9I4GQ3oEXc8pdGTAfSMdCsCgYEA16dz2evDgKdn0v7Ak0rU6LVmckB3Gs3r
+ta15b0eP7E1FmF77yVMpaCicjYkQL63yHzTi3UlA66jAnW0fFtzClyl3TEMnXpJR
+3b5JCeH9O/Hkvt9Go5uLODMo70rjuVuS8gcK8myefFybWH/t3gXo59hspXiG+xZY
+EKd7mEW8MScCgYEAlkcrQaYQwK3hryJmwWAONnE1W6QtS1oOtOnX6zWBQAul3RMs
+2xpekyjHu8C7sBVeoZKXLt+X0SdR2Pz2rlcqMLHqMJqHEt1OMyQdse5FX8CT9byb
+WS11bmYhR08ywHryL7J100B5KzK6JZC7smGu+5WiWO6lN2VTFb6cJNGRmS0CgYAo
+tFCnp1qFZBOyvab3pj49lk+57PUOOCPvbMjo+ibuQT+LnRIFVA8Su+egx2got7pl
+rYPMpND+KiIBFOGzXQPVqFv+Jwa9UPzmz83VcbRspiG47UfWBbvnZbCqSgZlrCU2
+TaIBVAMuEgS4VZ0+NPtbF3yaVv+TUQpaSmKHwVHeLQKBgCgGe5NVgB0u9S36ltit
+tYlnPPjuipxv9yruq+nva+WKT0q/BfeIlH3IUf2qNFQhR6caJGv7BU7naqNGq80m
+ks/J5ExR5vBpxzXgc7oBn2pyFJYckbJoccrqv48GRBigJpDjmo1f8wZ7fNt/ULH1
+NBinA5ZsT8d0v3QCr2xDJH9D
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.key.keyspec b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.key.keyspec
new file mode 100644
index 000000000..4ad96d515
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.key.keyspec
@@ -0,0 +1 @@
+default
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.pem b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.pem
new file mode 100644
index 000000000..cbfd53b47
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDRzCCAjGgAwIBAgIURUX21bPV9r+a9MgTdgH/Z0JF7fEwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAcMRowGAYDVQQDDBF0ZXN0LW9pZC1wYXRoLWludDCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs
+9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8
+HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7Ak
+kqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJet
+lmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2r
+kQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBizCB
+iDAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjBKBggrBgEFBQcBAQQ+MDwwOgYI
+KwYBBQUHMAGGLmh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC90ZXN0LW9pZC1w
+YXRoLWludC8wHwYDVR0gBBgwFjAUBhIrBgEEAetJhRqFGoUaAYN0CQEwCwYJKoZI
+hvcNAQELA4IBAQAZpXz9L80yAL7c4NxT761VSaAxlL7djEAFx8XzTRI3Npd7pH9J
+GjD08pBw4fJoRkVaZhHMfTylYLR/trURFsBF/P9CCqcKUBk6P2hReEsmSV+nG8xp
+zs8M0JEoJbD3gWytwV0LZgc8INkmwo91CYlgvpBqpRrowdyYEc/+pE0lyn6kwjJE
+k6OwDnI1sbl3Aid9iMILITqvt9pRTh2ZbcpgXXRifk+LJNNgo+U54+VHEy1sGjFp
+/tXOqCeKAV5peEbWnXfewaitKTGBE/6zuEBQTeWzNDcwQwSYvS9oRcLxNn/qIyrj
+OIaT9QQeDT0AbHNIRj8npCaZrSxWRMPH12/4
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.pem.certspec b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.pem.certspec
new file mode 100644
index 000000000..53534eb52
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ev_certs/test-oid-path-int.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:test-oid-path-int
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/test-oid-path-int/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_forget_about_site_security_headers.js b/security/manager/ssl/tests/unit/test_forget_about_site_security_headers.js
new file mode 100644
index 000000000..4db133e43
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_forget_about_site_security_headers.js
@@ -0,0 +1,100 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim: sw=2 ts=2 sts=2
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Ensures that HSTS (HTTP Strict Transport Security) and HPKP (HTTP Public key
+// pinning) are cleared when using "Forget About This Site".
+
+var { ForgetAboutSite } = Cu.import("resource://gre/modules/ForgetAboutSite.jsm", {});
+
+do_register_cleanup(() => {
+ Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
+ Services.prefs.clearUserPref(
+ "security.cert_pinning.process_headers_from_non_builtin_roots");
+});
+
+const GOOD_MAX_AGE_SECONDS = 69403;
+const NON_ISSUED_KEY_HASH = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
+const VALID_PIN = `pin-sha256="${PINNING_ROOT_KEY_HASH}";`;
+const BACKUP_PIN = `pin-sha256="${NON_ISSUED_KEY_HASH}";`;
+const GOOD_MAX_AGE = `max-age=${GOOD_MAX_AGE_SECONDS};`;
+
+do_get_profile(); // must be done before instantiating nsIX509CertDB
+
+Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
+Services.prefs.setBoolPref(
+ "security.cert_pinning.process_headers_from_non_builtin_roots", true);
+
+var certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+addCertFromFile(certdb, "test_pinning_dynamic/pinningroot.pem", "CTu,CTu,CTu");
+
+var sss = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+var uri = Services.io.newURI("https://a.pinning2.example.com", null, null);
+
+// This test re-uses certificates from pinning tests because that's easier and
+// simpler than recreating new certificates, hence the slightly longer than
+// necessary domain name.
+var sslStatus = new FakeSSLStatus(constructCertFromFile(
+ "test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem"));
+
+// Test the normal case of processing HSTS and HPKP headers for
+// a.pinning2.example.com, using "Forget About Site" on a.pinning2.example.com,
+// and then checking that the platform doesn't consider a.pinning2.example.com
+// to be HSTS or HPKP any longer.
+add_task(function* () {
+ sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri, GOOD_MAX_AGE,
+ sslStatus, 0);
+ sss.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
+ GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN, sslStatus, 0);
+
+ Assert.ok(sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "a.pinning2.example.com", 0),
+ "a.pinning2.example.com should be HSTS");
+ Assert.ok(sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "a.pinning2.example.com", 0),
+ "a.pinning2.example.com should be HPKP");
+
+ yield ForgetAboutSite.removeDataFromDomain("a.pinning2.example.com");
+
+ Assert.ok(!sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "a.pinning2.example.com", 0),
+ "a.pinning2.example.com should not be HSTS now");
+ Assert.ok(!sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "a.pinning2.example.com", 0),
+ "a.pinning2.example.com should not be HPKP now");
+});
+
+// TODO (bug 1290529): the platform does not support this yet.
+// Test the case of processing HSTS and HPKP headers for a.pinning2.example.com,
+// using "Forget About Site" on example.com, and then checking that the platform
+// doesn't consider the subdomain to be HSTS or HPKP any longer.
+add_task(function* () {
+ sss.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri, GOOD_MAX_AGE,
+ sslStatus, 0);
+ sss.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
+ GOOD_MAX_AGE + VALID_PIN + BACKUP_PIN, sslStatus, 0);
+
+ Assert.ok(sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "a.pinning2.example.com", 0),
+ "a.pinning2.example.com should be HSTS (subdomain case)");
+ Assert.ok(sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "a.pinning2.example.com", 0),
+ "a.pinning2.example.com should be HPKP (subdomain case)");
+
+ yield ForgetAboutSite.removeDataFromDomain("example.com");
+
+ // TODO (bug 1290529):
+ // Assert.ok(!sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ // "a.pinning2.example.com", 0),
+ // "a.pinning2.example.com should not be HSTS now (subdomain case)");
+ // Assert.ok(!sss.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ // "a.pinning2.example.com", 0),
+ // "a.pinning2.example.com should not be HPKP now (subdomain case)");
+});
diff --git a/security/manager/ssl/tests/unit/test_getchain.js b/security/manager/ssl/tests/unit/test_getchain.js
new file mode 100644
index 000000000..2851c3a70
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_getchain.js
@@ -0,0 +1,82 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+// This is the list of certificates needed for the test.
+var certList = [
+ 'ee',
+ 'ca-1',
+ 'ca-2',
+];
+
+// Since all the ca's are identical expect for the serial number
+// I have to grab them by enumerating all the certs and then finding
+// the ones that I am interested in.
+function get_ca_array() {
+ let ret_array = [];
+ let allCerts = certdb.getCerts();
+ let enumerator = allCerts.getEnumerator();
+ while (enumerator.hasMoreElements()) {
+ let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
+ if (cert.commonName == 'ca') {
+ ret_array[parseInt(cert.serialNumber, 16)] = cert;
+ }
+ }
+ return ret_array;
+}
+
+
+function check_matching_issuer_and_getchain(expected_issuer_serial, cert) {
+ const nsIX509Cert = Components.interfaces.nsIX509Cert;
+
+ equal(expected_issuer_serial, cert.issuer.serialNumber,
+ "Expected and actual issuer serial numbers should match");
+ let chain = cert.getChain();
+ let issuer_via_getchain = chain.queryElementAt(1, nsIX509Cert);
+ // The issuer returned by cert.issuer or cert.getchain should be consistent.
+ equal(cert.issuer.serialNumber, issuer_via_getchain.serialNumber,
+ "Serial numbers via cert.issuer and via getChain() should match");
+}
+
+function check_getchain(ee_cert, ssl_ca, email_ca) {
+ // A certificate should first build a chain/issuer to
+ // a SSL trust domain, then an EMAIL trust domain and then
+ // an object signer trust domain.
+
+ const nsIX509Cert = Components.interfaces.nsIX509Cert;
+ certdb.setCertTrust(ssl_ca, nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL);
+ certdb.setCertTrust(email_ca, nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_EMAIL);
+ check_matching_issuer_and_getchain(ssl_ca.serialNumber, ee_cert);
+ certdb.setCertTrust(ssl_ca, nsIX509Cert.CA_CERT, 0);
+ check_matching_issuer_and_getchain(email_ca.serialNumber, ee_cert);
+ certdb.setCertTrust(email_ca, nsIX509Cert.CA_CERT, 0);
+ // Do a final test on the case of no trust. The results must
+ // be consistent (the actual value is non-deterministic).
+ check_matching_issuer_and_getchain(ee_cert.issuer.serialNumber, ee_cert);
+}
+
+function run_test() {
+ clearOCSPCache();
+ clearSessionCache();
+
+ for (let cert of certList) {
+ addCertFromFile(certdb, `test_getchain/${cert}.pem`, ",,");
+ }
+
+ let ee_cert = certdb.findCertByNickname('ee');
+ notEqual(ee_cert, null, "EE cert should be in the cert DB");
+
+ let ca = get_ca_array();
+
+ check_getchain(ee_cert, ca[1], ca[2]);
+ // Swap ca certs to deal alternate trust settings.
+ check_getchain(ee_cert, ca[2], ca[1]);
+}
diff --git a/security/manager/ssl/tests/unit/test_getchain/ca-1.pem b/security/manager/ssl/tests/unit/test_getchain/ca-1.pem
new file mode 100644
index 000000000..a3dcb268c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_getchain/ca-1.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsjCCAZygAwIBAgIBATALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP
+MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCY2Ew
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEB
+CwOCAQEAchHf1yV+blE6fvS53L3DGmvxEpn9+t+xwOvWczBmLFEzUPdncakdaWlQ
+v7q81BPyjBqkYbQi15Ws81hY3dnXn8LT1QktCL9guvc3z4fMdQbRjpjcIReCYt3E
+PB22Jl2FCm6ii4XL0qDFD26WK3zMe2Uks6t55f8VeDTBGNoPp2JMsWY1Pi4vR6wK
+AY96WoXS/qrYkmMEOgFu907pApeAeE8VJzXjqMLF6/W1VN7ISnGzWQ8zKQnlp3YA
+mvWZQcD6INK8mvpZxIeu6NtHaKEXGw7tlGekmkVhapPtQZYnWcsXybRrZf5g3hOh
+JFPl8kW42VoxXL11PP5NX2ylTsJ//g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_getchain/ca-1.pem.certspec b/security/manager/ssl/tests/unit/test_getchain/ca-1.pem.certspec
new file mode 100644
index 000000000..6062931cd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_getchain/ca-1.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+serialNumber:1
diff --git a/security/manager/ssl/tests/unit/test_getchain/ca-2.pem b/security/manager/ssl/tests/unit/test_getchain/ca-2.pem
new file mode 100644
index 000000000..fab9f209e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_getchain/ca-2.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsjCCAZygAwIBAgIBAjALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP
+MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCY2Ew
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEB
+CwOCAQEAXjVM9rVj8ZtTUvdKGMWaYkLGKqvi4dwK2ZwvAqeybTK7XCRKmXYksAxT
+NVKx2DgHn0r0nYk7gu3TYKpFfI4i1zSriq4FXd8Z5fhbRGToyU6nFBqWnDET+haJ
++jrI34kLG1oXqZMbbcUZX7sXnVYafxr/MYBVhtIwwUV8tgX+5SzdRsZ85REiBGbZ
+Y915NAo7ZNfGkjOSNS3BycdHPMgEHqONq+BSAwYAuKT05LI/KgSZK+8vfNrcvvMV
+TO1T4HC3vmOuKZkMWTj6JKyGO07R3CNypW+9Fi5LjRjVFf2acZM0VVPsSdiIp1EZ
+xa6RkYqPfRLrTKUkti6BFJlXozfnNA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_getchain/ca-2.pem.certspec b/security/manager/ssl/tests/unit/test_getchain/ca-2.pem.certspec
new file mode 100644
index 000000000..bb599046e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_getchain/ca-2.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+serialNumber:2
diff --git a/security/manager/ssl/tests/unit/test_getchain/ee.pem b/security/manager/ssl/tests/unit/test_getchain/ee.pem
new file mode 100644
index 000000000..237e36bf0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_getchain/ee.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICpjCCAZCgAwIBAgIUQ9aT0/eKZXjA2Ma4sq+QU+/srsowCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAEWMrrsgZ
+yxJk3jvJA5l7J6L9yspBBY/bpi7x4YTWssHemTdJVQAX4p+9rKCa5CfEy5LrE4up
+KnNyMYJzlFuLvcu4ExOmj5ceGRiD5s++g5R4OHzn9QNUeav9b3dFPT3q7dLg2Emm
+RClgZGiwgBXZsaa+urw7Y4oi8DhMePHt523Wv6JFacV42tq0TqIzDIH61nhGamJC
+TafTmYZqGTaNxweBy9m3JJot3zwqTId98TlJStY+oHYI9vGBD8ug0xQWd233d1k9
+BH5axHeYUu2GKLauWH49zSBv+hAeYKmjU3p1qIEzFsQ7ezUNJu5/x+kiClTclITJ
+IrtAUwHJuatuWQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_getchain/ee.pem.certspec b/security/manager/ssl/tests/unit/test_getchain/ee.pem.certspec
new file mode 100644
index 000000000..34e99782b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_getchain/ee.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:ee
diff --git a/security/manager/ssl/tests/unit/test_getchain/moz.build b/security/manager/ssl/tests/unit/test_getchain/moz.build
new file mode 100644
index 000000000..8bf3d1082
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_getchain/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca-1.pem',
+# 'ca-2.pem',
+# 'ee.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_hash_algorithms.js b/security/manager/ssl/tests/unit/test_hash_algorithms.js
new file mode 100644
index 000000000..17ccd0781
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_hash_algorithms.js
@@ -0,0 +1,87 @@
+"use strict";
+
+const messages = [
+ "The quick brown fox jumps over the lazy dog",
+ ""
+];
+const hashes = {
+ md2: [
+ "03d85a0d629d2c442e987525319fc471",
+ "8350e5a3e24c153df2275c9f80692773"
+ ],
+ md5: [
+ "9e107d9d372bb6826bd81d3542a419d6",
+ "d41d8cd98f00b204e9800998ecf8427e"
+ ],
+ sha1: [
+ "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
+ "da39a3ee5e6b4b0d3255bfef95601890afd80709"
+ ],
+ sha256: [
+ "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ ],
+ sha384: [
+ "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1",
+ "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
+ ],
+ sha512: [
+ "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
+ "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
+ ]
+};
+
+function hexdigest(data) {
+ // |slice(-2)| chomps off the last two characters of a string.
+ //
+ // Therefore, if the Unicode value is < 10, we have a single-character hex
+ // string when we want one that's two characters, and unconditionally
+ // prepending a "0" solves the problem.
+ return Array.from(data, (c, i) => ("0" + data.charCodeAt(i).toString(16)).slice(-2)).join("");
+}
+
+function doHash(algo, value, cmp) {
+ let hash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
+ hash.initWithString(algo);
+
+ let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+ .createInstance(Ci.nsIScriptableUnicodeConverter);
+ converter.charset = 'utf8';
+ value = converter.convertToByteArray(value);
+ hash.update(value, value.length);
+ equal(hexdigest(hash.finish(false)), cmp,
+ `Actual and expected hash for ${algo} should match`);
+
+ hash.initWithString(algo);
+ hash.update(value, value.length);
+ equal(hexdigest(hash.finish(false)), cmp,
+ `Actual and expected hash for ${algo} should match after re-init`);
+}
+
+function doHashStream(algo, value, cmp) {
+ let hash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
+ hash.initWithString(algo);
+
+ let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+ .createInstance(Ci.nsIScriptableUnicodeConverter);
+ converter.charset = 'utf8';
+ let stream = converter.convertToInputStream(value);
+ hash.updateFromStream(stream, stream.available());
+ equal(hexdigest(hash.finish(false)), cmp,
+ `Actual and expected hash for ${algo} should match updating from stream`);
+}
+
+function run_test() {
+ for (let algo in hashes) {
+ hashes[algo].forEach(
+ function(e, i) {
+ doHash(algo, messages[i], e);
+
+ if (messages[i].length) {
+ // this test doesn't work for empty string/stream
+ doHashStream(algo, messages[i], e);
+ }
+ }
+ );
+ }
+}
diff --git a/security/manager/ssl/tests/unit/test_hash_algorithms_wrap.js b/security/manager/ssl/tests/unit/test_hash_algorithms_wrap.js
new file mode 100644
index 000000000..f2b7016c0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_hash_algorithms_wrap.js
@@ -0,0 +1,5 @@
+"use strict";
+
+function run_test() {
+ run_test_in_child("test_hash_algorithms.js");
+}
diff --git a/security/manager/ssl/tests/unit/test_hmac.js b/security/manager/ssl/tests/unit/test_hmac.js
new file mode 100644
index 000000000..7adc46190
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_hmac.js
@@ -0,0 +1,88 @@
+"use strict";
+
+var ScriptableUnicodeConverter =
+ Components.Constructor("@mozilla.org/intl/scriptableunicodeconverter",
+ "nsIScriptableUnicodeConverter");
+
+function getHMAC(data, key, alg) {
+ let converter = new ScriptableUnicodeConverter();
+ converter.charset = "utf8";
+ let dataArray = converter.convertToByteArray(data);
+
+ let keyObject = Cc["@mozilla.org/security/keyobjectfactory;1"]
+ .getService(Ci.nsIKeyObjectFactory)
+ .keyFromString(Ci.nsIKeyObject.HMAC, key);
+
+ let cryptoHMAC = Cc["@mozilla.org/security/hmac;1"]
+ .createInstance(Ci.nsICryptoHMAC);
+
+ cryptoHMAC.init(alg, keyObject);
+ cryptoHMAC.update(dataArray, dataArray.length);
+ let digest1 = cryptoHMAC.finish(false);
+
+ cryptoHMAC.reset();
+ cryptoHMAC.update(dataArray, dataArray.length);
+ let digest2 = cryptoHMAC.finish(false);
+
+ equal(digest1, digest2,
+ "Initial digest and digest after calling reset() should match");
+
+ return digest1;
+}
+
+function testHMAC(alg) {
+ const key1 = 'MyKey_ABCDEFGHIJKLMN';
+ const key2 = 'MyKey_01234567890123';
+
+ const dataA = "Secret message";
+ const dataB = "Secres message";
+
+ let digest1a = getHMAC(key1, dataA, alg);
+ let digest2 = getHMAC(key2, dataA, alg);
+ let digest1b = getHMAC(key1, dataA, alg);
+
+ equal(digest1a, digest1b,
+ "The digests for the same key, data and algorithm should match");
+ notEqual(digest1a, digest2, "The digests for different keys should not match");
+
+ let digest1 = getHMAC(key1, dataA, alg);
+ digest2 = getHMAC(key1, dataB, alg);
+
+ notEqual(digest1, digest2, "The digests for different data should not match");
+}
+
+function hexdigest(data) {
+ return Array.from(data, (c, i) => ("0" + data.charCodeAt(i).toString(16)).slice(-2)).join("");
+}
+
+function testVectors() {
+ // These are test vectors taken from RFC 4231, section 4.3. (Test Case 2)
+ const keyTestVector = "Jefe";
+ const dataTestVector = "what do ya want for nothing?";
+
+ let digest = hexdigest(getHMAC(dataTestVector, keyTestVector,
+ Ci.nsICryptoHMAC.SHA256));
+ equal(digest,
+ "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ "Actual and expected SHA-256 digests should match");
+
+ digest = hexdigest(getHMAC(dataTestVector, keyTestVector,
+ Ci.nsICryptoHMAC.SHA384));
+ equal(digest,
+ "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
+ "Actual and expected SHA-384 digests should match");
+
+ digest = hexdigest(getHMAC(dataTestVector, keyTestVector,
+ Ci.nsICryptoHMAC.SHA512));
+ equal(digest,
+ "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
+ "Actual and expected SHA-512 digests should match");
+}
+
+function run_test() {
+ testVectors();
+
+ testHMAC(Ci.nsICryptoHMAC.SHA1);
+ testHMAC(Ci.nsICryptoHMAC.SHA512);
+ testHMAC(Ci.nsICryptoHMAC.MD5);
+}
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints.js b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints.js
new file mode 100644
index 000000000..5ebc1546b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints.js
@@ -0,0 +1,111 @@
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function load_cert(name, trust) {
+ let filename = "test_intermediate_basic_usage_constraints/" + name + ".pem";
+ addCertFromFile(certdb, filename, trust);
+}
+
+function test_cert_for_usages(certChainNicks, expected_usages) {
+ let certs = [];
+ for (let i in certChainNicks) {
+ let certNick = certChainNicks[i];
+ let certPEM = readFile(
+ do_get_file("test_intermediate_basic_usage_constraints/"
+ + certNick + ".pem"), false);
+ certs.push(certdb.constructX509FromBase64(pemToBase64(certPEM)));
+ }
+
+ let cert = certs[0];
+ return asyncTestCertificateUsages(certdb, cert, expected_usages);
+}
+
+add_task(function* () {
+ let ee_usages = [ certificateUsageSSLClient, certificateUsageSSLServer,
+ certificateUsageEmailSigner, certificateUsageEmailRecipient,
+ certificateUsageObjectSigner ];
+ let ca_usages = [ certificateUsageSSLCA, certificateUsageVerifyCA ];
+ let eku_usages = [ certificateUsageSSLClient, certificateUsageSSLServer ];
+
+ // Load the ca into mem
+ let ca_name = "ca";
+ load_cert(ca_name, "CTu,CTu,CTu");
+ yield test_cert_for_usages([ca_name], ca_usages);
+
+ // A certificate with no basicConstraints extension is considered an EE.
+ yield test_cert_for_usages(["int-no-extensions"], ee_usages);
+
+ // int-no-extensions is an EE (see previous case), so no certs can chain to
+ // it.
+ yield test_cert_for_usages(["ee-int-no-extensions", "int-no-extensions"], []);
+
+ // a certificate with basicConstraints.cA==false is considered an EE.
+ yield test_cert_for_usages(["int-not-a-ca"], ee_usages);
+
+ // int-not-a-ca is an EE (see previous case), so no certs can chain to it.
+ yield test_cert_for_usages(["ee-int-not-a-ca", "int-not-a-ca"], []);
+
+ // a certificate with basicConstraints.cA==false but with the keyCertSign
+ // key usage may not act as a CA (it can act like an end-entity).
+ yield test_cert_for_usages(["int-cA-FALSE-asserts-keyCertSign"], ee_usages);
+ yield test_cert_for_usages(["ee-int-cA-FALSE-asserts-keyCertSign",
+ "int-cA-FALSE-asserts-keyCertSign"], []);
+
+
+ // int-limited-depth has cA==true and a path length constraint of zero.
+ yield test_cert_for_usages(["int-limited-depth"], ca_usages);
+
+ // path length constraints do not affect the ability of a non-CA cert to
+ // chain to to the CA cert.
+ yield test_cert_for_usages(["ee-int-limited-depth", "int-limited-depth"],
+ ee_usages);
+
+ // ca
+ // int-limited-depth (cA==true, pathLenConstraint==0)
+ // int-limited-depth-invalid (cA==true)
+ //
+ yield test_cert_for_usages(["int-limited-depth-invalid", "int-limited-depth"],
+ []);
+ yield test_cert_for_usages(["ee-int-limited-depth-invalid",
+ "int-limited-depth-invalid", "int-limited-depth"],
+ []);
+
+ // int-valid-ku-no-eku has keyCertSign
+ yield test_cert_for_usages(["int-valid-ku-no-eku"], ca_usages);
+ yield test_cert_for_usages(["ee-int-valid-ku-no-eku", "int-valid-ku-no-eku"],
+ ee_usages);
+
+ // int-bad-ku-no-eku has basicConstraints.cA==true and has a KU extension
+ // but the KU extension is missing keyCertSign. Note that mozilla::pkix
+ // doesn't validate certificates with basicConstraints.Ca==true for non-CA
+ // uses.
+ yield test_cert_for_usages(["int-bad-ku-no-eku"], []);
+ yield test_cert_for_usages(["ee-int-bad-ku-no-eku", "int-bad-ku-no-eku"], []);
+
+ // int-no-ku-no-eku has basicConstraints.cA==true and no KU extension.
+ // We treat a missing KU as "any key usage is OK".
+ yield test_cert_for_usages(["int-no-ku-no-eku"], ca_usages);
+ yield test_cert_for_usages(["ee-int-no-ku-no-eku", "int-no-ku-no-eku"],
+ ee_usages);
+
+ // int-valid-ku-server-eku has basicConstraints.cA==true, keyCertSign in KU,
+ // and EKU=={id-kp-serverAuth,id-kp-clientAuth}.
+ yield test_cert_for_usages(["int-valid-ku-server-eku"], ca_usages);
+ yield test_cert_for_usages(["ee-int-valid-ku-server-eku",
+ "int-valid-ku-server-eku"], eku_usages);
+
+ // int-bad-ku-server-eku has basicConstraints.cA==true, a KU without
+ // keyCertSign, and EKU=={id-kp-serverAuth,id-kp-clientAuth}.
+ yield test_cert_for_usages(["int-bad-ku-server-eku"], []);
+ yield test_cert_for_usages(["ee-int-bad-ku-server-eku",
+ "int-bad-ku-server-eku"], []);
+
+ // int-bad-ku-server-eku has basicConstraints.cA==true, no KU, and
+ // EKU=={id-kp-serverAuth,id-kp-clientAuth}.
+ yield test_cert_for_usages(["int-no-ku-server-eku"], ca_usages);
+ yield test_cert_for_usages(["ee-int-no-ku-server-eku",
+ "int-no-ku-server-eku"], eku_usages);
+});
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.pem
new file mode 100644
index 000000000..f9bc514d4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICuDCCAaKgAwIBAgIUNRoMRQGf1ZJA3n83kdc6L92/CEowCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MAsGCSqG
+SIb3DQEBCwOCAQEAs/WSLtD9nmferqrktS7n94DuJKXYIyVwANS+HUSP515q0zTY
+12Poo6n4UAJpAcO+MK2DhBREa3qtQBxxazmC6zAqvyOCE6l7YlzDXbjqLSfKn3ti
+JrltsfR/0P5zqLDPu2TaXaYey+dtGqvGINjRccB9OknroUH+jX7jWqGBL4Gz8IOR
+5I30FWKfDZTuhMNyBCVpCo5IL5VUdEgZsOlBe5jnGPtN7Q3LmFU91yoRXoOtp+e6
+94pZNhJqGfqLpH8ArRi5qr4QteCRSfvYFBusniJOLnGDi6K3Nh6iBvwPM8qSfQ5A
+Cj361pbNvT+OPpdlm9DFCh6k8jKhZ2fXXMHdtg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.pem.certspec
new file mode 100644
index 000000000..eb7c4b4be
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.pem
new file mode 100644
index 000000000..7204416fd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5jCCAdCgAwIBAgIUK7AF47QInCeFM5oGehLpWlwykXswCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEWludC1iYWQta3Utbm8tZWt1MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMB8xHTAbBgNVBAMMFGVlLWludC1iYWQta3Utbm8t
+ZWt1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62
+iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHql
+WqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosq
+Qe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+
+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8i
+b2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoY
+CjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQEAMAsGA1UdDwQEAwID+DALBgkqhkiG
+9w0BAQsDggEBAJ03z0DxaMoamG4vjSJmVCVD5fg10BGbE59JqcA8IxjXMe4cbR7M
+eTBKx1SkwMIF5YblRtDJ486Xv+jddU+Ahtggbm5DQJ1y1q/Aqq1o4YVAqNoAbJ0o
+xapRfv/qzxqjKTnUdO0f4MLdAmR+62JFrUgw9CYQ/ve3DagsO07BYXEjtHVIB0Wx
+ur68eVQofh+3GkNJwP5g66wCIwbfMAZa50Z+0F8xRLPbAcObdvAxkuPDjsY0a3g+
+Jkkv2mnDm5ABmeqihCNBd5RAgC3xOToWosk4PlJGslydA339L5/K47wdGYLcWC5R
+VgAshQo/kwWTpHu3qbUkIEtFbYxJ7ab7Gak=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.pem.certspec
new file mode 100644
index 000000000..390adf234
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-bad-ku-no-eku
+subject:ee-int-bad-ku-no-eku
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.pem
new file mode 100644
index 000000000..0d39a7832
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7jCCAdigAwIBAgIUXYbRaawTt2Kjb5NY/aIyZ9Us5m4wCwYJKoZIhvcNAQEL
+MCAxHjAcBgNVBAMMFWludC1iYWQta3Utc2VydmVyLWVrdTAiGA8yMDE1MTEyODAw
+MDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAjMSEwHwYDVQQDDBhlZS1pbnQtYmFkLWt1
+LXNlcnZlci1la3UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGo
+RI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9a
+dWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6t
+aRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8n
+FthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kX
+Dqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/py
+UcQx1QOs2hgKNe2NAgMBAAGjHTAbMAwGA1UdEwQFMAMBAQAwCwYDVR0PBAQDAgP4
+MAsGCSqGSIb3DQEBCwOCAQEAq/zm5gIun6D8nAuEgmuXzmLoc8RorZg0f+6mPTFA
+Kld8ewwAxf1VkmEKxX1vBAh6XGtGmuFfoYp5HjcT/4w4Xsv/Tiht1vB40o23fD/Y
+URRdG1oTYErw0DX2cxcBdQMZygth5xOfW7X1Ts14Zl97l3JErgXo82KnT+S+Ohot
+GEMea4j1vnxLgZx+QB1d26BfOn58qeEad09YwS3NRj3AaFrY6VuvUPLIj/DfducW
+JLbC5ns5l8hf8Vk+oZNsKaynMUpYEZi4L6b7lCpL5bwEWoPR0ryNU3aGZNrCL3c6
+V/hTsg6CFojkRAmTzI2OLMsy51/JNMM0azRtVJ8i+WggGQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.pem.certspec
new file mode 100644
index 000000000..32bb6c248
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-bad-ku-server-eku
+subject:ee-int-bad-ku-server-eku
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-cA-FALSE-asserts-keyCertSign.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-cA-FALSE-asserts-keyCertSign.pem
new file mode 100644
index 000000000..d60e8e8fc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-cA-FALSE-asserts-keyCertSign.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBDCCAe6gAwIBAgIUH3DA15ZPfcaH0zDIfSBoT4pcTUwwCwYJKoZIhvcNAQEL
+MCsxKTAnBgNVBAMMIGludC1jQS1GQUxTRS1hc3NlcnRzLWtleUNlcnRTaWduMCIY
+DzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMC4xLDAqBgNVBAMMI2Vl
+LWludC1jQS1GQUxTRS1hc3NlcnRzLWtleUNlcnRTaWduMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFds
+JHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4
+ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25
+iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu3
+4pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42
+yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNV
+HRMEBTADAQEAMAsGA1UdDwQEAwID+DALBgkqhkiG9w0BAQsDggEBAJ6rNJFZaniL
+SWRKFdwG1vx/GPXLDl+/0VNyCVaTyYdT2tUt7A+jeJzDxv9/ELWiAhCPl77FwWOj
+xieY6CBJtQk+3Wxc9Ofc6kap5/5RtogfBsr26pfeDkKEPVFxwWTPa+tzd/Beapvg
+mew//Sp0Q3SdS0cxBQJp+u/aSEglM/Bh+l3q6sBrSGPY4/0mWQD4R/rq74sZ2TnL
+wshxO48fk1Map5kqg6L2vBNuDqr08/lrXnv1BzlgbL7UTa52BUtbPce3uegL8sIh
+5NQUW0UTIHBuBI3Ce46f5Rzeq0W7/yeDVdc6W/B/8+B5G+A2Xwlm+8AcMFsG2GFD
+K3mdAuGZW+A=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-cA-FALSE-asserts-keyCertSign.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-cA-FALSE-asserts-keyCertSign.pem.certspec
new file mode 100644
index 000000000..9e0fb65fd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-cA-FALSE-asserts-keyCertSign.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-cA-FALSE-asserts-keyCertSign
+subject:ee-int-cA-FALSE-asserts-keyCertSign
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.pem
new file mode 100644
index 000000000..10068137f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC9jCCAeCgAwIBAgIUddKEywO/Eq38I1xoGyTjg9hFzi8wCwYJKoZIhvcNAQEL
+MCQxIjAgBgNVBAMMGWludC1saW1pdGVkLWRlcHRoLWludmFsaWQwIhgPMjAxNTEx
+MjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowJzElMCMGA1UEAwwcZWUtaW50LWxp
+bWl0ZWQtZGVwdGgtaW52YWxpZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAab
+bhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmts
+Du0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhI
+H6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8
+rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kX
+Mbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEBADALBgNV
+HQ8EBAMCA/gwCwYJKoZIhvcNAQELA4IBAQAXnxXnkz6FPrXqw2XSvhy5YPEdGM5z
+qg+7A7nMLkGa3yLdsYXGKoxurlfBKfTNg7f/4vl3JHefS9dRJuSCHd/ie/mIr0Xt
+GFHoaZhl7LfEIMIe9caXgg2yWTSNCyFBh0Mxgvt1mHin0cWEV9qGiSmFiGzb8l0S
+ScNGFsBicFdnDa9I4cTGy9KNG4SAXSq5Mq8PyJ6ET6Iq7Z387T58yQtQke2/xIWB
+mnmZSnhCwBKqx5FntoIlhRWUfwSf0Z4H2UwZrU/Csv1cszRpgcYKGasRHNTg1TAj
+rIyTNmq7z/DAqdecE0js9SpD6Ht3MHSFPdhCsV+ev+H6i/IXWvxbYkgV
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.pem.certspec
new file mode 100644
index 000000000..f00b4d159
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-limited-depth-invalid
+subject:ee-int-limited-depth-invalid
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem
new file mode 100644
index 000000000..23904452a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5jCCAdCgAwIBAgIUXec5ZMQORrk2Pmi+OTo4ybN6MHowCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEWludC1saW1pdGVkLWRlcHRoMCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMB8xHTAbBgNVBAMMFGVlLWludC1saW1pdGVkLWRl
+cHRoMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62
+iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHql
+WqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosq
+Qe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+
+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8i
+b2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoY
+CjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQEAMAsGA1UdDwQEAwID+DALBgkqhkiG
+9w0BAQsDggEBAB557gwbSdb6slyiiKsSMDjGN1hfg6i77yvl4fJRYTdYrzvulc5k
+5GNCkM0FzmXeU2ZEqkvHpLRqBdtWmMeP1DoRMrwBMCDRuytrMFjNUdSfNl24ddU7
+qJ0VHzHzJsRX+4IQl3LLU46EtI9dtOkuftmZdgx+em0Ts/9cRVgT8DlzqtS7Zt6C
+ZaIg0Azle1k7eSndlzFeaEtdW7I8V0JUpBupKbFZejlccAT4Y9NBxw9QOJ7yd4kL
+P3do/lXOzc++Qh3OkJI1x69fzn5XyFuVac1tEzHS+9ODNWpFxsQtvQQ1WsjeznB2
+eWdV+jkakbbFJd733lEDoHcTa8nVLcY//GQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem.certspec
new file mode 100644
index 000000000..df85342d9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-limited-depth
+subject:ee-int-limited-depth
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.pem
new file mode 100644
index 000000000..b284989f9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5jCCAdCgAwIBAgIUBwoOpsgnbx58BjjIE/5qb5aWuEEwCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEWludC1uby1leHRlbnNpb25zMCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMB8xHTAbBgNVBAMMFGVlLWludC1uby1leHRlbnNp
+b25zMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62
+iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHql
+WqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosq
+Qe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+
+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8i
+b2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoY
+CjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQEAMAsGA1UdDwQEAwID+DALBgkqhkiG
+9w0BAQsDggEBAHPL8KLxeqX6z1G+2515iGSngTOR8CGYLjn990NWHQU8uCJPH1bu
+Q3ZaA8+E9qjVnOk79WaZ7xnD2TYEqIztDo9MbCOhsfggnF0lkoSbroVodN14Grob
+Dq+82SBC2LMtPuU1I7WR2S0svi6lAIVjTPCF6cV+2EzaGXip+R6QYpWButmtiP16
+LxtNyWqDd02C2VOSy7bX1Gk1ZFE65R97VRqVHN1ZCZQapxOySiw4+fhoBZknMX7g
+k6891BAoAiietKufOJyI3JOokTRzo8ML98grjZgAbf+/1TKTkm02ZOWC8daquuzt
+fWD4HfakwF94AsCdPjH1zIM9S3eNFsGqK5Q=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.pem.certspec
new file mode 100644
index 000000000..c5279046d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-no-extensions
+subject:ee-int-no-extensions
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.pem
new file mode 100644
index 000000000..3169edf91
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5DCCAc6gAwIBAgIUWXP9FsYmaGVIbwIJTUw0C5a0GDUwCwYJKoZIhvcNAQEL
+MBsxGTAXBgNVBAMMEGludC1uby1rdS1uby1la3UwIhgPMjAxNTExMjgwMDAwMDBa
+GA8yMDE4MDIwNTAwMDAwMFowHjEcMBoGA1UEAwwTZWUtaW50LW5vLWt1LW5vLWVr
+dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogG
+NhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqn
+RYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHu
+p3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQ
+Lzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p
+47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo1
+7Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEBADALBgNVHQ8EBAMCA/gwCwYJKoZIhvcN
+AQELA4IBAQBMW1+NpE+LWxquW2XsX+A4Dmi7Dy47Q89pX+YoWU+BIXCP6XIRSKJX
+FS3IPG3Gmd1a8SgzZxnnTCmUGDu5NtYM+vab1efNDzxjCf0JFsdjJy+sDMxh6p8f
+ffPpa8bbEjNUBC3C6z8GRWpjnDkRjco8osJkjH98GNPN3nsQhTaS6of0RLegfNQW
+PymuisSek2iW061L0z8GR8U6HB/Vh76FxMV9inZYHh0l9h1AlypYomAfnJ6l6fa8
+LLUhbqCJbPVTXIfJCgy8Mpc5vuD4OZ8/IDX/TANQsT5e3h4NLV5QjgPe0KxdLI0l
+AaiiwCz7dF2OXMEVRQe0+by4mmDjKer2
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.pem.certspec
new file mode 100644
index 000000000..92ee3cc6d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-no-ku-no-eku
+subject:ee-int-no-ku-no-eku
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.pem
new file mode 100644
index 000000000..1037a03fa
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7DCCAdagAwIBAgIUHQBwtK4YHGAX9lNXBBwc8zRAG+QwCwYJKoZIhvcNAQEL
+MB8xHTAbBgNVBAMMFGludC1uby1rdS1zZXJ2ZXItZWt1MCIYDzIwMTUxMTI4MDAw
+MDAwWhgPMjAxODAyMDUwMDAwMDBaMCIxIDAeBgNVBAMMF2VlLWludC1uby1rdS1z
+ZXJ2ZXItZWt1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
+FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
+amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
+sdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbY
+VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
+aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
+MdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQEAMAsGA1UdDwQEAwID+DAL
+BgkqhkiG9w0BAQsDggEBADyWiWIqd+ZAJLr9CTltk07maWEBfiojcboDFHdBbpuo
+9/WNyNXyQ5zNeVBx5t6VreVpFC283IIeTRpT2JRpwDMH0PrSrpaHMLuEBzitau+a
+lTujLC6oPkktRQIguqibIeqmaLc0aJfhCLpdVByQ8IA0lvn2/hSS60Lczi8/j9lf
+CBi8KR9Vbu4TE9gA2YPnX5QpUMPUVXNQFKhkNEOI4znDnWrWR+YqaxPOJJN4Y7+n
+tdR1ZAm7M4V759hEdPm3R6ailnZG1tHx+yiYlkavIz7YFqsod23KkKA2NIfms4U/
+0prBJQ31FlFJA4xIkqmv9QV37oLJY+PHT4779ess8Cg=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.pem.certspec
new file mode 100644
index 000000000..c14889671
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-no-ku-server-eku
+subject:ee-int-no-ku-server-eku
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.pem
new file mode 100644
index 000000000..5a959c953
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAcagAwIBAgIUZQzo04Yam+J7Cj0ABLKpTriWOOkwCwYJKoZIhvcNAQEL
+MBcxFTATBgNVBAMMDGludC1ub3QtYS1jYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
+MTgwMjA1MDAwMDAwWjAaMRgwFgYDVQQDDA9lZS1pbnQtbm90LWEtY2EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erk
+NUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwC
+fs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1m
+CyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTM
+HGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m
+1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGj
+HTAbMAwGA1UdEwQFMAMBAQAwCwYDVR0PBAQDAgP4MAsGCSqGSIb3DQEBCwOCAQEA
+l0yZ9gi1DSU1UCjhZqTwBBJXTq5DUgRdMB8D2XU8WTvFR419ttsp0eyEBBG2+Gk5
+IueA711TE+zRSgWePjlwRFK0ZalDZ0aRXXNGH5vrLYoigXHz+yrgAMIyxabl/RUT
+pw6wTQmt5iKN0cUICY7PgfjAiugkD5551KanWim/jnu/g1QbVCWIErawzB4kTbQj
+coWeFLL5RRL/tK1DnUWrvjynt/uBqilrqazdGYD3DwSx1r32nohK8YlvxsKzfEsR
+D8j9i/fM3HnuY9PnGh6w7Q0v8Ybx4PiXCZcTecPWjoHHDl0rGNbNOKF2BkMnuG38
+HennrEzAZa2Byk+8BKJx0g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.pem.certspec
new file mode 100644
index 000000000..a95b0dc26
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-not-a-ca
+subject:ee-int-not-a-ca
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.pem
new file mode 100644
index 000000000..97708b4b9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6jCCAdSgAwIBAgIUNdjCSw3sRlBVn+bb2BRT2/86rUwwCwYJKoZIhvcNAQEL
+MB4xHDAaBgNVBAMME2ludC12YWxpZC1rdS1uby1la3UwIhgPMjAxNTExMjgwMDAw
+MDBaGA8yMDE4MDIwNTAwMDAwMFowITEfMB0GA1UEAwwWZWUtaW50LXZhbGlkLWt1
+LW5vLWVrdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbW
+Qf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pk
+cQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHT
+AjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3
+ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jh
+s3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHV
+A6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEBADALBgNVHQ8EBAMCA/gwCwYJ
+KoZIhvcNAQELA4IBAQAJUHbGqWQWF/nXvq/x5V8hzM18GvrGoAToXcssHCpGDUL1
+76IQBEn5LwIdv/x+/vtWpIK+9n8sDeOwetba732nIHoMqVSVTSUa6VCc5arvXYUs
+FJ7fsAzJII21roEXtahd4cdJq9r3UUewERZvFjxnHU+FF43R8DsLZqGie97LQYAL
+DhJXWVJENp5RgQv0w7wWduqZNhnocKSfpwY4vy/4x4VRdS/4P0nv/qOYPO1JAwGg
+3xggbVGArL07dPBcV+/dVFYPv4LLAlaSsgcp3QUX4GS2RWnFuxa2N3oV2VEi6AtL
+qYAjzsVTlZajWS0bI3YDPoF1fA5D5I2UjLaqE+Xx
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.pem.certspec
new file mode 100644
index 000000000..89a66b9f9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-valid-ku-no-eku
+subject:ee-int-valid-ku-no-eku
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.pem
new file mode 100644
index 000000000..ba523f64d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8jCCAdygAwIBAgIUSWvWguZEz9NZBXX1ZCoChzAjiikwCwYJKoZIhvcNAQEL
+MCIxIDAeBgNVBAMMF2ludC12YWxpZC1rdS1zZXJ2ZXItZWt1MCIYDzIwMTUxMTI4
+MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMCUxIzAhBgNVBAMMGmVlLWludC12YWxp
+ZC1rdS1zZXJ2ZXItZWt1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+uohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGoby
+a+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWC
+D/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfT
+iEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXT
+Ce+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+
+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQEAMAsGA1UdDwQE
+AwID+DALBgkqhkiG9w0BAQsDggEBAFzS8Zf5e20Y3lpfm8vtfp6tYUE/Jafc7eXM
+OzIazcBDB9hpiLPeeliw1nVhVnN+C/cdVDtVkh7jfMzmq0bEv/fFTZLH0UcEXVKt
+AhV0P98PKxPcB8G0Q4AL0DL+hXy0vomGPWhnNdj7do/a2WlZUyFxnDtUOMwYkYkp
+V8ii4NOPGWK+5Oc6j/MpeTWeP5HtfYs4b1nuGW4dbklY/CjekRHWmWSwTVnQelAF
+bn9Cs1bXa+KntGX9iE8hK+4WLNM15/Ch9RRNbL3HGfntakHsjcqR8GL1cF3GrZkL
+L5hUuX6fzS04s6Lrqxnb5+KMGgEWgdbF5+bmPS0oAP4eAjrzqvs=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.pem.certspec
new file mode 100644
index 000000000..43e83a336
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int-valid-ku-server-eku
+subject:ee-int-valid-ku-server-eku
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.pem
new file mode 100644
index 000000000..87c9e7783
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1DCCAb6gAwIBAgIUYS3pOmOM6SjbT2+LSutSEZcu/T0wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBwxGjAYBgNVBAMMEWludC1iYWQta3Utbm8tZWt1MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFds
+JHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4
+ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25
+iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu3
+4pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42
+yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNV
+HRMEBTADAQH/MAsGA1UdDwQEAwIB+jALBgkqhkiG9w0BAQsDggEBAClZ/nt4DWBg
+s+370ym6UwtUi/rCqg2XztXbRPrnIZ3EwDCM4IEUnIhDb8mBu6yoT+GETyGGzINq
+XAue37I78nQoKsGiBX5itGGI3XvAuP0a5c/sYmHZD4uqjgRypGo6XLlM2ZZU9B1g
+vrY7oH9knLQzf9kcpo5IXQkzZbEy5KTmiyqHX4bSXZwHATDmXRFZNT4ojUV/8ozD
+KWgBWJBIiA1EpbWj1VoMTwWGp2UkPOyXTpmMe6nma+Swn4HAlYJlImwEtdBLZsIx
+vPRseb9zO3hLyeVMd3uHeOtgFcBWVx0vkX9taoGEhfds5i3m1vYMi1QD3cgmJTJO
+bTqfFO0+5Xo=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.pem.certspec
new file mode 100644
index 000000000..f6525449b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-bad-ku-no-eku
+extension:basicConstraints:cA,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.pem
new file mode 100644
index 000000000..f2550274a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC9zCCAeGgAwIBAgIUV7jmxQiYVnYXubm3dfP58HTCLAYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMCAxHjAcBgNVBAMMFWludC1iYWQta3Utc2VydmVyLWVrdTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs
+9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8
+HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7Ak
+kqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJet
+lmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2r
+kQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaM8MDow
+DAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAfowHQYDVR0lBBYwFAYIKwYBBQUHAwEG
+CCsGAQUFBwMCMAsGCSqGSIb3DQEBCwOCAQEAiWJSUz5NGSIGIBxnft0wa7D0Yu9K
+qx1vw4JfBnr2RFxb7Z4uLM4dQcyfqgvyEQks4yIDv/ygLZ4jUDoorVodnh/vEmeo
+HRUiCRFbTxhZjlepotgvwO8BjuPtRvswziVSEdglUYeWKirYuI8b3uaRnukoxP1c
+Y1yHz+khiu7gvF4I0qKVbZAPIGlveypPoliAVls1V80pDRYRJZQQGDkfr4Pt7U8j
+tWWD1N7LeTctyOnjJa5jBGruhzncRXv2yrgmQSxeHWvckdp8dbsp7jA8sFpvr8IB
+8APo5I/zKt76xZAes1AhRcsSQ+f25tAoLfERqCY+fQXs/ANe8VIOLZSNmw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.pem.certspec
new file mode 100644
index 000000000..2d324508d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-bad-ku-server-eku
+extension:basicConstraints:cA,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,cRLSign
+extension:extKeyUsage:serverAuth,clientAuth
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-cA-FALSE-asserts-keyCertSign.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-cA-FALSE-asserts-keyCertSign.pem
new file mode 100644
index 000000000..be9eeba00
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-cA-FALSE-asserts-keyCertSign.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4zCCAc2gAwIBAgIUfwtPS7BE2BHyTLJHGoXUsWPKb4IwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMCsxKTAnBgNVBAMMIGludC1jQS1GQUxTRS1hc3NlcnRzLWtleUNlcnRTaWdu
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2
+ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdF
+h/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6n
+cOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAv
+OnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2nj
+tIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXt
+jQIDAQABox0wGzAMBgNVHRMEBTADAQEAMAsGA1UdDwQEAwIB/jALBgkqhkiG9w0B
+AQsDggEBAKFcTDGv9WuNnIkWlpJt2zy0YxKGkRvDUtmQxx1pjUZgrYDAP/e24nzb
+IDYovT6Yy/2OUQCRKyrM8z36x8nhoS5Ulqrybbsn0qvR9pbydxNk9NFvj7HGiXOA
+6qbMCxu+ta5TIU8zA8Sz+6SmRcFS0ZtZdif9HPd4ALh4M9PyvUI/209HACc6FRY4
+Yl+A6EII5zasC/lQ51IHDJQ97JpLNUHD7yJ84rceGeqBh9VcV1rSpb2EQ4tb7884
+YHdeJ8be3Yw9Tomj0nOCOkbpzRgjrYqOGfnOrclZNODwRrDRJmiaa7pix6EFgech
+PQ6c9hZQB59oRzFVzr/+YK6e7NbbE1Q=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-cA-FALSE-asserts-keyCertSign.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-cA-FALSE-asserts-keyCertSign.pem.certspec
new file mode 100644
index 000000000..39785d8a4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-cA-FALSE-asserts-keyCertSign.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-cA-FALSE-asserts-keyCertSign
+extension:basicConstraints:,
+extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.pem
new file mode 100644
index 000000000..a7e980c85
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3jCCAcigAwIBAgIUC8p0CGJ9TpHnf4VF+SR1JBOadzEwCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEWludC1saW1pdGVkLWRlcHRoMCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMCQxIjAgBgNVBAMMGWludC1saW1pdGVkLWRlcHRo
+LWludmFsaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W
+1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtq
+ZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx
+0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthV
+t2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo
+4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx
+1QOs2hgKNe2NAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wCwYJKoZIhvcNAQELA4IB
+AQBiWZ2hrIIfeEAdXMatxKUw7JVb+YC5WZNiSMBEAxZHvsRrgxNnkruZfgdLvZ6c
+SSwE3ZelLCALkursSkYmJVbOXbMjo0Uxi3T2PPkU2sc7GgkGOeDnJ0EosZuOSi3R
+O95t+bqjHRXNzzdCbYELWiOlx1LwEXvoiBA/Ey/KYaNMflPnFZej9Xf9QMoP3/QF
+IOqP4DABiyz1zQmUDZMSB/63T0MV9QySIXYzumtrWSbxDdgfK7HDy7xYyZDLYchA
+NhkQT0ze6SOkplit4UDIUneK7r82jAkc94I+nyTr36oC4s23/NJh4OS8bUUkZmY+
+rjzdzQQ/Qn8DdAD3jhmvwSjF
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.pem.certspec
new file mode 100644
index 000000000..9fdb2a248
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int-limited-depth
+subject:int-limited-depth-invalid
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.pem
new file mode 100644
index 000000000..d8e06a572
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyjCCAbSgAwIBAgIUQ73/9r+OdKC4qNSYd5RxWvXEYiYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBwxGjAYBgNVBAMMEWludC1saW1pdGVkLWRlcHRoMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFds
+JHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4
+ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25
+iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu3
+4pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42
+yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxMwETAPBgNV
+HRMECDAGAQH/AgEAMAsGCSqGSIb3DQEBCwOCAQEAiBj74DBM3fQRjWjEs5k0+JDi
+8+sL+nzQjRxEULR9KoMPhKbI6htoZIj/Otbtay47Cl95T1QGBz7sJF0mOhM4Ubml
+lJ0BIV4rBxaLAN/3NxLZ1ATJVFAUTnJrA0/AkPPNNjq2RBU/dFlLUhZhXJS800Gx
+SS1OERNSvXMkOq13ZZ1hiVdrUBmilCtS5cxXCeFw2PeKQwWunKmJZjHInrteJHYB
+L5XkEfj4cP2hmQo/ZtviarLFQH/HSd8kfR7/IgPt664znUo7aFUJ5Hki7jNCjxBq
+tdDWPFT+TUWeWWbYzcVOk7PKT/aKLNRF/MEFBQMBH9ygUlMwVovwU7IKZAe/1g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.pem.certspec
new file mode 100644
index 000000000..64f54b044
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:int-limited-depth
+extension:basicConstraints:cA,0
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.pem
new file mode 100644
index 000000000..76930d04d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtTCCAZ+gAwIBAgIUdSMRoahH5nOZT7+cJre+BOvTLh4wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBwxGjAYBgNVBAMMEWludC1uby1leHRlbnNpb25zMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFds
+JHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4
+ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25
+iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu3
+4pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42
+yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3
+DQEBCwOCAQEAr3GUaY4QbqbKhXNArKMycwIPVYKzOzppwbfwbI5un65xI8e9GSDk
+qDYU6aV6c4ruqAY4Kzs/T/aHmJpTIusL+uUr8BfWVHUef+psJgSuBFKMnNcgTyO6
+XlBn9/PnjTYgy6jfbiXVY8OZe7WAIVhVY0YP9jOaL3f3/GjYVW/iWM5XEhW8LSQ5
+RekRVRwdDvdOXQMQfeWTc6gH6FrtUcxrU6+axA8rzIPE5HuUwE7BCyG/SRI49mXw
+285FxNKrNhX9Hb6O19OqAc4+qI7Tdqtgb6+BXer01tXb079IpzxavZ5VhaskBNpK
+Br1uFqwzrT231bCjBdDuxpPlALZ+EQQG7Q==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.pem.certspec
new file mode 100644
index 000000000..c99626bd5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.pem.certspec
@@ -0,0 +1,2 @@
+issuer:ca
+subject:int-no-extensions
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.pem
new file mode 100644
index 000000000..53437b1de
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxjCCAbCgAwIBAgIUH0pq51lOBUG6WhqGNAD+IlHKyxswCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBsxGTAXBgNVBAMMEGludC1uby1rdS1uby1la3UwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
+e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
+KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
+YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
+lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
+HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjEDAOMAwGA1Ud
+EwQFMAMBAf8wCwYJKoZIhvcNAQELA4IBAQBaV/7LFkIry4xDVcci1ssw5D9mfgqR
+6qp1YX+zKsiNVmiCQnBJPrQmGubZptuAKS7QdviBHxtfKm/gMCC2X9fDt9v5DAfp
+UtPeWUc1BCaJyEPtHQwcaCT9WkwxlMzMzJEitoxSo6Hug4xt2Qib8Ou5+inLfVqR
+dsb5rZav6c2SRU0patnr8+WWP6OqWqcwFn6H517KpyRP0XchCPlgbGC2gsmNct4o
+9BWhP2bpjDp9F2xelPgSe5Uo/ti/Q+Y2KrEQElmI6Uxnvj235BhPv0+KDFn/1vqr
+25RQcEoZOV6dYlBIzVP1AzkfXVUW3g5fN6PUdj2RmsktKd7rVfSUvsNw
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.pem.certspec
new file mode 100644
index 000000000..306a218db
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:int-no-ku-no-eku
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.pem
new file mode 100644
index 000000000..6cd516927
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6TCCAdOgAwIBAgIUTRygOfB3FLI5SJlQo+2t4dEYwkYwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMB8xHTAbBgNVBAMMFGludC1uby1rdS1zZXJ2ZXItZWt1MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoy8wLTAM
+BgNVHRMEBTADAQH/MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjALBgkq
+hkiG9w0BAQsDggEBAFnLVXAuHBhxNxmvn1TMA6kLSosQGei12Xd8wA6iuRDrD1qj
+nIZlaIJkZncxDocWo1a2vISQPyNe/dBVGC1HpGGUXSmDswQ5h6P0837buhsW2v9m
+/oYvcZwqjO+qvIpgTCN71QR7aPlvv4kgX/fJ6goGK7IPovcYX0U1LmZGZBIaqoCR
+8rG+orm8Aek+rqfKMV0fhMLFMiRHO/ly/ZZUfcd4M4ObW1l/SB4EKLNU4a3jH/ob
+CHrIu1umvn4SXUJBcEV3a+WLIuGexrLYFzkOV8doA/KAoE4xaArNKJFfCtgzzcRq
+uCqf96q8f5eLo4B5f00+Lqmxj72/8heCTunv/TA=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.pem.certspec
new file mode 100644
index 000000000..1482b627c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-no-ku-server-eku
+extension:basicConstraints:cA,
+extension:extKeyUsage:serverAuth,clientAuth
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.pem
new file mode 100644
index 000000000..3be0c2916
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaygAwIBAgIUXw5voQbjEKOz94iKt4vgWrxBWDMwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMBcxFTATBgNVBAMMDGludC1ub3QtYS1jYTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMQMA4wDAYDVR0TBAUw
+AwEBADALBgkqhkiG9w0BAQsDggEBAAcZ3izf+oLdjuYRPuBerrZMZZVacWp0mPgV
+iPBcEiJMnpExTolvwGRR9rUfbGZcoaxkr+vMv1n1X4ORmXQmKEkzbsGykwNJ72x8
+PayxV1lpDkL0LAWL16jaUhbFIu5D8t0AfissJ/0bC+xdKQqZdAlDJaCz5p5247Gw
+Um0vS10JAI2ykVMkZwgOPvV9YYIiZG7voBBlCrY32M9f5fTi75J4DGGCt0VSdkf0
+XAe6kM84BdQ0lDyitV5YaLAfahWKb6VPzcoeuwlLodXa1eoh8WBPQMmpn/eT9bcg
+W2BTrEMf/JpL+r36j5UsSzSNFktq5/RfpnaKX7mhw4IR3T19khw=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.pem.certspec
new file mode 100644
index 000000000..3161680b1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.pem.certspec
@@ -0,0 +1,3 @@
+issuer:ca
+subject:int-not-a-ca
+extension:basicConstraints:,
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.pem
new file mode 100644
index 000000000..84cd61105
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1jCCAcCgAwIBAgIUWQyWw8pJuxrZYnP/bZs+HBxFt0swCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMB4xHDAaBgNVBAMME2ludC12YWxpZC1rdS1uby1la3UwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVo
+V2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p
+0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKk
+fbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZh
+W7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EI
+TjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAwG
+A1UdEwQFMAMBAf8wCwYDVR0PBAQDAgIEMAsGCSqGSIb3DQEBCwOCAQEAaqysdeSM
+/kLPK1LgrOP5GsclIs9Ss0gB+sgSCWxRkrcs6JPxIblQjI0CYkWNVbtS6PSoa2TZ
+aRH3/mLKrdUEWrimZrapDkmwO2RmkS+oHEjxOIL3kla1khKf8IcmZYIS4OKXr+KT
+wJKlh6kjt2o40hMUA/jRVN52HCCIsZiAaYVqyQ9avyDf12zdQP3PBEe9pbwNbKme
+CDi7YtWDBG1uvSGrC6APzzXJe0GY/grLt9qOig6Kb2hmxdKT141ekjDX9Ju9P53J
+tLoQqgH56rMTfJfI87fWVyq0FGpAqdJbE8XnDI1n9S/XoSmDDifYt/GPo7vtGbX3
+KEXKaOqalzDy3w==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.pem.certspec
new file mode 100644
index 000000000..d7f9b0387
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int-valid-ku-no-eku
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.pem b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.pem
new file mode 100644
index 000000000..34818f172
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAeOgAwIBAgIUIwJxO+LBUmT20OYpAC6REFDuQ0swCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMCIxIDAeBgNVBAMMF2ludC12YWxpZC1rdS1zZXJ2ZXItZWt1MIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVK
+tOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7N
+Q/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39Zgsr
+sCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxs
+l62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYl
+nauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozww
+OjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcD
+AQYIKwYBBQUHAwIwCwYJKoZIhvcNAQELA4IBAQAP6RTfp/yTGvXtgPj34EZAptB4
+EyMT+ozD9EEKHXvHMfavy+nn21WiCuDzjp7r7bic/H8UEYUo3h+8M11hou7Abu4R
+1PtefBdT9NLndrkSD3XFqpAm+t5EmfXhMxIrYidPcXI1jOEjRCYDND41jZ5wQ41A
+Mlbe9sUAFV/gWFO/HCn1VLE9bzjelLJWMszAgraodyoDBQocUcNcA/E/iiTBofz2
+S6FncJfNFYSdXpfytk4apKpSitg6L+g5ELso6INK5Vo0okNaY8wLxKpCpn3zz3C6
+o6gGidSOdq8Vpdi8X93+JTuW/sNazHnYia3+uP8NxUbsh/zqRVEOOOJU2RQq
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.pem.certspec b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.pem.certspec
new file mode 100644
index 000000000..84314bfa4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:int-valid-ku-server-eku
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign
+extension:extKeyUsage:serverAuth,clientAuth
diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/moz.build b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/moz.build
new file mode 100644
index 000000000..59f5749a2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ca.pem',
+# 'ee-int-bad-ku-no-eku.pem',
+# 'ee-int-bad-ku-server-eku.pem',
+# 'ee-int-cA-FALSE-asserts-keyCertSign.pem',
+# 'ee-int-limited-depth.pem',
+# 'ee-int-limited-depth-invalid.pem',
+# 'ee-int-no-extensions.pem',
+# 'ee-int-no-ku-no-eku.pem',
+# 'ee-int-no-ku-server-eku.pem',
+# 'ee-int-not-a-ca.pem',
+# 'ee-int-valid-ku-no-eku.pem',
+# 'ee-int-valid-ku-server-eku.pem',
+# 'int-bad-ku-no-eku.pem',
+# 'int-bad-ku-server-eku.pem',
+# 'int-cA-FALSE-asserts-keyCertSign.pem',
+# 'int-limited-depth.pem',
+# 'int-limited-depth-invalid.pem',
+# 'int-no-extensions.pem',
+# 'int-no-ku-no-eku.pem',
+# 'int-no-ku-server-eku.pem',
+# 'int-not-a-ca.pem',
+# 'int-valid-ku-no-eku.pem',
+# 'int-valid-ku-server-eku.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_js_cert_override_service.js b/security/manager/ssl/tests/unit/test_js_cert_override_service.js
new file mode 100644
index 000000000..d085f0242
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_js_cert_override_service.js
@@ -0,0 +1,56 @@
+/* -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// This test ensures that nsICertOverrideService can be implemented in JS.
+// It does so by creating and registering a mock implementation that indicates
+// a specific host ("expired.example.com") has a matching override (ERROR_TIME).
+// Connections to that host should succeed.
+
+// Mock implementation of nsICertOverrideService
+const gCertOverrideService = {
+ rememberValidityOverride() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ rememberTemporaryValidityOverrideUsingFingerprint() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ hasMatchingOverride(hostname, port, cert, overrideBits, isTemporary) {
+ Assert.equal(hostname, "expired.example.com",
+ "hasMatchingOverride: hostname should be expired.example.com");
+ overrideBits.value = Ci.nsICertOverrideService.ERROR_TIME;
+ isTemporary.value = false;
+ return true;
+ },
+
+ getValidityOverride() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ clearValidityOverride() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ isCertUsedForOverrides() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsICertOverrideService])
+};
+
+function run_test() {
+ do_get_profile();
+ let certOverrideServiceCID =
+ MockRegistrar.register("@mozilla.org/security/certoverride;1",
+ gCertOverrideService);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(certOverrideServiceCID);
+ });
+ add_tls_server_setup("BadCertServer", "bad_certs");
+ add_connection_test("expired.example.com", PRErrorCodeSuccess);
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_keysize.js b/security/manager/ssl/tests/unit/test_keysize.js
new file mode 100644
index 000000000..3a8e28e87
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize.js
@@ -0,0 +1,127 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Checks that RSA certs with key sizes below 1024 bits are rejected.
+// Checks that ECC certs using curves other than the NIST P-256, P-384 or P-521
+// curves are rejected.
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+/**
+ * Tests a cert chain.
+ *
+ * @param {String} rootKeyType
+ * The key type of the root certificate, or the name of an elliptic
+ * curve, as output by the 'openssl ecparam -list_curves' command.
+ * @param {Number} rootKeySize
+ * @param {String} intKeyType
+ * @param {Number} intKeySize
+ * @param {String} eeKeyType
+ * @param {Number} eeKeySize
+ * @param {PRErrorCode} eeExpectedError
+ */
+function checkChain(rootKeyType, rootKeySize, intKeyType, intKeySize,
+ eeKeyType, eeKeySize, eeExpectedError) {
+ let rootName = "root_" + rootKeyType + "_" + rootKeySize;
+ let intName = "int_" + intKeyType + "_" + intKeySize;
+ let eeName = "ee_" + eeKeyType + "_" + eeKeySize;
+
+ let intFullName = intName + "-" + rootName;
+ let eeFullName = eeName + "-" + intName + "-" + rootName;
+
+ addCertFromFile(certdb, `test_keysize/${rootName}.pem`, "CTu,CTu,CTu");
+ addCertFromFile(certdb, `test_keysize/${intFullName}.pem`, ",,");
+ let eeCert = constructCertFromFile(`test_keysize/${eeFullName}.pem`);
+
+ do_print("cert o=" + eeCert.organization);
+ do_print("cert issuer o=" + eeCert.issuerOrganization);
+ checkCertErrorGeneric(certdb, eeCert, eeExpectedError,
+ certificateUsageSSLServer);
+}
+
+/**
+ * Tests various RSA chains.
+ *
+ * @param {Number} inadequateKeySize
+ * @param {Number} adequateKeySize
+ */
+function checkRSAChains(inadequateKeySize, adequateKeySize) {
+ // Chain with certs that have adequate sizes for DV
+ checkChain("rsa", adequateKeySize,
+ "rsa", adequateKeySize,
+ "rsa", adequateKeySize,
+ PRErrorCodeSuccess);
+
+ // Chain with a root cert that has an inadequate size for DV
+ checkChain("rsa", inadequateKeySize,
+ "rsa", adequateKeySize,
+ "rsa", adequateKeySize,
+ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+
+ // Chain with an intermediate cert that has an inadequate size for DV
+ checkChain("rsa", adequateKeySize,
+ "rsa", inadequateKeySize,
+ "rsa", adequateKeySize,
+ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+
+ // Chain with an end entity cert that has an inadequate size for DV
+ checkChain("rsa", adequateKeySize,
+ "rsa", adequateKeySize,
+ "rsa", inadequateKeySize,
+ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+}
+
+function checkECCChains() {
+ checkChain("secp256r1", 256,
+ "secp384r1", 384,
+ "secp521r1", 521,
+ PRErrorCodeSuccess);
+ checkChain("secp256r1", 256,
+ "secp224r1", 224,
+ "secp256r1", 256,
+ SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ checkChain("secp256r1", 256,
+ "secp256r1", 256,
+ "secp224r1", 224,
+ SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ checkChain("secp224r1", 224,
+ "secp256r1", 256,
+ "secp256r1", 256,
+ SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ checkChain("secp256r1", 256,
+ "secp256r1", 256,
+ "secp256k1", 256,
+ SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ checkChain("secp256k1", 256,
+ "secp256r1", 256,
+ "secp256r1", 256,
+ SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+}
+
+function checkCombinationChains() {
+ checkChain("rsa", 2048,
+ "secp256r1", 256,
+ "secp384r1", 384,
+ PRErrorCodeSuccess);
+ checkChain("rsa", 2048,
+ "secp256r1", 256,
+ "secp224r1", 224,
+ SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ checkChain("secp256r1", 256,
+ "rsa", 1016,
+ "secp256r1", 256,
+ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE);
+}
+
+function run_test() {
+ checkRSAChains(1016, 1024);
+ checkECCChains();
+ checkCombinationChains();
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem
new file mode 100644
index 000000000..020e46819
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB3DCCAUegAwIBAgIUeW3ngaE/CNhaakp8m4ETFPagv6IwCwYJKoZIhvcNAQEL
+MCUxIzAhBgNVBAMMGmludF9yc2FfMTAyNC1yb290X3JzYV8xMDI0MCIYDzIwMTUx
+MTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMDExLzAtBgNVBAMMJmVlX3JzYV8x
+MDE2LWludF9yc2FfMTAyNC1yb290X3JzYV8xMDI0MIGeMA0GCSqGSIb3DQEBAQUA
+A4GMADCBiAKBgADSm7EvuE/dzSmzpRnLZsQ7jY+L5UW6eThM5mPtA991mRYA65IH
+kNJTDOzlRNuZpx8FiWo+0gcWVTSqmQV+R8R+O8ga2m+h4S43JotQRqVSaPna18y0
+hdgaLhnVDU8LaFSsr2175p2aCDE24Vr6j1PByMhPxgdyed0OVdc2mlvdAgMBAAEw
+CwYJKoZIhvcNAQELA4GBACY8sq6EZJpNutOwEli+1sAFY+TEv/vKOUx0YVWOAPDG
+Fz/E7FlEzWHoCEgUTkloECJcgZnrJgp6at4X/Bpn6eS3aqDgYqCg/Ec1J3/sroiz
+GToe0ts9SsOyb+GEQ1+7AGSDc15AQQ1F6yVSLPtlCTvVy0wGl5hKWESb7LRc//6W
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem.certspec
new file mode 100644
index 000000000..7b86ef786
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int_rsa_1024-root_rsa_1024
+subject:ee_rsa_1016-int_rsa_1024-root_rsa_1024
+issuerKey:rsa1024
+subjectKey:rsa1016
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem
new file mode 100644
index 000000000..7c36379fe
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB3DCCAUigAwIBAgIUN5wiZ+RfSwcvb1a7l8ucBCzFcnAwCwYJKoZIhvcNAQEL
+MCUxIzAhBgNVBAMMGmludF9yc2FfMTAxNi1yb290X3JzYV8xMDI0MCIYDzIwMTUx
+MTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMDExLzAtBgNVBAMMJmVlX3JzYV8x
+MDI0LWludF9yc2FfMTAxNi1yb290X3JzYV8xMDI0MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDTqXRAEB66jF35UD5vk161L/6z6+nQ3Fys4m+XPKlMvA2cMdZs
+DAE7zpyC0NSAMo3wX7a815kKUxLdrmFSrW7mHIwb3YZjxovTYiSpiCrnjon1Vt/b
+5vUdphEsv8J8ikkza0Gv23UyG1KySnNE0TSOZGNRpVHHVxzNoLj+NfYadQIDAQAB
+MAsGCSqGSIb3DQEBCwOBgAB5LmLQhlHBqC31K1lP4+/DdPMeiYY5lN6sIyEhwHOU
+nRw6AFk6jt2MA6zOVTsK4xcPkRUiB+4hoUrxnwdup2Tv5x594LIl58dDgG6U0+gS
+mMmuOhxkhbdOJZDbHU2OrfS7540M5tPIMWxrG0JsUgQqHryVMxx/B7x+dQaIujjV
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem.certspec
new file mode 100644
index 000000000..326d665dc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int_rsa_1016-root_rsa_1024
+subject:ee_rsa_1024-int_rsa_1016-root_rsa_1024
+issuerKey:rsa1016
+subjectKey:rsa1024
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem
new file mode 100644
index 000000000..6020cf3ae
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICQjCCAa2gAwIBAgIUD/XcUH+cenVky6AuBp4QqnIEB3QwCwYJKoZIhvcNAQEL
+MCUxIzAhBgNVBAMMGmludF9yc2FfMTAyNC1yb290X3JzYV8xMDE2MCIYDzIwMTUx
+MTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMBIxEDAOBgNVBAMMB3JzYTEwMjQw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAEwCwYJKoZIhvcNAQELA4GBAJZyjN7rSepxVDNQRLWwdmf6McLXL4ihB+ib
+jqCOEHOLEoiB18juTh6bsB+Y5BTHAWWmqBOEcRX88R+ICTuHDbh76Y1yWsFw/4Xi
+is+yTvZkmtNEzEM4GWXRRBq0WuWFWMGAeFOPXNhs1UDYvrcpRd6byjohkFrj0zQc
+LtWo6gR0
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem.certspec
new file mode 100644
index 000000000..c44a089ed
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int_rsa_1024-root_rsa_1016
+subject:ee_rsa_1024-int_rsa_1024-root_rsa_1016
+issuerKey:rsa1024
+subject:rsa1024
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem
new file mode 100644
index 000000000..020b749b0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB3TCCAUigAwIBAgIUNzU3VQCyiT+NrgvVMkBnUSgebnYwCwYJKoZIhvcNAQEL
+MCUxIzAhBgNVBAMMGmludF9yc2FfMTAyNC1yb290X3JzYV8xMDI0MCIYDzIwMTUx
+MTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMDExLzAtBgNVBAMMJmVlX3JzYV8x
+MDI0LWludF9yc2FfMTAyNC1yb290X3JzYV8xMDI0MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDTqXRAEB66jF35UD5vk161L/6z6+nQ3Fys4m+XPKlMvA2cMdZs
+DAE7zpyC0NSAMo3wX7a815kKUxLdrmFSrW7mHIwb3YZjxovTYiSpiCrnjon1Vt/b
+5vUdphEsv8J8ikkza0Gv23UyG1KySnNE0TSOZGNRpVHHVxzNoLj+NfYadQIDAQAB
+MAsGCSqGSIb3DQEBCwOBgQCUvRKlj6hAjRSMr6KjNfSIiDErCt9lkWT+Xoknz+OW
+VACuTjBO5xOLabaYhGxHDlaDGw6hZOvF29e8cid5eEogNiSBtCgjh34w1mHQ2LVf
+SuG7GFRQLvzOHUQqgzftnVzw/ak+SVgnh9UyzHVv8CR9ljB1jNu7AAFB4s1IXlC7
++w==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem.certspec
new file mode 100644
index 000000000..a6ee408ec
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int_rsa_1024-root_rsa_1024
+subject:ee_rsa_1024-int_rsa_1024-root_rsa_1024
+issuerKey:rsa1024
+subjectKey:rsa1024
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem
new file mode 100644
index 000000000..18adf9859
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBXTCCAQOgAwIBAgIUIY9dtWlq0GcuLIMvwadTnAygONIwCgYIKoZIzj0EAwIw
+KjEoMCYGA1UEAwwfaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9yc2FfMjA0ODAiGA8y
+MDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjA7MTkwNwYDVQQDDDBlZV9z
+ZWNwMjI0cjFfMjI0LWludF9zZWNwMjU2cjFfMjU2LXJvb3RfcnNhXzIwNDgwTTAQ
+BgcqhkjOPQIBBgUrgQQAIQM5AARmjXLMpv1qGzVXtTZhBNhECOy2N/COjIa7/4LM
+6I8AZtevY8Mpi6N3NIoSArA7N/1rH/QVqjEeMAoGCCqGSM49BAMCA0gAMEUCIFx1
+UZ8TEVDNXYreIKO8BjCR/7JzdV8xZOz9y0KACnDmAiEA8WmMKFZiEqHpzhBMF56W
+ohttkzkw5Pim1A3Pg+M+EgQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem.certspec
new file mode 100644
index 000000000..87d2f6733
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int_secp256r1_256-root_rsa_2048
+subject:ee_secp224r1_224-int_secp256r1_256-root_rsa_2048
+issuerKey:secp256r1
+subjectKey:secp224r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem
new file mode 100644
index 000000000..04b630f61
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBZjCCAQ2gAwIBAgIUceEyhHgm6jvAxRjgPB7TZEUD6+cwCgYIKoZIzj0EAwIw
+LzEtMCsGA1UEAwwkaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9zZWNwMjU2cjFfMjU2
+MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMEAxPjA8BgNVBAMM
+NWVlX3NlY3AyMjRyMV8yMjQtaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9zZWNwMjU2
+cjFfMjU2ME0wEAYHKoZIzj0CAQYFK4EEACEDOQAEZo1yzKb9ahs1V7U2YQTYRAjs
+tjfwjoyGu/+CzOiPAGbXr2PDKYujdzSKEgKwOzf9ax/0FaoxHjAKBggqhkjOPQQD
+AgNHADBEAiBcdVGfExFQzV2K3iCjvAYwkf+yc3VfMWTs/ctCgApw5gIgSy0oqg4P
+75DkJCciEqnZbDsjC82PJPWEC0VfaspSdcs=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..1aadce076
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int_secp256r1_256-root_secp256r1_256
+subject:ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256
+issuerKey:secp256r1
+subjectKey:secp224r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem
new file mode 100644
index 000000000..b90be0ce3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbzCCARagAwIBAgIUUwzZV7XszL/aVykB1Ozw35aJd3YwCgYIKoZIzj0EAwIw
+LzEtMCsGA1UEAwwkaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9zZWNwMjU2cjFfMjU2
+MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMEAxPjA8BgNVBAMM
+NWVlX3NlY3AyNTZrMV8yNTYtaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9zZWNwMjU2
+cjFfMjU2MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAENe58conY/veoav5dpm2Lwuu2
+qFQ/0v6tCJ9FznrND6ZDgqlQDEHa13D/1LURv0tJLrEjiADDLE92xzo/MpTnxTAK
+BggqhkjOPQQDAgNHADBEAiBcdVGfExFQzV2K3iCjvAYwkf+yc3VfMWTs/ctCgApw
+5gIgVFxK6Odv9UpwqHXdT8lB+8UfLtaQlfo2r343SK9X9sI=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..ba999e8f1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int_secp256r1_256-root_secp256r1_256
+subject:ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256
+issuerKey:secp256r1
+subjectKey:secp256k1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem
new file mode 100644
index 000000000..024ca3e4c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBpDCCARCgAwIBAgIUabB6dOZPUb0d2XR3LNB3Cd/AuwgwCwYJKoZIhvcNAQEL
+MCoxKDAmBgNVBAMMH2ludF9yc2FfMTAxNi1yb290X3NlY3AyNTZyMV8yNTYwIhgP
+MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowOzE5MDcGA1UEAwwwZWVf
+c2VjcDI1NnIxXzI1Ni1pbnRfcnNhXzEwMTYtcm9vdF9zZWNwMjU2cjFfMjU2MFkw
+EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET7+7u2Hg+PmxpgpZrIcE4uwFC0I+PPcu
+kj8sT3lLRVwqadIzRWw2xBGdBwbgDu3I0ZOQ15kbey0HowTqoEqmwDALBgkqhkiG
+9w0BAQsDgYAApXG0yYRLpX60cYFkYhTIEc05prxaID/hQeDNxfCqaBpH2SojlDX1
+rud/Iu3siUy4FUQK00Dfl8mYwo88xah/uCQnmmVuC8BAdnYYQ3Qnf+wM3NWeXKW4
+8+uk/PnloAlOXBaNUeUeaq0ohQctWGuutT0oJSeDv3GfkpJJ0dkGTg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..1e2e0a375
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem.certspec
@@ -0,0 +1,4 @@
+issuer:int_rsa_1016-root_secp256r1_256
+subject:ee_secp256r1_256-int_rsa_1016-root_secp256r1_256
+issuerKey:rsa1016
+subjectKey:secp256r1
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem
new file mode 100644
index 000000000..f8e48209c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBazCCARmgAwIBAgIUP9OfNyc0D57T6dGzurRvtWWkKtswCgYIKoZIzj0EAwIw
+LzEtMCsGA1UEAwwkaW50X3NlY3AyMjRyMV8yMjQtcm9vdF9zZWNwMjU2cjFfMjU2
+MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMEAxPjA8BgNVBAMM
+NWVlX3NlY3AyNTZyMV8yNTYtaW50X3NlY3AyMjRyMV8yMjQtcm9vdF9zZWNwMjU2
+cjFfMjU2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET7+7u2Hg+PmxpgpZrIcE
+4uwFC0I+PPcukj8sT3lLRVwqadIzRWw2xBGdBwbgDu3I0ZOQ15kbey0HowTqoEqm
+wDAKBggqhkjOPQQDAgNAADA9Ah0Amjxv8EbbcPJV9S/WmFIc1y28BSBjT5W2S7JS
+VAIcAlACd6sAyqbCmlQSNaKuHGiqQ2yNdWctbBudVg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..bd7bc770c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int_secp224r1_224-root_secp256r1_256
+subject:ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256
+issuerKey:secp224r1
+subjectKey:secp256r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem
new file mode 100644
index 000000000..907017269
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBczCCARmgAwIBAgIULSjU8D5+HqVNW0P/AVRxquSuYOQwCgYIKoZIzj0EAwIw
+LzEtMCsGA1UEAwwkaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9zZWNwMjI0cjFfMjI0
+MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMEAxPjA8BgNVBAMM
+NWVlX3NlY3AyNTZyMV8yNTYtaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9zZWNwMjI0
+cjFfMjI0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET7+7u2Hg+PmxpgpZrIcE
+4uwFC0I+PPcukj8sT3lLRVwqadIzRWw2xBGdBwbgDu3I0ZOQ15kbey0HowTqoEqm
+wDAKBggqhkjOPQQDAgNIADBFAiBcdVGfExFQzV2K3iCjvAYwkf+yc3VfMWTs/ctC
+gApw5gIhAOOBpYoI2SObZwV+QABdwsb4CKb/p/BUPvBpLZl7qsyq
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem.certspec
new file mode 100644
index 000000000..fe7b7f748
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int_secp256r1_256-root_secp224r1_224
+subject:ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224
+issuerKey:secp256r1
+subjectKey:secp256r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem
new file mode 100644
index 000000000..37060f122
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBczCCARmgAwIBAgIUH1IpzZfvEpF2JmV7KBKHG0jM9HUwCgYIKoZIzj0EAwIw
+LzEtMCsGA1UEAwwkaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9zZWNwMjU2azFfMjU2
+MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMEAxPjA8BgNVBAMM
+NWVlX3NlY3AyNTZyMV8yNTYtaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9zZWNwMjU2
+azFfMjU2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAET7+7u2Hg+PmxpgpZrIcE
+4uwFC0I+PPcukj8sT3lLRVwqadIzRWw2xBGdBwbgDu3I0ZOQ15kbey0HowTqoEqm
+wDAKBggqhkjOPQQDAgNIADBFAiBcdVGfExFQzV2K3iCjvAYwkf+yc3VfMWTs/ctC
+gApw5gIhALrNUdttA6aKyReemPg5+7blFCdkym+iRE4ZY4r4v7Dj
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem.certspec
new file mode 100644
index 000000000..aefffd981
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int_secp256r1_256-root_secp256k1_256
+subject:ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256
+issuerKey:secp256r1
+subjectKey:secp256r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem
new file mode 100644
index 000000000..c2d227243
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhjCCASygAwIBAgIUTXVKaNjXdPHww35r4Jei7lctp3kwCgYIKoZIzj0EAwIw
+KjEoMCYGA1UEAwwfaW50X3NlY3AyNTZyMV8yNTYtcm9vdF9yc2FfMjA0ODAiGA8y
+MDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjA7MTkwNwYDVQQDDDBlZV9z
+ZWNwMzg0cjFfMzg0LWludF9zZWNwMjU2cjFfMjU2LXJvb3RfcnNhXzIwNDgwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtg
+jiUt5LcTLajOmOgxU05qnAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalx
+A74oiM/wAvBa9xof3cyDdKpuqc4wCgYIKoZIzj0EAwIDSAAwRQIgXHVRnxMRUM1d
+it4go7wGMJH/snN1XzFk7P3LQoAKcOYCIQCRU+DcUMuYV2efLWpgVoL6JAEeudGB
+jHb72NkQZb/BNg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem.certspec
new file mode 100644
index 000000000..615818d08
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int_secp256r1_256-root_rsa_2048
+subject:ee_secp384r1_384-int_secp256r1_256-root_rsa_2048
+issuerKey:secp256r1
+subjectKey:secp384r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem
new file mode 100644
index 000000000..5f5416365
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB1jCCAVygAwIBAgIUEcVF5BYUztPG7i0t9PxIGg6o6dwwCgYIKoZIzj0EAwIw
+LzEtMCsGA1UEAwwkaW50X3NlY3AzODRyMV8zODQtcm9vdF9zZWNwMjU2cjFfMjU2
+MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMEAxPjA8BgNVBAMM
+NWVlX3NlY3A1MjFyMV81MjEtaW50X3NlY3AzODRyMV8zODQtcm9vdF9zZWNwMjU2
+cjFfMjU2MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBTNycrMR5QQlrycxmdS7C
+f1l3NPpmxit5L4jFGdbTfw0W6hxIOhgnoBC5Eo46CAcMoz719Xg1t8G6JR9sw1Id
+xCsBBlNFGYG0RdND7tN4KjXWz/D/SE9aiD0gnxuQQrcmcDVosvMm4YuDO92KoHND
+krzRlQHhDWmKefU+EeCiK90qrZAwCgYIKoZIzj0EAwIDaAAwZQIxAO0GJz6haDpU
+tNgaQ3SESJY85j6+gRcD7Nc9cvCiVAZZ1OxFRuhW515lVbeTqfcA8wIwSn3QMxb0
+JD+pr9shd7R0F9hefLnHrygMF241qnEEwG0NqwPoe2gdQMFv/B7QntvX
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..b2ae9d0c8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem.certspec
@@ -0,0 +1,5 @@
+issuer:int_secp384r1_384-root_secp256r1_256
+subject:ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256
+issuerKey:secp384r1
+subjectKey:secp521r1
+signature:ecdsaWithSHA256
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_rsa_1024.pem b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_rsa_1024.pem
new file mode 100644
index 000000000..4e3b0d034
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_rsa_1024.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB4jCCAU2gAwIBAgIUZwdE3TaQiMsy82qMqZoGP6z0CwwwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDXJvb3RfcnNhXzEwMjQwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowJTEjMCEGA1UEAwwaaW50X3JzYV8xMDE2LXJvb3RfcnNh
+XzEwMjQwgZ4wDQYJKoZIhvcNAQEBBQADgYwAMIGIAoGAANKbsS+4T93NKbOlGctm
+xDuNj4vlRbp5OEzmY+0D33WZFgDrkgeQ0lMM7OVE25mnHwWJaj7SBxZVNKqZBX5H
+xH47yBrab6HhLjcmi1BGpVJo+drXzLSF2BouGdUNTwtoVKyvbXvmnZoIMTbhWvqP
+U8HIyE/GB3J53Q5V1zaaW90CAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8E
+BAMCAQYwCwYJKoZIhvcNAQELA4GBAGHDJkpCPHfVaQBBRoNWB4xLqnatAEx00jlS
+APUs7bJ6YFjrGElxTmtac5zB6+NpaEZL5JhUEPSEz/V3g0vaO+/W84pDiLQZgf+R
+ZwG0KmxFOfetZCIKPvue/f+aWaU+SHV9ioPz647iDYJOvEBHfWj7Iz7cjw4y7bUN
+cBOGkoOc
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_rsa_1024.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_rsa_1024.pem.certspec
new file mode 100644
index 000000000..c6e77116b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_rsa_1024.pem.certspec
@@ -0,0 +1,6 @@
+issuer:root_rsa_1024
+subject:int_rsa_1016-root_rsa_1024
+issuerKey:rsa1024
+subjectKey:rsa1016
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_secp256r1_256.pem
new file mode 100644
index 000000000..261ca6448
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_secp256r1_256.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBrzCCAVagAwIBAgIUExAlIjL69OL4W35uYWfbpzZ207YwCgYIKoZIzj0EAwIw
+HTEbMBkGA1UEAwwScm9vdF9zZWNwMjU2cjFfMjU2MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMCoxKDAmBgNVBAMMH2ludF9yc2FfMTAxNi1yb290
+X3NlY3AyNTZyMV8yNTYwgZ4wDQYJKoZIhvcNAQEBBQADgYwAMIGIAoGAANKbsS+4
+T93NKbOlGctmxDuNj4vlRbp5OEzmY+0D33WZFgDrkgeQ0lMM7OVE25mnHwWJaj7S
+BxZVNKqZBX5HxH47yBrab6HhLjcmi1BGpVJo+drXzLSF2BouGdUNTwtoVKyvbXvm
+nZoIMTbhWvqPU8HIyE/GB3J53Q5V1zaaW90CAwEAAaMdMBswDAYDVR0TBAUwAwEB
+/zALBgNVHQ8EBAMCAQYwCgYIKoZIzj0EAwIDRwAwRAIgXHVRnxMRUM1dit4go7wG
+MJH/snN1XzFk7P3LQoAKcOYCIDmD30j813c64HuW9WnjhZWMPRLqIiAMD+u9hWOm
+17If
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..27728ca37
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1016-root_secp256r1_256.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp256r1_256
+subject:int_rsa_1016-root_secp256r1_256
+issuerKey:secp256r1
+subjectKey:rsa1016
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1016.pem b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1016.pem
new file mode 100644
index 000000000..eff1ee721
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1016.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB4jCCAU6gAwIBAgIUeTtd4gq+pnMumaH8M1hJb7WxuRAwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDXJvb3RfcnNhXzEwMTYwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowJTEjMCEGA1UEAwwaaW50X3JzYV8xMDI0LXJvb3RfcnNh
+XzEwMTYwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOpdEAQHrqMXflQPm+T
+XrUv/rPr6dDcXKzib5c8qUy8DZwx1mwMATvOnILQ1IAyjfBftrzXmQpTEt2uYVKt
+buYcjBvdhmPGi9NiJKmIKueOifVW39vm9R2mESy/wnyKSTNrQa/bdTIbUrJKc0TR
+NI5kY1GlUcdXHM2guP419hp1AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P
+BAQDAgEGMAsGCSqGSIb3DQEBCwOBgACvCVg2KCtiE/g+PkXU3bn7mj4hGwOxH+2P
+NnyhAnlx3kEEEJIHaCIS3s56wiWtwf0P4DG1qHn+IZR6zbZ+0ALzZneREtGvLCNI
+M7+GCoOmkPWbR4I+2wYpBgRtHDeK06EWbrSQF9V+P+Z9hXW7NJ/npxD40+fs27Ot
+hjVyw0ex
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1016.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1016.pem.certspec
new file mode 100644
index 000000000..fafb393bf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1016.pem.certspec
@@ -0,0 +1,6 @@
+issuer:root_rsa_1016
+subject:int_rsa_1024-root_rsa_1016
+issuerKey:rsa1016
+subjectKey:rsa1024
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1024.pem b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1024.pem
new file mode 100644
index 000000000..3c6264488
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1024.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB4zCCAU6gAwIBAgIUKd2Q3DzwYKrXasi5yQdWvgSatdgwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDXJvb3RfcnNhXzEwMjQwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowJTEjMCEGA1UEAwwaaW50X3JzYV8xMDI0LXJvb3RfcnNh
+XzEwMjQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOpdEAQHrqMXflQPm+T
+XrUv/rPr6dDcXKzib5c8qUy8DZwx1mwMATvOnILQ1IAyjfBftrzXmQpTEt2uYVKt
+buYcjBvdhmPGi9NiJKmIKueOifVW39vm9R2mESy/wnyKSTNrQa/bdTIbUrJKc0TR
+NI5kY1GlUcdXHM2guP419hp1AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P
+BAQDAgEGMAsGCSqGSIb3DQEBCwOBgQBpJC20/N+v3Xb66ZpiGiwrh2zAo940Fvmo
+UXPG5+jwTCSowU8aDXGq+PeHsu+X58NTigSU37zhu4xOATCL06w71FnJTfVFseF1
+FUnYPQahSARRlMGyz3AfcTcexTqiJCIn7Owvsjj9eEUKiMnwOY5z+vc11g3pW2Q4
+ALoRuo9ETg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1024.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1024.pem.certspec
new file mode 100644
index 000000000..66891f979
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_rsa_1024-root_rsa_1024.pem.certspec
@@ -0,0 +1,6 @@
+issuer:root_rsa_1024
+subject:int_rsa_1024-root_rsa_1024
+issuerKey:rsa1024
+subjectKey:rsa1024
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp224r1_224-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/int_secp224r1_224-root_secp256r1_256.pem
new file mode 100644
index 000000000..cfd1fc33a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp224r1_224-root_secp256r1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBYzCCAQmgAwIBAgIUMfmdT1oaX8JMXd4bb7glStZfa0AwCgYIKoZIzj0EAwIw
+HTEbMBkGA1UEAwwScm9vdF9zZWNwMjU2cjFfMjU2MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMC8xLTArBgNVBAMMJGludF9zZWNwMjI0cjFfMjI0
+LXJvb3Rfc2VjcDI1NnIxXzI1NjBNMBAGByqGSM49AgEGBSuBBAAhAzkABGaNcsym
+/WobNVe1NmEE2EQI7LY38I6Mhrv/gszojwBm169jwymLo3c0ihICsDs3/Wsf9BWq
+MR6jHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqGSM49BAMCA0gA
+MEUCIFx1UZ8TEVDNXYreIKO8BjCR/7JzdV8xZOz9y0KACnDmAiEAv+3koyIlSx0a
+SY0agquE0R53+/Q+kNJwlvdfEMNYjs4=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp224r1_224-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_secp224r1_224-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..89d77d3b8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp224r1_224-root_secp256r1_256.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp256r1_256
+subject:int_secp224r1_224-root_secp256r1_256
+issuerKey:secp256r1
+subjectKey:secp224r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_rsa_2048.pem b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_rsa_2048.pem
new file mode 100644
index 000000000..5cda1057d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_rsa_2048.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICIjCCAQygAwIBAgIUUyCpJPo1OBfUzS63URCB8jij4wYwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDXJvb3RfcnNhXzIwNDgwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowKjEoMCYGA1UEAwwfaW50X3NlY3AyNTZyMV8yNTYtcm9v
+dF9yc2FfMjA0ODBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE+/u7th4Pj5saYK
+WayHBOLsBQtCPjz3LpI/LE95S0VcKmnSM0VsNsQRnQcG4A7tyNGTkNeZG3stB6ME
+6qBKpsCjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEB
+CwOCAQEAQFZl1Ogt4U76JlyY3Iuw3xKnOUyU+Mmt1oD+WXuHuwuxBbd29n0at+Qi
+wOomkgbbudIiVF+X+AXb/PKXmQhUqQxQzROt77cU8JV7upVf0NaN26rrwLgoGFI0
+ipmxbzev2nMrJMkzH2cAEXKCE92VPaQGsuLR0SlGFsHTDRPk5bNI8RL5CxPjw0VA
+89wLF+DB1yqtuWIuqvgIG38BQCnRyZiql9eH+EQtonPm+L+PAa5MJAHNF+C7vHEN
+TB6gjO2J6Pt6tt50ByikmTjQcIMLkG6Y63XUpNZYMToUSnd+BvcuJDY1nDHv2BG2
+l1s7rOMeHUKiDjhKnhiyOBemiwjomQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_rsa_2048.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_rsa_2048.pem.certspec
new file mode 100644
index 000000000..44a65ef5a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_rsa_2048.pem.certspec
@@ -0,0 +1,5 @@
+issuer:root_rsa_2048
+subject:int_secp256r1_256-root_rsa_2048
+subjectKey:secp256r1
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp224r1_224.pem b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp224r1_224.pem
new file mode 100644
index 000000000..2d04da2e0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp224r1_224.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBaDCCARWgAwIBAgIUFW655tKQ8N76G2Fs4e+yyy9HSu0wCgYIKoZIzj0EAwIw
+HTEbMBkGA1UEAwwScm9vdF9zZWNwMjI0cjFfMjI0MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMC8xLTArBgNVBAMMJGludF9zZWNwMjU2cjFfMjU2
+LXJvb3Rfc2VjcDIyNHIxXzIyNDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE+/
+u7th4Pj5saYKWayHBOLsBQtCPjz3LpI/LE95S0VcKmnSM0VsNsQRnQcG4A7tyNGT
+kNeZG3stB6ME6qBKpsCjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoG
+CCqGSM49BAMCA0EAMD4CHQCaPG/wRttw8lX1L9aYUhzXLbwFIGNPlbZLslJUAh0A
+sdRLm9WH7E0AswZO3oBFsoiZgtUXKojJjBOlhQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp224r1_224.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp224r1_224.pem.certspec
new file mode 100644
index 000000000..66ebc1b93
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp224r1_224.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp224r1_224
+subject:int_secp256r1_256-root_secp224r1_224
+issuerKey:secp224r1
+subjectKey:secp256r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256k1_256.pem b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256k1_256.pem
new file mode 100644
index 000000000..dba78878f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256k1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbjCCARWgAwIBAgIUYTlSrggMzCP6DVELNF4gN3/2PagwCgYIKoZIzj0EAwIw
+HTEbMBkGA1UEAwwScm9vdF9zZWNwMjU2azFfMjU2MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMC8xLTArBgNVBAMMJGludF9zZWNwMjU2cjFfMjU2
+LXJvb3Rfc2VjcDI1NmsxXzI1NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE+/
+u7th4Pj5saYKWayHBOLsBQtCPjz3LpI/LE95S0VcKmnSM0VsNsQRnQcG4A7tyNGT
+kNeZG3stB6ME6qBKpsCjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoG
+CCqGSM49BAMCA0cAMEQCIGNZAgGJ1z5b/9EWTuPiCuBK2HWvd1yTYLoQH5fdJy0k
+AiBNdBxpWObwfdKgHCLH8gHgQEBLLT5lpWwSlvTGnjknKQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256k1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256k1_256.pem.certspec
new file mode 100644
index 000000000..c7e190ab0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256k1_256.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp256k1_256
+subject:int_secp256r1_256-root_secp256k1_256
+issuerKey:secp256k1
+subjectKey:secp256r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256r1_256.pem
new file mode 100644
index 000000000..b415487ef
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256r1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbzCCARWgAwIBAgIUZ1LG/akVEjMI75EV2IrvSQz2ONgwCgYIKoZIzj0EAwIw
+HTEbMBkGA1UEAwwScm9vdF9zZWNwMjU2cjFfMjU2MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMC8xLTArBgNVBAMMJGludF9zZWNwMjU2cjFfMjU2
+LXJvb3Rfc2VjcDI1NnIxXzI1NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE+/
+u7th4Pj5saYKWayHBOLsBQtCPjz3LpI/LE95S0VcKmnSM0VsNsQRnQcG4A7tyNGT
+kNeZG3stB6ME6qBKpsCjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoG
+CCqGSM49BAMCA0gAMEUCIFx1UZ8TEVDNXYreIKO8BjCR/7JzdV8xZOz9y0KACnDm
+AiEA3SQoQJXCBse68NgRuB1mVoMTEJOAe+qrkoRGsx5dNDY=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..6854d2187
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp256r1_256-root_secp256r1_256.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp256r1_256
+subject:int_secp256r1_256-root_secp256r1_256
+issuerKey:secp256r1
+subjectKey:secp256r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp384r1_384-root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/int_secp384r1_384-root_secp256r1_256.pem
new file mode 100644
index 000000000..c2958dc6d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp384r1_384-root_secp256r1_256.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBjDCCATKgAwIBAgIURykYBB7pd62OS//UuN+CSn+WSwwwCgYIKoZIzj0EAwIw
+HTEbMBkGA1UEAwwScm9vdF9zZWNwMjU2cjFfMjU2MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMC8xLTArBgNVBAMMJGludF9zZWNwMzg0cjFfMzg0
+LXJvb3Rfc2VjcDI1NnIxXzI1NjB2MBAGByqGSM49AgEGBSuBBAAiA2IABKFockM2
+K1x7GInzeRVGFaHHP7SN7oY+AikV22COJS3ktxMtqM6Y6DFTTmqcDAsJyNY5regy
+BuW6gTRzoR+jMOBdqMluQ4P+J4c9qXEDviiIz/AC8Fr3Gh/dzIN0qm6pzqMdMBsw
+DAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCgYIKoZIzj0EAwIDSAAwRQIgXHVR
+nxMRUM1dit4go7wGMJH/snN1XzFk7P3LQoAKcOYCIQDQJQ6/wj2o6teiKvbzgn63
+QDv+vT1n/+9GOhIWeo1FSw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/int_secp384r1_384-root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/int_secp384r1_384-root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..de8e85198
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/int_secp384r1_384-root_secp256r1_256.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp256r1_256
+subject:int_secp384r1_384-root_secp256r1_256
+issuerKey:secp256r1
+subjectKey:secp384r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/moz.build b/security/manager/ssl/tests/unit/test_keysize/moz.build
new file mode 100644
index 000000000..a69bf43a9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/moz.build
@@ -0,0 +1,41 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ee_rsa_1016-int_rsa_1024-root_rsa_1024.pem',
+# 'ee_rsa_1024-int_rsa_1016-root_rsa_1024.pem',
+# 'ee_rsa_1024-int_rsa_1024-root_rsa_1016.pem',
+# 'ee_rsa_1024-int_rsa_1024-root_rsa_1024.pem',
+# 'ee_secp224r1_224-int_secp256r1_256-root_rsa_2048.pem',
+# 'ee_secp224r1_224-int_secp256r1_256-root_secp256r1_256.pem',
+# 'ee_secp256k1_256-int_secp256r1_256-root_secp256r1_256.pem',
+# 'ee_secp256r1_256-int_rsa_1016-root_secp256r1_256.pem',
+# 'ee_secp256r1_256-int_secp224r1_224-root_secp256r1_256.pem',
+# 'ee_secp256r1_256-int_secp256r1_256-root_secp224r1_224.pem',
+# 'ee_secp256r1_256-int_secp256r1_256-root_secp256k1_256.pem',
+# 'ee_secp384r1_384-int_secp256r1_256-root_rsa_2048.pem',
+# 'ee_secp521r1_521-int_secp384r1_384-root_secp256r1_256.pem',
+# 'int_rsa_1016-root_rsa_1024.pem',
+# 'int_rsa_1016-root_secp256r1_256.pem',
+# 'int_rsa_1024-root_rsa_1016.pem',
+# 'int_rsa_1024-root_rsa_1024.pem',
+# 'int_secp224r1_224-root_secp256r1_256.pem',
+# 'int_secp256r1_256-root_rsa_2048.pem',
+# 'int_secp256r1_256-root_secp224r1_224.pem',
+# 'int_secp256r1_256-root_secp256k1_256.pem',
+# 'int_secp256r1_256-root_secp256r1_256.pem',
+# 'int_secp384r1_384-root_secp256r1_256.pem',
+# 'root_rsa_1016.pem',
+# 'root_rsa_1024.pem',
+# 'root_rsa_2048.pem',
+# 'root_secp224r1_224.pem',
+# 'root_secp256k1_256.pem',
+# 'root_secp256r1_256.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_rsa_1016.pem b/security/manager/ssl/tests/unit/test_keysize/root_rsa_1016.pem
new file mode 100644
index 000000000..0a72087f1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_rsa_1016.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB1DCCAUCgAwIBAgIUM7Lg6QmOdkt261MCbyFKi45pe74wCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDXJvb3RfcnNhXzEwMTYwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowGDEWMBQGA1UEAwwNcm9vdF9yc2FfMTAxNjCBnjANBgkq
+hkiG9w0BAQEFAAOBjAAwgYgCgYAA0puxL7hP3c0ps6UZy2bEO42Pi+VFunk4TOZj
+7QPfdZkWAOuSB5DSUwzs5UTbmacfBYlqPtIHFlU0qpkFfkfEfjvIGtpvoeEuNyaL
+UEalUmj52tfMtIXYGi4Z1Q1PC2hUrK9te+admggxNuFa+o9TwcjIT8YHcnndDlXX
+Nppb3QIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjALBgkqhkiG
+9w0BAQsDgYAAg+CxStL2zK/003mV+gzN6dSgozHCdJyVQLN9LbsqvAHu/Ker02zl
+Ngsq7TZmpCKfa2VYRpNJbzW0095UGnD/qVS876pNzQPmUlg5QVWda6y2esKwksxO
+7yEShApyGMgxL4VEkCNxz40+NfU2falPeXtjkZU6CuOTWSU/cWRs1w==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_rsa_1016.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/root_rsa_1016.pem.certspec
new file mode 100644
index 000000000..b0b5ba8e5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_rsa_1016.pem.certspec
@@ -0,0 +1,6 @@
+issuer:root_rsa_1016
+subject:root_rsa_1016
+issuerKey:rsa1016
+subjectKey:rsa1016
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_rsa_1024.pem b/security/manager/ssl/tests/unit/test_keysize/root_rsa_1024.pem
new file mode 100644
index 000000000..4057c0d02
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_rsa_1024.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB1jCCAUGgAwIBAgIUN4fAqdmb7z7NLWF0XiUi1tHIHQ0wCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDXJvb3RfcnNhXzEwMjQwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowGDEWMBQGA1UEAwwNcm9vdF9yc2FfMTAyNDCBnzANBgkq
+hkiG9w0BAQEFAAOBjQAwgYkCgYEA06l0QBAeuoxd+VA+b5NetS/+s+vp0NxcrOJv
+lzypTLwNnDHWbAwBO86cgtDUgDKN8F+2vNeZClMS3a5hUq1u5hyMG92GY8aL02Ik
+qYgq546J9Vbf2+b1HaYRLL/CfIpJM2tBr9t1MhtSskpzRNE0jmRjUaVRx1cczaC4
+/jX2GnUCAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZI
+hvcNAQELA4GBABaze8o5xyNFgdXvK0pFIj+ZfG634ATqddoE7x1C89M3Mh4j5nJv
+/zuKwz1NS4uty584WWCODuu1iAqwKYeOmg2aejN3k/cVWMEqmRG5DRL9CdYs8/Jt
+eFS05lsRzHVRq9m7nEOgv5Xhbn5egMwGxEjmI0Bu/o1YJ/2hxrhXit5W
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_rsa_1024.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/root_rsa_1024.pem.certspec
new file mode 100644
index 000000000..09cd420f7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_rsa_1024.pem.certspec
@@ -0,0 +1,6 @@
+issuer:root_rsa_1024
+subject:root_rsa_1024
+issuerKey:rsa1024
+subjectKey:rsa1024
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_rsa_2048.pem b/security/manager/ssl/tests/unit/test_keysize/root_rsa_2048.pem
new file mode 100644
index 000000000..f08030ecc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_rsa_2048.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAcWgAwIBAgIUL9RaZAoENJalu9ROFdxp+1zeK3wwCwYJKoZIhvcNAQEL
+MBgxFjAUBgNVBAMMDXJvb3RfcnNhXzIwNDgwIhgPMjAxNTExMjgwMDAwMDBaGA8y
+MDE4MDIwNTAwMDAwMFowGDEWMBQGA1UEAwwNcm9vdF9yc2FfMjA0ODCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
+SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYL
+K7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwc
+bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
+JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMd
+MBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQAG
+/Ky5Qkbd1EjvW6h/wvxOP5jj5FQiN4c+kxP5IpiXZr2YyjZIVRShExNfzpCmLuPq
+rkaY/IZVHT32bwW87BudscCL9lTqZbsDXayEh2KuWDbw/+FfXd+KpKWi6jweyjyW
+159Im2POWzi9XyKtwY6GdVKhsrL5LwCO9nhNBwVoQ+2WiFvc5eggNPl7WTbywgV3
+eDfDVN+3NVAoDw6tcTkFYbmjJpF3w+c839wtiIJEvQ6okv5cZOLF4pW+3PoYAEaI
+jVfGtGF8QnzSBeetTliQcCy0Ce/mVZ+N0+bYeHrTm4Bm5YySszKs+1vxdzm9+fH3
+jZ6//NQm+C+GVbNGj8Nm
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_rsa_2048.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/root_rsa_2048.pem.certspec
new file mode 100644
index 000000000..cebc2f8e6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_rsa_2048.pem.certspec
@@ -0,0 +1,4 @@
+issuer:root_rsa_2048
+subject:root_rsa_2048
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_secp224r1_224.pem b/security/manager/ssl/tests/unit/test_keysize/root_secp224r1_224.pem
new file mode 100644
index 000000000..afc387bf1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_secp224r1_224.pem
@@ -0,0 +1,9 @@
+-----BEGIN CERTIFICATE-----
+MIIBSDCB96ADAgECAhQJ0gm/8w+13dcPEBRcKlEAdi1aKjAKBggqhkjOPQQDAjAd
+MRswGQYDVQQDDBJyb290X3NlY3AyMjRyMV8yMjQwIhgPMjAxNTExMjgwMDAwMDBa
+GA8yMDE4MDIwNTAwMDAwMFowHTEbMBkGA1UEAwwScm9vdF9zZWNwMjI0cjFfMjI0
+ME0wEAYHKoZIzj0CAQYFK4EEACEDOQAEZo1yzKb9ahs1V7U2YQTYRAjstjfwjoyG
+u/+CzOiPAGbXr2PDKYujdzSKEgKwOzf9ax/0FaoxHqMdMBswDAYDVR0TBAUwAwEB
+/zALBgNVHQ8EBAMCAQYwCgYIKoZIzj0EAwIDQAAwPQIdAJo8b/BG23DyVfUv1phS
+HNctvAUgY0+VtkuyUlQCHFuyUCiwjmlUwEFrlJJcS0k4ErhiiH2J96FdTCw=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_secp224r1_224.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/root_secp224r1_224.pem.certspec
new file mode 100644
index 000000000..31370f6f7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_secp224r1_224.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp224r1_224
+subject:root_secp224r1_224
+issuerKey:secp224r1
+subjectKey:secp224r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_secp256k1_256.pem b/security/manager/ssl/tests/unit/test_keysize/root_secp256k1_256.pem
new file mode 100644
index 000000000..19cbdc712
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_secp256k1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBWTCCAQCgAwIBAgIUDZ1MSO282sT4cTPmUNrRED65xiAwCgYIKoZIzj0EAwIw
+HTEbMBkGA1UEAwwScm9vdF9zZWNwMjU2azFfMjU2MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMB0xGzAZBgNVBAMMEnJvb3Rfc2VjcDI1NmsxXzI1
+NjBWMBAGByqGSM49AgEGBSuBBAAKA0IABDXufHKJ2P73qGr+XaZti8LrtqhUP9L+
+rQifRc56zQ+mQ4KpUAxB2tdw/9S1Eb9LSS6xI4gAwyxPdsc6PzKU58WjHTAbMAwG
+A1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqGSM49BAMCA0cAMEQCIGNZAgGJ
+1z5b/9EWTuPiCuBK2HWvd1yTYLoQH5fdJy0kAiBbbODJAli2zU6pkhPi4lq9+jKA
+l32sv96VWrOsyrAFjg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_secp256k1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/root_secp256k1_256.pem.certspec
new file mode 100644
index 000000000..c78aa61bb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_secp256k1_256.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp256k1_256
+subject:root_secp256k1_256
+issuerKey:secp256k1
+subjectKey:secp256k1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_secp256r1_256.pem b/security/manager/ssl/tests/unit/test_keysize/root_secp256r1_256.pem
new file mode 100644
index 000000000..2417685dd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_secp256r1_256.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBXTCCAQOgAwIBAgIUHe1Ak9B5RX1dDhygSBpPrhZ9JEowCgYIKoZIzj0EAwIw
+HTEbMBkGA1UEAwwScm9vdF9zZWNwMjU2cjFfMjU2MCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMB0xGzAZBgNVBAMMEnJvb3Rfc2VjcDI1NnIxXzI1
+NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE+/u7th4Pj5saYKWayHBOLsBQtC
+Pjz3LpI/LE95S0VcKmnSM0VsNsQRnQcG4A7tyNGTkNeZG3stB6ME6qBKpsCjHTAb
+MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqGSM49BAMCA0gAMEUCIFx1
+UZ8TEVDNXYreIKO8BjCR/7JzdV8xZOz9y0KACnDmAiEA/cwfybIBowGnPXI58HEd
+4kEWa8IF3nFuEFBja30LxhI=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize/root_secp256r1_256.pem.certspec b/security/manager/ssl/tests/unit/test_keysize/root_secp256r1_256.pem.certspec
new file mode 100644
index 000000000..4447fc4b4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize/root_secp256r1_256.pem.certspec
@@ -0,0 +1,7 @@
+issuer:root_secp256r1_256
+subject:root_secp256r1_256
+issuerKey:secp256r1
+subjectKey:secp256r1
+signature:ecdsaWithSHA256
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev.js b/security/manager/ssl/tests/unit/test_keysize_ev.js
new file mode 100644
index 000000000..b6b4ccade
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev.js
@@ -0,0 +1,146 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Checks that RSA certs with key sizes below 2048 bits when verifying for EV
+// are rejected.
+
+do_get_profile(); // Must be called before getting nsIX509CertDB
+const certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+const SERVER_PORT = 8888;
+
+function getOCSPResponder(expectedCertNames) {
+ let expectedPaths = expectedCertNames.slice();
+ return startOCSPResponder(SERVER_PORT, "www.example.com", "test_keysize_ev/",
+ expectedCertNames, expectedPaths);
+}
+
+function loadCert(certName, trustString) {
+ let certFilename = "test_keysize_ev/" + certName + ".pem";
+ addCertFromFile(certDB, certFilename, trustString);
+ return constructCertFromFile(certFilename);
+}
+
+/**
+ * Adds a single EV key size test.
+ *
+ * @param {Array} expectedNamesForOCSP
+ * An array of nicknames of the certs to be responded to.
+ * @param {String} rootCertFileName
+ * The file name of the root cert. Can begin with ".." to reference
+ * certs in folders other than "test_keysize_ev/".
+ * @param {Array} intCertFileNames
+ * An array of file names of any intermediate certificates.
+ * @param {String} endEntityCertFileName
+ * The file name of the end entity cert.
+ * @param {Boolean} expectedResult
+ * Whether the chain is expected to validate as EV.
+ */
+function addKeySizeTestForEV(expectedNamesForOCSP,
+ rootCertFileName, intCertFileNames,
+ endEntityCertFileName, expectedResult)
+{
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = getOCSPResponder(expectedNamesForOCSP);
+
+ loadCert(rootCertFileName, "CTu,CTu,CTu");
+ for (let intCertFileName of intCertFileNames) {
+ loadCert(intCertFileName, ",,");
+ }
+ checkEVStatus(
+ certDB,
+ constructCertFromFile(`test_keysize_ev/${endEntityCertFileName}.pem`),
+ certificateUsageSSLServer,
+ expectedResult);
+
+ ocspResponder.stop(run_next_test);
+ });
+}
+
+/**
+ * For debug builds which have the test EV roots compiled in, checks RSA chains
+ * which contain certs with key sizes adequate for EV are validated as such,
+ * while chains that contain any cert with an inadequate key size fail EV and
+ * validate as DV.
+ * For opt builds which don't have the test EV roots compiled in, checks that
+ * none of the chains validate as EV.
+ *
+ * Note: This function assumes that the key size requirements for EV are greater
+ * than the requirements for DV.
+ *
+ * @param {Number} inadequateKeySize
+ * The inadequate key size of the generated certs.
+ * @param {Number} adequateKeySize
+ * The adequate key size of the generated certs.
+ */
+function checkRSAChains(inadequateKeySize, adequateKeySize) {
+ // Reuse the existing test RSA EV root
+ let rootOKCertFileName = "../test_ev_certs/evroot";
+ let rootOKName = "evroot";
+ let rootNotOKName = "ev_root_rsa_" + inadequateKeySize;
+ let intOKName = "ev_int_rsa_" + adequateKeySize;
+ let intNotOKName = "ev_int_rsa_" + inadequateKeySize;
+ let eeOKName = "ev_ee_rsa_" + adequateKeySize;
+ let eeNotOKName = "ev_ee_rsa_" + inadequateKeySize;
+
+ // Chain with certs that have adequate sizes for EV and DV
+ // In opt builds, this chain is only validated for DV. Hence, an OCSP fetch
+ // will for example not be done for the "ev_int_rsa_2048-evroot" intermediate
+ // in such a build.
+ let intFullName = intOKName + "-" + rootOKName;
+ let eeFullName = eeOKName + "-" + intOKName + "-" + rootOKName;
+ let expectedNamesForOCSP = gEVExpected
+ ? [ intFullName,
+ eeFullName ]
+ : [ eeFullName ];
+ addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
+ [ intFullName ], eeFullName, gEVExpected);
+
+ // Chain with a root cert that has an inadequate size for EV, but
+ // adequate size for DV
+ intFullName = intOKName + "-" + rootNotOKName;
+ eeFullName = eeOKName + "-" + intOKName + "-" + rootNotOKName;
+ expectedNamesForOCSP = [ eeFullName ];
+ addKeySizeTestForEV(expectedNamesForOCSP, rootNotOKName,
+ [ intFullName ], eeFullName, false);
+
+ // Chain with an intermediate cert that has an inadequate size for EV, but
+ // adequate size for DV
+ intFullName = intNotOKName + "-" + rootOKName;
+ eeFullName = eeOKName + "-" + intNotOKName + "-" + rootOKName;
+ expectedNamesForOCSP = [ eeFullName ];
+ addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
+ [ intFullName ], eeFullName, false);
+
+ // Chain with an end entity cert that has an inadequate size for EV, but
+ // adequate size for DV
+ intFullName = intOKName + "-" + rootOKName;
+ eeFullName = eeNotOKName + "-" + intOKName + "-" + rootOKName;
+ expectedNamesForOCSP = gEVExpected
+ ? [ intFullName,
+ eeFullName ]
+ : [ eeFullName ];
+ addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
+ [ intFullName ], eeFullName, false);
+}
+
+function run_test() {
+ Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+
+ let smallKeyEVRoot =
+ constructCertFromFile("test_keysize_ev/ev_root_rsa_2040.pem");
+ equal(smallKeyEVRoot.sha256Fingerprint,
+ "49:46:10:F4:F5:B1:96:E7:FB:FA:4D:A6:34:03:D0:99:" +
+ "22:D4:77:20:3F:84:E0:DF:1C:AD:B4:C2:76:BB:63:24",
+ "test sanity check: the small-key EV root must have the same " +
+ "fingerprint as the corresponding entry in ExtendedValidation.cpp");
+
+ checkRSAChains(2040, 2048);
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem
new file mode 100644
index 000000000..1e231157c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDYzCCAk2gAwIBAgIUYWcJYs/7lzpBLFqmhT8F7LPbOLAwCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmV2X2ludF9yc2FfMjA0OC1ldnJvb3QwIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowMDEuMCwGA1UEAwwlZXZfZWVfcnNhXzIw
+NDAtZXZfaW50X3JzYV8yMDQ4LWV2cm9vdDCCASEwDQYJKoZIhvcNAQEBBQADggEO
+ADCCAQkCggEAALrAZS/fvABViC/7rqzuyI+i0IPCl91dQGZN09kPUvmqAr2KUPuh
+bg/ZkYeO9HX5s1DZ+OPrKr1xfOMnsJeIUx8T344+TjudYWu4pB5TBu7SRyFjFhBR
+GAEnak62bwczG1y8i8rnAWqPmz1PKsRVPGJM9SY7yzSOiEDeZhKHCWCnkhkbE4+y
+F/dlzse/+OlPFrOUGb91BMWafk95vW0XPpx789nSpOc8wYCwWQpz1YT7f8m1T6VE
+YH5T/GhcelX9RKgdQUK2r1Hqb6bOpSlloujF2E88oCTW+7mwBbllHOXZ8uz0DtQE
+mBqf/AJjbjEbCVxjMqDIfcOScbVVFIF3SwIDAQABo4GEMIGBMF4GCCsGAQUFBwEB
+BFIwUDBOBggrBgEFBQcwAYZCaHR0cDovL3d3dy5leGFtcGxlLmNvbTo4ODg4L2V2
+X2VlX3JzYV8yMDQwLWV2X2ludF9yc2FfMjA0OC1ldnJvb3QvMB8GA1UdIAQYMBYw
+FAYSKwYBBAHrSYUahRqFGgGDdAkBMAsGCSqGSIb3DQEBCwOCAQEACeVAAm2UDFMG
+vuYyPdPhGr7DBIAbk2RHE+k/KKZvOC2AgK1USid4/lOdFVcFijDS46t97otxVYvA
+NDuPj/O3uYf+Gjw4rATdiA6YTXtumOfC2nwhJ9zBSFsDLEajynStYcUtJClentys
+b08EGO3cUr40aWMXZMIG4mjZhQgfTu6TJ9OlDwzexb0/L2AF8PyEd8wrO1RUTU2e
+Tb3/d15AgDccaBfrEg72Mb7oDGr/QIdTgqdtLqMF9BTQRat3O6J4LRf2UMpot9Pr
+j4eKG/93p+TymG6SdosjWavD5EQngZ7ihayl9xPZ7nAnPfLI43KNqVHDALxT8ROA
+HNBIjUe9pw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem.certspec
new file mode 100644
index 000000000..e64c651bc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ev_int_rsa_2048-evroot
+subject:ev_ee_rsa_2040-ev_int_rsa_2048-evroot
+subjectKey:rsa2040
+extension:authorityInformationAccess:http://www.example.com:8888/ev_ee_rsa_2040-ev_int_rsa_2048-evroot/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem
new file mode 100644
index 000000000..4c66b2252
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDYzCCAk6gAwIBAgIUX1WnK44zi+RzvEojjYi3bcyvC34wCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmV2X2ludF9yc2FfMjA0MC1ldnJvb3QwIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowMDEuMCwGA1UEAwwlZXZfZWVfcnNhXzIw
+NDgtZXZfaW50X3JzYV8yMDQwLWV2cm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODY
+H72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk
+27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A9
+0jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMM
+kd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaL
+L+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBhDCBgTBeBggrBgEFBQcB
+AQRSMFAwTgYIKwYBBQUHMAGGQmh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9l
+dl9lZV9yc2FfMjA0OC1ldl9pbnRfcnNhXzIwNDAtZXZyb290LzAfBgNVHSAEGDAW
+MBQGEisGAQQB60mFGoUahRoBg3QJATALBgkqhkiG9w0BAQsDggEAAErvI4rRV3Xf
+3NzWWiiryrNpibL3bYmzXsF3+jZWBobx21Qrck7nGeHAuZ7M90Aw9HdPxlIOnwNA
+jHv141zXE2vntVhKUTgS4TLou8+7A5Al8azWMAj9M7fqtx1Y9b4j+NK26KEOHSF0
+8MtxEYaiQfAOZEA3m0Z60w0XyQ4ULZKUEVJkrwY7sJUSzExd2dyFVQDM5uZXN/0n
+ZyGAWIj57xwxf4aXgR4y6WgBf7AZqTFc4F/YUzH9HlpRSD0uWolUB4dqNuZ2ApXZ
+arj4rqV/4Pub9IAi0AmzWDZxGkQk3E4BGHkk6unVniuQlnCMNIn/uKj2PqetX9nx
+k+dj1HE2ig==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem.certspec
new file mode 100644
index 000000000..0b7bfd426
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ev_int_rsa_2040-evroot
+subject:ev_ee_rsa_2048-ev_int_rsa_2040-evroot
+issuerKey:rsa2040
+extension:authorityInformationAccess:http://www.example.com:8888/ev_ee_rsa_2048-ev_int_rsa_2040-evroot/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem
new file mode 100644
index 000000000..3b579102a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDgjCCAmygAwIBAgIUa/PALQU+SWg3PCw8ajeVDsqyk+IwCwYJKoZIhvcNAQEL
+MCsxKTAnBgNVBAMMIGV2X2ludF9yc2FfMjA0OC1ldl9yb290X3JzYV8yMDQwMCIY
+DzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMDoxODA2BgNVBAMML2V2
+X2VlX3JzYV8yMDQ4LWV2X2ludF9yc2FfMjA0OC1ldl9yb290X3JzYV8yMDQwMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08
+E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc
+1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAP
+DY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQ
+gAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqV
+YR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQID
+AQABo4GOMIGLMGgGCCsGAQUFBwEBBFwwWjBYBggrBgEFBQcwAYZMaHR0cDovL3d3
+dy5leGFtcGxlLmNvbTo4ODg4L2V2X2VlX3JzYV8yMDQ4LWV2X2ludF9yc2FfMjA0
+OC1ldl9yb290X3JzYV8yMDQwLzAfBgNVHSAEGDAWMBQGEisGAQQB60mFGoUahRoB
+g3QJATALBgkqhkiG9w0BAQsDggEBAIol9cdHyFph1UFZIuQTdAgBr5GGyZP/9cHt
+ffmjqSz4TIlZPN4+FC+yh+wC/KeZiFDWuyGtdnfADkbbuG0hzSppx8EcctiKUbwE
+VnEgmX+P0nQGsdpPek8WgjZriAHJGdlFN4wJfECBgSa7SL8uwvY5VrI/4BQTRXq1
+b4fzHEZtJX5pPwoQSfHmjD6uMSK/FwTCSWNCIcA+tfwc7V31jmuc3Nz+gg5QMJFc
+5vzei1jgc0o4FxoFJhKbNQzgOMMOFdrercVcdM5HkEdlkoEo3Ae9hidP9DnHUoFZ
+lz9iVgvQiFoEYqa1Z1OFxmIGnzbwCCAq727elUxDZB3fnBeZeWc=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem.certspec
new file mode 100644
index 000000000..a36acf887
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ev_int_rsa_2048-ev_root_rsa_2040
+subject:ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040
+extension:authorityInformationAccess:http://www.example.com:8888/ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem
new file mode 100644
index 000000000..47d86baf5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDZDCCAk6gAwIBAgIUNQdpgL87vkOZHNiFDZ66Q1FTBqMwCwYJKoZIhvcNAQEL
+MCExHzAdBgNVBAMMFmV2X2ludF9yc2FfMjA0OC1ldnJvb3QwIhgPMjAxNTExMjgw
+MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowMDEuMCwGA1UEAwwlZXZfZWVfcnNhXzIw
+NDgtZXZfaW50X3JzYV8yMDQ4LWV2cm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODY
+H72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk
+27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A9
+0jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMM
+kd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaL
+L+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBhDCBgTBeBggrBgEFBQcB
+AQRSMFAwTgYIKwYBBQUHMAGGQmh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9l
+dl9lZV9yc2FfMjA0OC1ldl9pbnRfcnNhXzIwNDgtZXZyb290LzAfBgNVHSAEGDAW
+MBQGEisGAQQB60mFGoUahRoBg3QJATALBgkqhkiG9w0BAQsDggEBAH9rJ2oLLQfB
+e2pBzFw73x5QvhVbNl3O9gFTov/97zU8mfpdKoBjcf32d8/AvJ8qzCLve+4zlT5i
+6ZNwyxZpjb/dJpgZ35dbV9+qXI14m1604r4gcmpQjLDpjgAUUI15EvBkPmCmfVP2
+biIHTPGZZrcqjVh6uCs7UdBM/WtHC8Tn+cmUJZzj5kpmK0hNk26BsW+vsXXwias5
+SxR0oW1hKA4sCoqs9VByyMujiVjVivc1HzINRtiHYdQVlEPrUsYoKFh2zYS6oi6K
+wiFOzv6cLFv2j2TwBI8tD1LXjUBJA/fq8Q/8AOwZ/KUgjhz9ifV1d/FRKBqLT0Vs
+l/RXjR75s38=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem.certspec
new file mode 100644
index 000000000..0b34be6db
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ev_int_rsa_2048-evroot
+subject:ev_ee_rsa_2048-ev_int_rsa_2048-evroot
+extension:authorityInformationAccess:http://www.example.com:8888/ev_ee_rsa_2048-ev_int_rsa_2048-evroot/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040-evroot.pem b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040-evroot.pem
new file mode 100644
index 000000000..db935fd24
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040-evroot.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUDCCAjqgAwIBAgIUdSW9+f5SZzr700VP9vbhznUgRHMwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAhMR8wHQYDVQQDDBZldl9pbnRfcnNhXzIwNDAtZXZyb290MIIBITAN
+BgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQAAusBlL9+8AFWIL/uurO7Ij6LQg8KX
+3V1AZk3T2Q9S+aoCvYpQ+6FuD9mRh470dfmzUNn44+sqvXF84yewl4hTHxPfjj5O
+O51ha7ikHlMG7tJHIWMWEFEYASdqTrZvBzMbXLyLyucBao+bPU8qxFU8Ykz1JjvL
+NI6IQN5mEocJYKeSGRsTj7IX92XOx7/46U8Ws5QZv3UExZp+T3m9bRc+nHvz2dKk
+5zzBgLBZCnPVhPt/ybVPpURgflP8aFx6Vf1EqB1BQravUepvps6lKWWi6MXYTzyg
+JNb7ubAFuWUc5dny7PQO1ASYGp/8AmNuMRsJXGMyoMh9w5JxtVUUgXdLAgMBAAGj
+gZAwgY0wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwTwYIKwYBBQUHAQEEQzBB
+MD8GCCsGAQUFBzABhjNodHRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgvZXZfaW50
+X3JzYV8yMDQwLWV2cm9vdC8wHwYDVR0gBBgwFjAUBhIrBgEEAetJhRqFGoUaAYN0
+CQEwCwYJKoZIhvcNAQELA4IBAQAdKlRgP4yJ9q9zCdpE//xy6P9GnaT+yrmoM7CA
++sF9Jao0iM5EaF/VVYKg6sM/sBeG+RGgkIp7A3DfLXXR83a6EyXrhSLiEKOWi5xe
+WY2Q/CaRd4U05p5fvFsL88hY/Wvlj/mcCNLQ2GUYsdR/OL0XK1jHVTixGxRzRsN9
+mI+6rnA8swDZ2FTNLZ3DheNxsaIDYAZwpOaRLh6NTgbP0e0t3RvzV1dKvbXRv7QI
+HXV4KOdKAl5QMI43M4UhxSSszURZDxNRqlcyaVeNAenaiN3SiSng7HwVmb/jlpvp
+eEoXyl/+TEZebH2yniK/lzfVr3rcXm8own5V6ZHu/jucdZFT
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040-evroot.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040-evroot.pem.certspec
new file mode 100644
index 000000000..80be71174
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040-evroot.pem.certspec
@@ -0,0 +1,8 @@
+issuer:evroot
+subject:ev_int_rsa_2040-evroot
+issuerKey:ev
+subjectKey:rsa2040
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/ev_int_rsa_2040-evroot/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040.key b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040.key
new file mode 100644
index 000000000..e9010b691
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEtwIBADANBgkqhkiG9w0BAQEFAASCBKEwggSdAgEAAoIBAAC6wGUv37wAVYgv
++66s7siPotCDwpfdXUBmTdPZD1L5qgK9ilD7oW4P2ZGHjvR1+bNQ2fjj6yq9cXzj
+J7CXiFMfE9+OPk47nWFruKQeUwbu0kchYxYQURgBJ2pOtm8HMxtcvIvK5wFqj5s9
+TyrEVTxiTPUmO8s0johA3mYShwlgp5IZGxOPshf3Zc7Hv/jpTxazlBm/dQTFmn5P
+eb1tFz6ce/PZ0qTnPMGAsFkKc9WE+3/JtU+lRGB+U/xoXHpV/USoHUFCtq9R6m+m
+zqUpZaLoxdhPPKAk1vu5sAW5ZRzl2fLs9A7UBJgan/wCY24xGwlcYzKgyH3DknG1
+VRSBd0sCAwEAAQKB/2A9smffl1VcvthrjfNVA0ryjx638+eCnSObzCc6fHppoQvo
+8h8bbEsCxrrjcxwxWLW7/0YF9Xq3t7Kgy6LsAFottbHqbgrO6lvHRdzS0OnWuA1+
+sOorwIEnvONfpQxCzEEYcbpZHiO6ajhISjPv8TR/kH7ppakqIxG7C0NVEAIPeOO7
+AAmdtNEYKSgJZQX8uoTzyhI4/R66XuofORu7zFQksWgGP8F+HKbhkSzLpE+dApIw
+ih/tuAYSUps59Z0KP4GAtbogETIZf5OlgV3tk43459k8mxV2ZYjzObtZEAr9pJSn
+5FLX3UyaGc4uw6M6GLIPC02t4XK+4Z8m8Ny+QQKBgA7Dhpy5LUBsrd96MZqylEi8
+UFoFkTcHhzNh/FuYakmftl7rgVp+N2h9GfEoCHKJ2buIGOe8ylAsSQCtmuzhF5vh
+L/PkZ9YG/IIOqPB6yev/4iNuOBaEEgKIIj5C2+aN/ZcqhaZEflFpXyNNp5EcZ8mr
+lTHzPfO5lDLU7ojJpO+7AoGADKY5NFSehf6sjg9WBDA/0YSf6Ir0t/fhITKDu8ei
+wqUJ+Sc8Qoxo3j25PmFF8bQAvW1KJiYU6QQ602LU66SmuZU5nIk0o5mRIZnoQdjo
+2/8EifaeZjeWcwspgFMLMctwaVohYl6irczAnZMFFvqHIhGpHiLdif2et9qFdLci
+NbECgYANfTp14X9l+KZYpIXECVwQpPZpeeK3O8qc+O8hJT4frKxtR5H1g5LOhlb4
+jxJAzJDCllPjEAxtejjtRLFjsznl87bjiRISbGmzzv8uUZJCbZZJtv/KGrt10rou
+1tmiaqODxZc9ViFv8u25DM+Id0Kg8YOskslM8YdldkXHdy2a1wKBgAP1UBlMEX8k
+vqKFsgkFgDL0KYX/Vazr6IsW35o3UntOYdyRpo28mmRRNFKM5fJIvaKJPJbLe+ee
+5zmWx8Ild/bC95BAbzRyrbOyEbfpRJTzLFxvzAl4g5/kckwxsGMYokiVZ7T8oDN6
+yxuEEieqpfbHSACiMGkp8CzgOLrZQ99BAoGACAp9v6jCWEgUxxZkxW62LOTK8Wr+
+iNRJkVnWdHdKOj7N3xJWwC/JFSXFJ2kkItCrqU5cQe4S3HG7Zvhnn6F+CW8oCAhR
+ugRusxiFwUFOiYWt5ZnZB68XRT0cyuosDQZEP4Nnpr4VSxJeOQ7g2Q90bwiAHdP1
+Nn9Z+6LlpnwF83U=
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040.key.keyspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040.key.keyspec
new file mode 100644
index 000000000..f488e73a9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2040.key.keyspec
@@ -0,0 +1 @@
+rsa2040
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-ev_root_rsa_2040.pem b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-ev_root_rsa_2040.pem
new file mode 100644
index 000000000..3de3f13d0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-ev_root_rsa_2040.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbjCCAlmgAwIBAgIUAeu/QCFxArrPIMJNFvRH8DQpIB8wCwYJKoZIhvcNAQEL
+MBsxGTAXBgNVBAMMEGV2X3Jvb3RfcnNhXzIwNDAwIhgPMjAxNTExMjgwMDAwMDBa
+GA8yMDE4MDIwNTAwMDAwMFowKzEpMCcGA1UEAwwgZXZfaW50X3JzYV8yMDQ4LWV2
+X3Jvb3RfcnNhXzIwNDAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6
+iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr
+4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP
+8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OI
+Q+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ
+77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5J
+I/pyUcQx1QOs2hgKNe2NAgMBAAGjgZowgZcwDAYDVR0TBAUwAwEB/zALBgNVHQ8E
+BAMCAQYwWQYIKwYBBQUHAQEETTBLMEkGCCsGAQUFBzABhj1odHRwOi8vd3d3LmV4
+YW1wbGUuY29tOjg4ODgvZXZfaW50X3JzYV8yMDQ4LWV2X3Jvb3RfcnNhXzIwNDAv
+MB8GA1UdIAQYMBYwFAYSKwYBBAHrSYUahRqFGgGDdAkBMAsGCSqGSIb3DQEBCwOC
+AQAAGu+2My8IJ62el8ZSd8XObf5FZdc9mSKPDrUx9lbNfiYivNPW7IZ4G1Ku9ejt
+KCTlBGFYeiRX80lAmnn4uqjNFyr83P2iMnTGu4A602DdZHidnrNIoukyOlrO8ve8
+OiKZ2P42nb0+XRuMUSsfVo+MqegBQJSQx6NRoJZ9xsDA+58KLL/e7hZBE9IZocMd
+6IzGfGuu86CkfiJehlMFph0fkY9NaWVuthMzE8YJMOCZ6nb0ymHxKO+EqbliiyuI
+lvMR3i1WfDPF0YN4/YILt+72hFDqI8EvFYl9xqXkkOtkLVArVDMvhrdHWJOeV8n4
+5Lyiu5+Iy63klHNJxlfx7tWh
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-ev_root_rsa_2040.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-ev_root_rsa_2040.pem.certspec
new file mode 100644
index 000000000..5bc5674b2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-ev_root_rsa_2040.pem.certspec
@@ -0,0 +1,7 @@
+issuer:ev_root_rsa_2040
+subject:ev_int_rsa_2048-ev_root_rsa_2040
+issuerKey:evRSA2040
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/ev_int_rsa_2048-ev_root_rsa_2040/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-evroot.pem b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-evroot.pem
new file mode 100644
index 000000000..28ef9a63f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-evroot.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUTCCAjugAwIBAgIUIUhiWxj3v86Cc27pFN9+AFjY11owCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
+MDAwMDAwWjAhMR8wHQYDVQQDDBZldl9pbnRfcnNhXzIwNDgtZXZyb290MIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq
+5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SSc
+An7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39
+ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYk
+zBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3u
+JtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQAB
+o4GQMIGNMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGME8GCCsGAQUFBwEBBEMw
+QTA/BggrBgEFBQcwAYYzaHR0cDovL3d3dy5leGFtcGxlLmNvbTo4ODg4L2V2X2lu
+dF9yc2FfMjA0OC1ldnJvb3QvMB8GA1UdIAQYMBYwFAYSKwYBBAHrSYUahRqFGgGD
+dAkBMAsGCSqGSIb3DQEBCwOCAQEAkDJICQpDQGnSlRP4irr/shKc0CdSlp/Ub/zl
+pJ9g218t/mCjQKcWJakb2ClzFJq3FJvpLB9h1gy9b1bZ3sVtGW8DvFI0XRztmNXN
+3hNHQLAPr6oz9bl4OYUzbp7yYjMmkm1bnZQPhlQx5R8tIlFOZJP2vh98fUZSY9kh
+WWrqaUQNZckvGYvJLOa9fhxesrDYuY05WZH0E2JUC5V7v7gP7NvkW8/5yc/82af8
+xqNGWic+9+wmHA7J5PpW/owqKOe35WpQOclafg42XH/3qT5bLms6+X2iV3Ys3SuB
+qmFU9n5zMCvDn4r4sPSYuaq8q3QNTNcT4inos++rfHtFyjWhjQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-evroot.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-evroot.pem.certspec
new file mode 100644
index 000000000..a0cb6250d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048-evroot.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:ev_int_rsa_2048-evroot
+issuerKey:ev
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/ev_int_rsa_2048-evroot/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048.key b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048.key
new file mode 100644
index 000000000..8af23e068
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAECggEBAJ7LzjhhpFTsseD+j4XdQ8kvWCXOLpl4hNDhqUnaosWs
+VZskBFDlrJ/gw+McDu+mUlpl8MIhlABO4atGPd6e6CKHzJPnRqkZKcXmrD2IdT9s
+JbpZeec+XY+yOREaPNq4pLDN9fnKsF8SM6ODNcZLVWBSXn47kq18dQTPHcfLAFeI
+r8vh6Pld90AqFRUw1YCDRoZOs3CqeZVqWHhiy1M3kTB/cNkcltItABppAJuSPGgz
+iMnzbLm16+ZDAgQceNkIIGuHAJy4yrrK09vbJ5L7kRss9NtmA1hb6a4Mo7jmQXqg
+SwbkcOoaO1gcoDpngckxW2KzDmAR8iRyWUbuxXxtlEECgYEA3W4dT//r9o2InE0R
+TNqqnKpjpZN0KGyKXCmnF7umA3VkTVyqZ0xLi8cyY1hkYiDkVQ12CKwn1Vttt0+N
+gSfvj6CQmLaRR94GVXNEfhg9Iv59iFrOtRPZWB3V4HwakPXOCHneExNx7O/JznLp
+xD3BJ9I4GQ3oEXc8pdGTAfSMdCsCgYEA16dz2evDgKdn0v7Ak0rU6LVmckB3Gs3r
+ta15b0eP7E1FmF77yVMpaCicjYkQL63yHzTi3UlA66jAnW0fFtzClyl3TEMnXpJR
+3b5JCeH9O/Hkvt9Go5uLODMo70rjuVuS8gcK8myefFybWH/t3gXo59hspXiG+xZY
+EKd7mEW8MScCgYEAlkcrQaYQwK3hryJmwWAONnE1W6QtS1oOtOnX6zWBQAul3RMs
+2xpekyjHu8C7sBVeoZKXLt+X0SdR2Pz2rlcqMLHqMJqHEt1OMyQdse5FX8CT9byb
+WS11bmYhR08ywHryL7J100B5KzK6JZC7smGu+5WiWO6lN2VTFb6cJNGRmS0CgYAo
+tFCnp1qFZBOyvab3pj49lk+57PUOOCPvbMjo+ibuQT+LnRIFVA8Su+egx2got7pl
+rYPMpND+KiIBFOGzXQPVqFv+Jwa9UPzmz83VcbRspiG47UfWBbvnZbCqSgZlrCU2
+TaIBVAMuEgS4VZ0+NPtbF3yaVv+TUQpaSmKHwVHeLQKBgCgGe5NVgB0u9S36ltit
+tYlnPPjuipxv9yruq+nva+WKT0q/BfeIlH3IUf2qNFQhR6caJGv7BU7naqNGq80m
+ks/J5ExR5vBpxzXgc7oBn2pyFJYckbJoccrqv48GRBigJpDjmo1f8wZ7fNt/ULH1
+NBinA5ZsT8d0v3QCr2xDJH9D
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048.key.keyspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048.key.keyspec
new file mode 100644
index 000000000..4ad96d515
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_int_rsa_2048.key.keyspec
@@ -0,0 +1 @@
+default
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.key b/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.key
new file mode 100644
index 000000000..bb8708bfd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEuQIBADANBgkqhkiG9w0BAQEFAASCBKMwggSfAgEAAoIBAADKcCDcIV9XkU00
+P65KAVERaXr5l6Xs6RhmSZ/CPxuIoRjL0wsQ2Rx7mg1O6JcvyuVsr1fyX8EnWipN
+vLmCQowy71h78jh0EDMKD/sWuAKb14OWnvZ19t44wY9nGTy2wHL4sj0LM3QRJiel
+e5AFV3HZ5iYD9TeI1/Y6+nJPXRCAlt8x+J8msetffENXmA4Aj81V2CfdJiOVyi9S
+ageJfMQMWTs4cW68DKpZZxnG8prJtzp6lEdIo6o+CenrTUYeoAJ+VAkmYUcoudJD
+l1z5oFQb79JedrUflREQsOdkT8fjhEF5G20iJzhMuABOIzQjcrHPXMPnPjG3u++h
+YOaGLrsCAwEAAQKCAQAAstt0vOkjYqv3KVWmOK6HILowM7t/lxyvORiNdULqocGr
+tdIFseIRH0eRwIkRouFB6M/XBUcC0jEAtWQsBuGjGxGK/R+aLzlsztQlxQHZFDXK
+hlZ2bO0rk7u4Zp/Om6zXJ9Hayz2vq8MpPjU4nu+OoLWOGusaIOamH5/NRT91Z/4x
+0SO2FqJv703x1sn3SQER0Cju/R2XIEWxokInPdemfr8RHbJ0GlqTx7IonMSiNvWp
+mm7HqCBv2uHB0EvbsZgNSimMWhfa5BhkdKX3g12IK87ySu9O1vFJ+U2WyffXjmR/
+x3ipAX/yCNO0oXaLGCFiECzasDL6u6s41SAKMkZJAoGADzhE0NTU1qIazXam/DcL
+hVDh1+xaYjQXLnkPACmuZR9tXFkzCrGYArnXogfeeh+3eON3T9vcQRdQYz2NGz/g
+dQBv/P0dEOdjx6kifS1fDC2t4cnmWcNQoVnTa7mG8SY21PmUKyiLwP4h2oeZR3Fz
+FEJJyi44nmxcJap4yMrX1N8CgYANTQvt0ZYvB6Hq1rI6TtZ66vEnDwUqbSm6B0lF
+xjYaXE+PB7+FngZ67T9ObjI+8qqKas00CwvcfP5P0ynjyX+HDH93NXksaqnQ9+dU
+KijtbwGw5VorjZwkplxtoxTJVIT1x8OVSoG7AWsH7RfumwYDlpW8oFmnn43CQj0y
+jVJlpQKBgAnymi/wW+ipbWFLoxsIk1QgqGxrxCuZpmkuoNpXY/AeWWlZt93Oc++c
+Lk9uW0BxCIdQDUS6DDzTEyy6J0dfOcLfdVLi0SOiSXpPlwZAKHaaSKNiRlf3K/U5
+89DeI0/szTvooKqQxr9umwvtQwcKJNBh/z7RdRo+8v9/a5C529X7AoGAAaZZ4XDK
+wSCgO+HPj53xyqNTsDWTvXR25YU72HTChziGAcbDQc6dHShKXu8aOmadMrgWpers
+2LeET+BwZLm8oMKzGNVAJ3s/fxUQ04a7NuA7BHceXSKeiIk+E7dTv7lFGLtjjiQE
+vW5qmTwWaNk/wLgv8IqvNDR9P+g5cQjIfKUCgYAEAlfA1KIcC5hDKXxlZS22YwT7
+Jjdz1yi2q/oG03rAymLGKAI+CeN9wKkB5M4SJBgOJYKjqktqGnuY4r1wB3rsFKyK
+tmp1XHHg/BAkcfm7wbRqlaoLZF8sOOdkUCiWGeo/XormEDe//PgknyKqTnbioBkJ
+8/6ykM6T7fV7EOvnlg==
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.key.keyspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.key.keyspec
new file mode 100644
index 000000000..a85e16858
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.key.keyspec
@@ -0,0 +1 @@
+evRSA2040
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.pem b/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.pem
new file mode 100644
index 000000000..e8640696e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3zCCAcqgAwIBAgIUP1iIBgxk6kH+x64EUBTV3qoHuaswCwYJKoZIhvcNAQEL
+MBsxGTAXBgNVBAMMEGV2X3Jvb3RfcnNhXzIwNDAwIhgPMjAxNTAxMDEwMDAwMDBa
+GA8yMDM1MDEwMTAwMDAwMFowGzEZMBcGA1UEAwwQZXZfcm9vdF9yc2FfMjA0MDCC
+ASEwDQYJKoZIhvcNAQEBBQADggEOADCCAQkCggEAAMpwINwhX1eRTTQ/rkoBURFp
+evmXpezpGGZJn8I/G4ihGMvTCxDZHHuaDU7oly/K5WyvV/JfwSdaKk28uYJCjDLv
+WHvyOHQQMwoP+xa4ApvXg5ae9nX23jjBj2cZPLbAcviyPQszdBEmJ6V7kAVXcdnm
+JgP1N4jX9jr6ck9dEICW3zH4nyax6198Q1eYDgCPzVXYJ90mI5XKL1JqB4l8xAxZ
+OzhxbrwMqllnGcbymsm3OnqUR0ijqj4J6etNRh6gAn5UCSZhRyi50kOXXPmgVBvv
+0l52tR+VERCw52RPx+OEQXkbbSInOEy4AE4jNCNysc9cw+c+Mbe776Fg5oYuuwID
+AQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjALBgkqhkiG9w0BAQsD
+ggEAAKNwPHDMqBevLghX34q3XuZSQuR4ZTmYBA/f79+1eGM9ljJFyVVYNPPu8a1u
+ePKCZrsrc7H8PqQTyg87XlLi9gwkERZqL1DDKI9LQEf7AK7eA1fgpabc4b/YARQf
+06bd+bRMUjEf5ZS0DaGib3GgOC4HU9L9tFfvxLI0CyZkQQoMcWWNEd0iQEp+0hBX
+Pt8avMmO7IrAkcXroLBYtFdU0nf3OQlCBAHMOupWo/cguPoQO62+dVgz5O/msMQk
+tYpgwH126xnWGP5+pjHmjssycbBLOJgCU2gvQa8aGM7tFvAUGiflsQIGgx8c9aBG
+jhTdA+xV2I+gY8rv98s2Dr5gMQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.pem.certspec
new file mode 100644
index 000000000..fd1ade8de
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/ev_root_rsa_2040.pem.certspec
@@ -0,0 +1,7 @@
+issuer:ev_root_rsa_2040
+subject:ev_root_rsa_2040
+issuerKey:evRSA2040
+subjectKey:evRSA2040
+validity:20150101-20350101
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/evroot.key b/security/manager/ssl/tests/unit/test_keysize_ev/evroot.key
new file mode 100644
index 000000000..a756a0705
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/evroot.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC1SYlcnQAQjRGh
++Z+HqePRpdtd+uzxiNpXv2QTaI8s5HIs/xCQOMF0Ask6Kkc9vShq7T/c02PPWikU
+dwG92BjXYVv5NWvV08gzaqqMCXE2igbDzURhuT5RQk4XRLsuqtRqqzjOGWghlh+H
+cUoWY2k/CXYc301roSXqzse+Jw04j3ifbN94rjFE7SjEXnkpOGOnoipImAo2pA5y
+1XnJuSXf+MeTNi/9aJenwXVMXpfJZ8Pq3RquiqLMzjSKAWm4Diii1wwalgxvM18t
+oJubZD9av7pJ6Kqpgelg4n2HSAvdVd2UF/oYUJ+7VUzPgaQ5fouoEoo0vfJ4ZcGJ
+5XNPsikFAgMBAAECggEBAJg9VPlNb0x26yPW+T14UjUwz3Ow0WJUxueBdo1F9VaB
+0dAvsr0qrGq8HDiYYJNcUqDY9BSCAQOUd4MUHYZL/zCANjilwBUlcK6dGPPYyhY+
++0dbDd3zLn4W7HVl5rteAlxBxcZuV6A87eVUIh+DBFNHosTEUcPc5Ha3h84MBXJE
+vp4E7xMRjbuz1eCmzIcCnq/Upp7ZsUdZsV452KmITlb1TS+asBPw0V8xipq2svc9
+HsPJ/idK6JQxoQZAvniZsAEcXlCToYNHCGid4QBjTaveYPvWqu+joz3zSh829gwE
+MDa3SNHJ7pjEAxoK/sYO/aCpkL5ST1YU6sT9s0pS+VECgYEA6twssz5f8co3a72V
+vWoXd9LPT6xHVF6S0RpiCbnV5N7UeDRYHBabPIhHQqCeoYdQXBylVBTY0ltJdjLV
+7CqqBSM0MPrUmJJ3en1o4Dj1YaO4lp5gsKJj3vv9pIqbD/OdlbyIsVJnyK3pe1EH
+lI5B5DMknYf32xCdXXRYTYa8wdcCgYEAxZrldqIWRwJI2USlW56b+TKZ2jQexW5V
+jrqCGrzhv1e3nPQR0pBMd0+duh8VGF9gewV0oIIF1uwotmo21jQjLqry/qN1Yauv
+nWRLaNs4yZZMuMluwKxh66ZNBbRGVC9COXb1rN5OzJVTbS31eJVPk/DP2cWPt4ui
+p23VrChNyIMCgYEAwdLvOQYzHFKspkgR+f5CW+somDIvs9tRAyzo1+n8MiQL6SAZ
+zySA/NXjKYNxJxGLKlmhv+BsiD46REfz8DHNmuvQuNNo/Hl0DSzOjq2zJN9/CR6v
+4VZDYdVJILAbBHEjDl5H2T+O0zljxRe8T8ePbYsfnrqFvM7bcDMCZQjbYoUCgYEA
+hSG421aU376ASjFfnvybZSdcVJCs8qNFbWXm5hC/n2R/xnUB1PV3LyMqxwzN75/C
+pt+kFcfEG2r8evnQfDygP37ZPAnwuZ8sMEQ0Mi8QcXCbvBuqTJFXX6apWeB9SZaV
+bZXiK1eTi25HyNUf/t/Jv4iM4NGj5CtlqJvtS5HT5fUCgYEA3El7BrkgyL4LAHe3
+mOl37vdEqQ7Cxdfmy7IkSPrHLagaMxgODYoC6DFGDH/H/TphL3uZMLYbeZ+OkI5j
+LpugQJtqpwsDo7p4dCYmO1vVhD34R27bXRT2qGE+uvW5zVykL1+9KALgjk5J5XCf
+UVFRDKpassHG6z7+kpXRbowlyRY=
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/evroot.key.keyspec b/security/manager/ssl/tests/unit/test_keysize_ev/evroot.key.keyspec
new file mode 100644
index 000000000..1a3d76a55
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/evroot.key.keyspec
@@ -0,0 +1 @@
+ev
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/evroot.pem b/security/manager/ssl/tests/unit/test_keysize_ev/evroot.pem
new file mode 100644
index 000000000..cd2fd7ed8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/evroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUW9j5PS8YoKgynZdYa9i2Kwexnp8wCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MDEwMTAwMDAwMFoYDzIwMzUwMTAx
+MDAwMDAwWjARMQ8wDQYDVQQDDAZldnJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC1SYlcnQAQjRGh+Z+HqePRpdtd+uzxiNpXv2QTaI8s5HIs/xCQ
+OMF0Ask6Kkc9vShq7T/c02PPWikUdwG92BjXYVv5NWvV08gzaqqMCXE2igbDzURh
+uT5RQk4XRLsuqtRqqzjOGWghlh+HcUoWY2k/CXYc301roSXqzse+Jw04j3ifbN94
+rjFE7SjEXnkpOGOnoipImAo2pA5y1XnJuSXf+MeTNi/9aJenwXVMXpfJZ8Pq3Rqu
+iqLMzjSKAWm4Diii1wwalgxvM18toJubZD9av7pJ6Kqpgelg4n2HSAvdVd2UF/oY
+UJ+7VUzPgaQ5fouoEoo0vfJ4ZcGJ5XNPsikFAgMBAAGjHTAbMAwGA1UdEwQFMAMB
+Af8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAO1EZ134zXCiYSMixYSVP
+gAXWdR8zvaeS8UF0Xihle6nBdtkcmhiMgxXecMv7P7xO/U/wz5NAyJ1cvqaxrPbn
+8bekVCCsAAae6mVJIsVeuLtg3f89Qmx6KF6By2NI5R/AX5gxs0V9Tvjp9NfpIWh9
+I0BO0/REmq+CxKWjO6Loq0JA/QRW1jnD3XLitJ9QiCfnLqgUAG8JnkhG/JtpcJC3
+91SluwhVw+8i7caDOgHZGvjBEycyje0iyDLybaVjv2PpyuQx8H6hDzTGd2bNDl22
+fZ0FsOYCH6TJPx7nsCJCQ8/jGsRAGPxbItwSpTQJegKVaJ9s2dOAreJdkQFSIEo+
+3g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/evroot.pem.certspec b/security/manager/ssl/tests/unit/test_keysize_ev/evroot.pem.certspec
new file mode 100644
index 000000000..3121f3486
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/evroot.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:evroot
+subjectKey:ev
+issuerKey:ev
+validity:20150101-20350101
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_keysize_ev/moz.build b/security/manager/ssl/tests/unit/test_keysize_ev/moz.build
new file mode 100644
index 000000000..85dc78a3c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_keysize_ev/moz.build
@@ -0,0 +1,31 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ev_ee_rsa_2040-ev_int_rsa_2048-evroot.pem',
+# 'ev_ee_rsa_2048-ev_int_rsa_2040-evroot.pem',
+# 'ev_ee_rsa_2048-ev_int_rsa_2048-ev_root_rsa_2040.pem',
+# 'ev_ee_rsa_2048-ev_int_rsa_2048-evroot.pem',
+# 'ev_int_rsa_2040-evroot.pem',
+# 'ev_int_rsa_2048-ev_root_rsa_2040.pem',
+# 'ev_int_rsa_2048-evroot.pem',
+# 'ev_root_rsa_2040.pem',
+# 'evroot.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
+#
+#test_keys = (
+# 'ev_int_rsa_2040.key',
+# 'ev_int_rsa_2048.key',
+# 'ev_root_rsa_2040.key',
+# 'evroot.key',
+#)
+#
+#for test_key in test_keys:
+# GeneratedTestKey(test_key)
diff --git a/security/manager/ssl/tests/unit/test_local_cert.js b/security/manager/ssl/tests/unit/test_local_cert.js
new file mode 100644
index 000000000..937c0432b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_local_cert.js
@@ -0,0 +1,83 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const certService = Cc["@mozilla.org/security/local-cert-service;1"]
+ .getService(Ci.nsILocalCertService);
+
+const gNickname = "local-cert-test";
+
+function run_test() {
+ // Need profile dir to store the key / cert
+ do_get_profile();
+ // Ensure PSM is initialized
+ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+ run_next_test();
+}
+
+function getOrCreateCert(nickname) {
+ return new Promise((resolve, reject) => {
+ certService.getOrCreateCert(nickname, {
+ handleCert: function(c, rv) {
+ if (rv) {
+ reject(rv);
+ return;
+ }
+ resolve(c);
+ }
+ });
+ });
+}
+
+function removeCert(nickname) {
+ return new Promise((resolve, reject) => {
+ certService.removeCert(nickname, {
+ handleResult: function(rv) {
+ if (rv) {
+ reject(rv);
+ return;
+ }
+ resolve();
+ }
+ });
+ });
+}
+
+add_task(function* () {
+ // No master password, so no prompt required here
+ ok(!certService.loginPromptRequired);
+
+ let certA = yield getOrCreateCert(gNickname);
+ equal(certA.nickname, gNickname);
+
+ // Getting again should give the same cert
+ let certB = yield getOrCreateCert(gNickname);
+ equal(certB.nickname, gNickname);
+
+ // Should be matching instances
+ ok(certA.equals(certB));
+
+ // Check a few expected attributes
+ ok(certA.isSelfSigned);
+ equal(certA.certType, Ci.nsIX509Cert.USER_CERT);
+
+ // New nickname should give a different cert
+ let diffNameCert = yield getOrCreateCert("cool-stuff");
+ ok(!diffNameCert.equals(certA));
+
+ // Remove the cert, and get a new one again
+ yield removeCert(gNickname);
+ let newCert = yield getOrCreateCert(gNickname);
+ ok(!newCert.equals(certA));
+
+ // Drop all cert references and GC
+ let serial = newCert.serialNumber;
+ certA = certB = diffNameCert = newCert = null;
+ Cu.forceGC();
+ Cu.forceCC();
+
+ // Should still get the same cert back
+ let certAfterGC = yield getOrCreateCert(gNickname);
+ equal(certAfterGC.serialNumber, serial);
+});
diff --git a/security/manager/ssl/tests/unit/test_logoutAndTeardown.js b/security/manager/ssl/tests/unit/test_logoutAndTeardown.js
new file mode 100644
index 000000000..2bf8855fe
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_logoutAndTeardown.js
@@ -0,0 +1,55 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+do_get_profile();
+
+function connect_and_teardown() {
+ let socketTransportService =
+ Cc["@mozilla.org/network/socket-transport-service;1"]
+ .getService(Ci.nsISocketTransportService);
+
+ let tearDown = false;
+
+ let reader = {
+ onInputStreamReady: function(stream) {
+ throws(() => stream.available(), /NS_ERROR_FAILURE/,
+ "stream should be in an error state");
+ ok(tearDown, "A tear down attempt should have occurred");
+ run_next_test();
+ }
+ };
+
+ let sink = {
+ onTransportStatus: function(transport, status, progress, progressmax) {
+ if (status == Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
+ // Try to logout and tear down the secure decoder ring.
+ // This should close and stream and notify the reader.
+ // The test will time out if this fails.
+ tearDown = true;
+ Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing)
+ .logoutAndTeardown();
+ }
+ }
+ };
+
+ Services.prefs.setCharPref("network.dns.localDomains",
+ "ocsp-stapling-none.example.com");
+ let transport = socketTransportService.createTransport(
+ ["ssl"], 1, "ocsp-stapling-none.example.com", 8443, null);
+ transport.setEventSink(sink, Services.tm.currentThread);
+
+ let inStream = transport.openInputStream(0, 0, 0)
+ .QueryInterface(Ci.nsIAsyncInputStream);
+ inStream.asyncWait(reader, Ci.nsIAsyncInputStream.WAIT_CLOSURE_ONLY, 0,
+ Services.tm.currentThread);
+}
+
+function run_test() {
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+ add_test(connect_and_teardown);
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_name_constraints.js b/security/manager/ssl/tests/unit/test_name_constraints.js
new file mode 100644
index 000000000..e75c89740
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints.js
@@ -0,0 +1,63 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+// This test tests two specific items:
+// 1. Are name constraints properly enforced across the entire constructed
+// certificate chain? This makes use of a certificate hierarchy like so:
+// - (trusted) root CA with permitted subtree dNSName example.com
+// - intermediate CA with permitted subtree dNSName example.org
+// a. end-entity with dNSNames example.com and example.org
+// (the first entry is allowed by the root but not by the intermediate,
+// and the second entry is allowed by the intermediate but not by the
+// root)
+// b. end-entity with dNSName example.com (not allowed by the intermediate)
+// c. end-entity with dNSName examle.org (not allowed by the root)
+// d. end-entity with dNSName example.test (not allowed by either)
+// All of these cases should fail to verify with the error that the
+// end-entity is not in the name space permitted by the hierarchy.
+//
+// 2. Are externally-imposed name constraints properly enforced? This makes use
+// of a certificate hierarchy rooted by a certificate with the same DN as an
+// existing hierarchy that has externally-imposed name constraints (DCISS).
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function certFromFile(name) {
+ return constructCertFromFile(`test_name_constraints/${name}.pem`);
+}
+
+function loadCertWithTrust(certName, trustString) {
+ addCertFromFile(certdb, `test_name_constraints/${certName}.pem`,
+ trustString);
+}
+
+function checkCertNotInNameSpace(cert) {
+ checkCertErrorGeneric(certdb, cert, SEC_ERROR_CERT_NOT_IN_NAME_SPACE,
+ certificateUsageSSLServer);
+}
+
+function checkCertInNameSpace(cert) {
+ checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess,
+ certificateUsageSSLServer);
+}
+
+function run_test() {
+ // Test that name constraints from the entire certificate chain are enforced.
+ loadCertWithTrust("ca-example-com-permitted", "CTu,,");
+ loadCertWithTrust("int-example-org-permitted", ",,");
+ checkCertNotInNameSpace(certFromFile("ee-example-com-and-org"));
+ checkCertNotInNameSpace(certFromFile("ee-example-com"));
+ checkCertNotInNameSpace(certFromFile("ee-example-org"));
+ checkCertNotInNameSpace(certFromFile("ee-example-test"));
+
+ // Test that externally-imposed name constraints are enforced (DCISS tests).
+ loadCertWithTrust("dciss", "CTu,,");
+ checkCertInNameSpace(certFromFile("NameConstraints.dcissallowed"));
+ checkCertNotInNameSpace(certFromFile("NameConstraints.dcissblocked"));
+}
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissallowed.pem b/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissallowed.pem
new file mode 100644
index 000000000..9eb316736
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissallowed.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAj2gAwIBAgIUayXt32lO6eul4Qcp7fVRAg5vETEwCwYJKoZIhvcNAQEL
+MIGFMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJp
+czEQMA4GA1UEChMHUE0vU0dETjEOMAwGA1UECxMFRENTU0kxDjAMBgNVBAMTBUlH
+Qy9BMSMwIQYJKoZIhvcNAQkBFhRpZ2NhQHNnZG4ucG0uZ291di5mcjAiGA8yMDE1
+MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjBBMQswCQYDVQQGEwJVUzELMAkG
+A1UECAwCQ0ExDDAKBgNVBAoMA0ZvbzEXMBUGA1UEAwwOZm9vLmV4YW1wbGUuZnIw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ
+PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH
+9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw
+4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86
+exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0
+ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N
+AgMBAAEwCwYJKoZIhvcNAQELA4IBAQBUTnm4u9mzMIaSUdrQ+pSM0dtQAP/7b93e
+/fpICLB65fjxUxQMvRG65i4vn6HG+FFbDi/n/kURSN8r1VItjq+QUK55VL/F7bh7
+6P9xi4o1h6qb4tiXKb3YE2D7+zRENWGvTidDV1u3e2Tfuu0pu0NkD5PUvb0dtScW
+LvruBaJdRJgx9z1BIYN5uqQhOa4hHV46z7hAVyJyhsdwRO3NG/OYFmdlcIUTwcvF
+Qb+YgeviFlLdqRqt4vxT54Ko3GGqx2l609PZslD3F9vcP31n/VbowU256HSTjral
+DL9dS/KG2XFWySC9vrFjyLx8eR9SOMfasCIG835f81YI2E7UjGBH
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissallowed.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissallowed.pem.certspec
new file mode 100644
index 000000000..1a02a0cc1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissallowed.pem.certspec
@@ -0,0 +1,2 @@
+issuer:printableString/C=FR/ST=France/L=Paris/O=PM/SGDN/OU=DCSSI/CN=IGC/A/emailAddress=igca@sgdn.pm.gouv.fr
+subject:/C=US/ST=CA/O=Foo/CN=foo.example.fr
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissblocked.pem b/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissblocked.pem
new file mode 100644
index 000000000..044a8205d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissblocked.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAj6gAwIBAgIUB0a84yh5MqyYUB0tMRJgU70UqzEwCwYJKoZIhvcNAQEL
+MIGFMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJp
+czEQMA4GA1UEChMHUE0vU0dETjEOMAwGA1UECxMFRENTU0kxDjAMBgNVBAMTBUlH
+Qy9BMSMwIQYJKoZIhvcNAQkBFhRpZ2NhQHNnZG4ucG0uZ291di5mcjAiGA8yMDE1
+MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjBCMQswCQYDVQQGEwJVUzELMAkG
+A1UECAwCQ0ExDDAKBgNVBAoMA0ZvbzEYMBYGA1UEAwwPZm9vLmV4YW1wbGUuY29t
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2
+ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdF
+h/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6n
+cOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAv
+OnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2nj
+tIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXt
+jQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAmvWg9zOGlCX5ZjPFoX0wpfQ2pSAPsbv9
+sC4uDLBQj6Tx/bmm5JRI3p/+hceC+y5gVmA30dOBVAGm9Bzj/M7tY1+eYH9fXnhO
+asM3onOEAd7R26Dztl3/RaKIZzIDALc/0fOeCHfRKmh5Ao/9MHIBH8vyyCvyHRZV
+ixaX5zhSA6u8PrC36Hwbu40LNaVgV/S7xWiE5bAOT4zhS61C+Sjji0wmK9vgEgCT
+8e3UFCWEGgr6zavD0E5dvZIbyM8q8TMdTe5FDV9e1Jivk2WcDli39eYiOhyglqaF
+PZ4pRuvNO2+2VJxakjzfrTeQA7k/ZWX6ljwFSMypgEm/m7HC8BQ7qQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissblocked.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissblocked.pem.certspec
new file mode 100644
index 000000000..eabee87e8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/NameConstraints.dcissblocked.pem.certspec
@@ -0,0 +1,2 @@
+issuer:printableString/C=FR/ST=France/L=Paris/O=PM/SGDN/OU=DCSSI/CN=IGC/A/emailAddress=igca@sgdn.pm.gouv.fr
+subject:/C=US/ST=CA/O=Foo/CN=foo.example.com
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ca-example-com-permitted.pem b/security/manager/ssl/tests/unit/test_name_constraints/ca-example-com-permitted.pem
new file mode 100644
index 000000000..a82688fd8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ca-example-com-permitted.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDTCCAfegAwIBAgIUadTGcLSWi68lBexbnxxJdH4o7S4wCwYJKoZIhvcNAQEL
+MCMxITAfBgNVBAMMGGNhLWV4YW1wbGUtY29tLXBlcm1pdHRlZDAiGA8yMDE1MTEy
+ODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAjMSEwHwYDVQQDDBhjYS1leGFtcGxl
+LWNvbS1wZXJtaXR0ZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6
+iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr
+4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP
+8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OI
+Q+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ
+77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5J
+I/pyUcQx1QOs2hgKNe2NAgMBAAGjOTA3MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQD
+AgEGMBoGA1UdHgQTMBGgDzANggtleGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEB
+ABqsSZFz9PEgN6+qyElJbM3P/NEy4HSfNOybDbKspySnBlYC9cZXgY3EJ0FSeKSQ
+hDM9CvMKtAhTJjj9PDQHnh0jevD0USO6riqkkENo+c3tL8cAZbLT8oPe4Q52PRii
+Yqi4XZiigtQmLxdyS4ryuSvhRs0IcNDqp7f23uLgGQpv7GUpoc4hg14JxIW1Bz42
+x60m+jTVMkpHj01uUJ9J4bTDoxLjjPI6ED/lXaccJCpl3smMPErEKM3K6LBfL6g7
+r+IkdTAhsQmPgnhi07SSV34ZXto8cpjSpJDl3LKBUmHF82XqJNHxwYZ7VjwnSc5c
+9sw3hmmmt7Su7dEeScCKPW0=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ca-example-com-permitted.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/ca-example-com-permitted.pem.certspec
new file mode 100644
index 000000000..1cc3c1d81
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ca-example-com-permitted.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca-example-com-permitted
+subject:ca-example-com-permitted
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:nameConstraints:permitted:example.com
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/dciss.pem b/security/manager/ssl/tests/unit/test_name_constraints/dciss.pem
new file mode 100644
index 000000000..2d8fc903a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/dciss.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAqGgAwIBAgIUfbbH+o/snQqIZa44UsC8vi+3+EgwCwYJKoZIhvcNAQEL
+MIGFMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJp
+czEQMA4GA1UEChMHUE0vU0dETjEOMAwGA1UECxMFRENTU0kxDjAMBgNVBAMTBUlH
+Qy9BMSMwIQYJKoZIhvcNAQkBFhRpZ2NhQHNnZG4ucG0uZ291di5mcjAiGA8yMDE1
+MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjCBhTELMAkGA1UEBhMCRlIxDzAN
+BgNVBAgTBkZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoTB1BNL1NHRE4x
+DjAMBgNVBAsTBURDU1NJMQ4wDAYDVQQDEwVJR0MvQTEjMCEGCSqGSIb3DQEJARYU
+aWdjYUBzZ2RuLnBtLmdvdXYuZnIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwG
+m24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJr
+bA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4
+SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3
+/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+Z
+FzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYD
+VR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAHyAZhHXZ7L+pJAMKXiMpxLf+bt8w
+3EfZ+y7htjiDsDLLB9T3A/zj0V2LlVGJ8RfQOT690czYqidFL7bQayJuC5S1MBxt
+Q6W0GsHHVR2v/uCPFntzVhKFSeGyao+V2t/ZTYQ4MIiZTRkK0QWGL2XFGjRhfGMf
+6WDBjnndyVg0fXnvlYTCfZFp7yZ9pkdS3kgLTfq4PAknm9eU/bJ+DjHedGb6GWY3
+X0+xXw2u6Td1UdupliEOX6mGC7P3E6g8Dmrxn36OiKeh3kHmVIyyUrpLI/XM67B8
+9RG2d7e8gBlKKSwcwynM/snRco9AWgiaSZEmmb2a9+FQ/qGwtZVwvgkAuQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/dciss.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/dciss.pem.certspec
new file mode 100644
index 000000000..5d53706bc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/dciss.pem.certspec
@@ -0,0 +1,4 @@
+issuer:printableString/C=FR/ST=France/L=Paris/O=PM/SGDN/OU=DCSSI/CN=IGC/A/emailAddress=igca@sgdn.pm.gouv.fr
+subject:printableString/C=FR/ST=France/L=Paris/O=PM/SGDN/OU=DCSSI/CN=IGC/A/emailAddress=igca@sgdn.pm.gouv.fr
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com-and-org.pem b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com-and-org.pem
new file mode 100644
index 000000000..d0442e004
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com-and-org.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC+jCCAeSgAwIBAgIUaRmgL0d90KT16jbz/DDS4TvGvwEwCwYJKoZIhvcNAQEL
+MCQxIjAgBgNVBAMMGWludC1leGFtcGxlLW9yZy1wZXJtaXR0ZWQwIhgPMjAxNTEx
+MjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowITEfMB0GA1UEAwwWZWUtZXhhbXBs
+ZS1jb20tYW5kLW9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqI
+UahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvi
+r1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/x
+fq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD
+7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnv
+uRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj
++nJRxDHVA6zaGAo17Y0CAwEAAaMnMCUwIwYDVR0RBBwwGoILZXhhbXBsZS5jb22C
+C2V4YW1wbGUub3JnMAsGCSqGSIb3DQEBCwOCAQEAnnaFdrE6UGQCmCtMEhHicq9Y
+NE/TGItWvGqP+iU/7+fpTRF5TvrB9mieRPZgU2FQPbHbVs4f3Akaiv7gwnBdE6+d
+HL0v7qoVSGofmZh9GbE+i3kqXSyylOFhjCuQ92+5lMIQ/hxumyUuQSfw/SRs5I2c
+l7otGokpxOqRfw9oFusF1AccSm0ynVbdanjfMZFBc0Hwfy4qYXGqP1AmiNJgjves
+MEjCfwsoFv4Y23CSdTBduo5P6JzLS2Ay99NTG1UOto+UIDSZwIylSjphc0XOMJ2+
+TbbCo9XHmhWN8i9xw0anSOXvz66yWFBbtuvjPweHAOoSWsqdQ5GoReoqqF5xSw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com-and-org.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com-and-org.pem.certspec
new file mode 100644
index 000000000..904ca6595
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com-and-org.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int-example-org-permitted
+subject:ee-example-com-and-org
+extension:subjectAlternativeName:example.com,example.org
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com.pem b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com.pem
new file mode 100644
index 000000000..fad336b1c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5TCCAc+gAwIBAgIUGQSGboQn0O+dvd3cf/FaobEeoiEwCwYJKoZIhvcNAQEL
+MCQxIjAgBgNVBAMMGWludC1leGFtcGxlLW9yZy1wZXJtaXR0ZWQwIhgPMjAxNTEx
+MjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowGTEXMBUGA1UEAwwOZWUtZXhhbXBs
+ZS1jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAGjGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMAsGCSqGSIb3
+DQEBCwOCAQEAP24kpBxa9l3+LpfmIc4UsSpXvY+DGt5bjM0TzuNHR6FMQhLnYdF1
+0Lbl6TYFd62kA2GANMGkLImIGJCP9XEEJYF0lQQ3w06rofsnEVbrraF0UjhyMSdt
++IBWwn/ZD37/D2iYUXInEWLNsiTe/ggrfk4VCy48l40toW0CdW0xTorYHrmtTmcg
+Ie7i6ODcA7avSdsw/mbZqbSqNHBdDnydUgkwZUJKlp2DH85MoVrHcNVW6mVlRZ96
+I31+EyLS5NlYb1e4CiEo2uvhvrAxeDw9mvNKWrV4BXc58vq8N48/r83lBdV09OyP
+tymoRevjFD3M5fcR8VzXVg/diItDZ15fUw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com.pem.certspec
new file mode 100644
index 000000000..46630c4a1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-com.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int-example-org-permitted
+subject:ee-example-com
+extension:subjectAlternativeName:example.com
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ee-example-org.pem b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-org.pem
new file mode 100644
index 000000000..7e366f8ca
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-org.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5TCCAc+gAwIBAgIUcZBzsxoUEYUZlsKZQdyvAEhTgaswCwYJKoZIhvcNAQEL
+MCQxIjAgBgNVBAMMGWludC1leGFtcGxlLW9yZy1wZXJtaXR0ZWQwIhgPMjAxNTEx
+MjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowGTEXMBUGA1UEAwwOZWUtZXhhbXBs
+ZS1vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAGjGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUub3JnMAsGCSqGSIb3
+DQEBCwOCAQEAJwtc0BV1zdS6BO2he4SbTeDvHxkNqlkgRbrcT5kSgQgqlH6rcnoe
+QHrIsbGeHBoWJKI2tsmeKkGyswPsxyktEXKLb53J8EGpc72XwazhTFQTKCfLeB0n
+GlYfdI65ipwnqo46Juj6WHcFjf964eNhVLBun/535CcT5I7Y8bVDDakSkAfdxY8k
+JjRVe73yAt7pjpQ70Gq39tiuMD16pJ8+M6FJvbYKFmelhWcusRo56fJsx4jkN0zo
+I75MJ1cjr+UL1ixMVXjj5WQzZw+Ec+SBAL4fR8JTkkdjRNJTWB5Pr1eH4xa6vQsB
+wc3PCSdU0y80ihL2AcxNKZiOVAftJM9lIw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ee-example-org.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-org.pem.certspec
new file mode 100644
index 000000000..6a24090e5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-org.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int-example-org-permitted
+subject:ee-example-org
+extension:subjectAlternativeName:example.org
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ee-example-test.pem b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-test.pem
new file mode 100644
index 000000000..0b65d0f3d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-test.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAdGgAwIBAgIUVQNQFeYcunS/xUPvzDd6P51z7PEwCwYJKoZIhvcNAQEL
+MCQxIjAgBgNVBAMMGWludC1leGFtcGxlLW9yZy1wZXJtaXR0ZWQwIhgPMjAxNTEx
+MjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowGjEYMBYGA1UEAwwPZWUtZXhhbXBs
+ZS10ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB
+/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRx
+CHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMC
+OosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdm
+Wqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGz
+ey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUD
+rNoYCjXtjQIDAQABoxswGTAXBgNVHREEEDAOggxleGFtcGxlLnRlc3QwCwYJKoZI
+hvcNAQELA4IBAQAcdgKZ3Dp2Q6EMCWw+5VgzS2lEwf+LgxwNWLKnI0sX1YYuP3oq
+6t+UMcYelMwaYISXy+v8ZCrey1nJidjuRZHigQun7aqnQ4ugyPATbCrO/3eJZ6K0
+JVDPCt8hYSrogDWGG3KqX5z0lyjcWMGSDL+z6sWxLneOIdNFD6WsY8leM1jbaGD6
+fTJyHzaJ7m2kvp67Doqb8XzMlAY3nX3S/qD/mW0fO/IOAmogVZgG/5KbyQeJC0uu
+qoFmeRFoAuoNhRY2XuHh4I3OQCRtUGujNeC9AzVUQGI69saKvq96W/M5ij9JKfnP
+K6woylFDR67heaevocc4EcbSE7Y4e2LUURtL
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/ee-example-test.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-test.pem.certspec
new file mode 100644
index 000000000..0926ce477
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/ee-example-test.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int-example-org-permitted
+subject:ee-example-test
+extension:subjectAlternativeName:example.test
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/int-example-org-permitted.pem b/security/manager/ssl/tests/unit/test_name_constraints/int-example-org-permitted.pem
new file mode 100644
index 000000000..4f12c9a61
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/int-example-org-permitted.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDjCCAfigAwIBAgIUa0ZhHpbuqgjJTZfVUN+proqgaCQwCwYJKoZIhvcNAQEL
+MCMxITAfBgNVBAMMGGNhLWV4YW1wbGUtY29tLXBlcm1pdHRlZDAiGA8yMDE1MTEy
+ODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAkMSIwIAYDVQQDDBlpbnQtZXhhbXBs
+ZS1vcmctcGVybWl0dGVkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+uohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGoby
+a+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWC
+D/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfT
+iEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXT
+Ce+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+
+SSP6clHEMdUDrNoYCjXtjQIDAQABozkwNzAMBgNVHRMEBTADAQH/MAsGA1UdDwQE
+AwIBBjAaBgNVHR4EEzARoA8wDYILZXhhbXBsZS5vcmcwCwYJKoZIhvcNAQELA4IB
+AQB1roD4dkWf/+8VEomThWmJaQiemqbSpv1T2pwy7dp/FhmqSHuJMYjL+2Whh8Nd
+j/b2fC9TAB3Q02WgF4ZCt53rr2wztO5JWel3uEZRlt5AIXJNkSYjfYuSoKcvntWS
+aenDy8+HTFZ4XqItv4qpRBCo/qguiohJ7wjPPCOuG/LFNgJdssC7TNHwhuPdnqCr
+B4EGFo6swUA4zJqS4kJdMQHnyhDRT0hVNSZF0Ql19bF69M9obqfrFbCMvuTj2kxo
+7hCG0C+Ws4bL+EA2ohjwPXgkFZcph/MRhLAa5U9s8G3TFLuJvOGZ6CAaSfQCJoAG
+nzgVDB82G7c1g67m186RSXzt
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/int-example-org-permitted.pem.certspec b/security/manager/ssl/tests/unit/test_name_constraints/int-example-org-permitted.pem.certspec
new file mode 100644
index 000000000..87e2cf8a5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/int-example-org-permitted.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca-example-com-permitted
+subject:int-example-org-permitted
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:nameConstraints:permitted:example.org
diff --git a/security/manager/ssl/tests/unit/test_name_constraints/moz.build b/security/manager/ssl/tests/unit/test_name_constraints/moz.build
new file mode 100644
index 000000000..3eb064111
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_name_constraints/moz.build
@@ -0,0 +1,21 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'NameConstraints.dcissallowed.pem',
+# 'NameConstraints.dcissblocked.pem',
+# 'ca-example-com-permitted.pem',
+# 'int-example-org-permitted.pem',
+# 'ee-example-com-and-org.pem',
+# 'ee-example-com.pem',
+# 'ee-example-org.pem',
+# 'ee-example-test.pem',
+# 'dciss.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_nsCertType.js b/security/manager/ssl/tests/unit/test_nsCertType.js
new file mode 100644
index 000000000..2e378541d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_nsCertType.js
@@ -0,0 +1,28 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// While the Netscape certificate type extension is not a standard and has been
+// discouraged from use for quite some time, it is still encountered. Thus, we
+// handle it slightly differently from other unknown extensions.
+// If it is not marked critical, we ignore it.
+// If it is marked critical:
+// If the basic constraints and extended key usage extensions are also
+// present, we ignore it, because they are standardized and should convey the
+// same information.
+// Otherwise, we reject it with an error indicating an unknown critical
+// extension.
+
+"use strict";
+
+function run_test() {
+ do_get_profile();
+ add_tls_server_setup("BadCertServer", "bad_certs");
+ add_connection_test("nsCertTypeNotCritical.example.com", PRErrorCodeSuccess);
+ add_connection_test("nsCertTypeCriticalWithExtKeyUsage.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("nsCertTypeCritical.example.com",
+ SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_nsIX509CertValidity.js b/security/manager/ssl/tests/unit/test_nsIX509CertValidity.js
new file mode 100644
index 000000000..f35f5d97b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_nsIX509CertValidity.js
@@ -0,0 +1,49 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// This file tests the nsIX509CertValidity implementation.
+
+function fuzzyEqual(attributeName, dateString, expectedTime) {
+ do_print(`${attributeName}: ${dateString}`);
+ let absTimeDiff = Math.abs(expectedTime - Date.parse(dateString));
+ const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000;
+ lessOrEqual(absTimeDiff, ONE_DAY_IN_MS,
+ `Time difference for ${attributeName} should be <= one day`);
+}
+
+function run_test() {
+ // Date.parse("2013-01-01T00:00:00Z")
+ const NOT_BEFORE_IN_MS = 1356998400000;
+ // Date.parse("2014-01-01T00:00:00Z")
+ const NOT_AFTER_IN_MS = 1388534400000;
+ let cert = constructCertFromFile("bad_certs/expired-ee.pem");
+
+ equal(cert.validity.notBefore, NOT_BEFORE_IN_MS * 1000,
+ "Actual and expected notBefore should be equal");
+ equal(cert.validity.notAfter, NOT_AFTER_IN_MS * 1000,
+ "Actual and expected notAfter should be equal");
+
+ // The following tests rely on the implementation of nsIX509CertValidity
+ // providing long formatted dates to work. If this is not true, a returned
+ // short formatted date such as "12/31/12" may be interpreted as something
+ // other than the expected "December 31st, 2012".
+ //
+ // On Android, the implementation of nsIDateTimeFormat currently does not
+ // return a long formatted date even if it is asked to. This, combined with
+ // the reason above is why the following tests are disabled on Android.
+ if (AppConstants.platform != "android") {
+ fuzzyEqual("notBeforeLocalTime", cert.validity.notBeforeLocalTime,
+ NOT_BEFORE_IN_MS);
+ fuzzyEqual("notBeforeLocalDay", cert.validity.notBeforeLocalDay,
+ NOT_BEFORE_IN_MS);
+ fuzzyEqual("notBeforeGMT", cert.validity.notBeforeGMT, NOT_BEFORE_IN_MS);
+
+ fuzzyEqual("notAfterLocalTime", cert.validity.notAfterLocalTime,
+ NOT_AFTER_IN_MS);
+ fuzzyEqual("notAfterLocalDay", cert.validity.notAfterLocalDay,
+ NOT_AFTER_IN_MS);
+ fuzzyEqual("notAfterGMT", cert.validity.notAfterGMT, NOT_AFTER_IN_MS);
+ }
+}
diff --git a/security/manager/ssl/tests/unit/test_nsIX509Cert_utf8.js b/security/manager/ssl/tests/unit/test_nsIX509Cert_utf8.js
new file mode 100644
index 000000000..b4b0d6f37
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_nsIX509Cert_utf8.js
@@ -0,0 +1,70 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Checks that various nsIX509Cert attributes correctly handle UTF-8.
+
+do_get_profile(); // Must be called before getting nsIX509CertDB
+const certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function run_test() {
+ let cert = certDB.constructX509FromBase64(
+ "MIIF3DCCBMSgAwIBAgIEAJiZbzANBgkqhkiG9w0BAQUFADCCAQ0xYTBfBgNVBAMM" +
+ "WEkuQ0EgLSBRdWFsaWZpZWQgcm9vdCBjZXJ0aWZpY2F0ZSAoa3ZhbGlmaWtvdmFu" +
+ "w70gY2VydGlmaWvDoXQgcG9za3l0b3ZhdGVsZSkgLSBQU0VVRE9OWU0xCzAJBgNV" +
+ "BAYTAkNaMS8wLQYDVQQHDCZQb2R2aW5uw70gbWzDvW4gMjE3OC82LCAxOTAgMDAg" +
+ "UHJhaGEgOTEsMCoGA1UECgwjUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRh" +
+ "IGEucy4xPDA6BgNVBAsMM0FrcmVkaXRvdmFuw70gcG9za3l0b3ZhdGVsIGNlcnRp" +
+ "ZmlrYcSNbsOtY2ggc2x1xb5lYjAeFw0wMjEyMTIxMzMzNDZaFw0wMzEyMTIxMzMz" +
+ "NDZaMIIBFDELMAkGA1UEBhMCQ1oxHzAdBgNVBAMeFgBMAHUAZAEbAGsAIABSAGEB" +
+ "YQBlAGsxGTAXBgNVBAgeEABWAHkAcwBvAQ0AaQBuAGExLzAtBgNVBAceJgBQAGEA" +
+ "YwBvAHYALAAgAE4A4QBkAHIAYQF+AG4A7QAgADcANgA5MSUwIwYJKoZIhvcNAQkB" +
+ "FhZsdWRlay5yYXNla0BjZW50cnVtLmN6MRMwEQYDVQQqHgoATAB1AGQBGwBrMQ0w" +
+ "CwYDVQQrHgQATABSMR8wHQYDVQQpHhYATAB1AGQBGwBrACAAUgBhAWEAZQBrMRMw" +
+ "EQYDVQQEHgoAUgBhAWEAZQBrMRcwFQYDVQQFEw5JQ0EgLSAxMDAwMzc2OTCBnzAN" +
+ "BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxc7dGd0cNlHZ7tUUl5k30bfYlY3lnOD0" +
+ "49JGbTXSt4jNFMRLj6s/777W3kcIdcIwdKxjQULBKgryDvZJ1DAWp2TwzhPDVYj3" +
+ "sU4Niqb7mOUcp/4ckteUxGF6FmXtJR9+XHTuLZ+omF9HOUefheBKnXvZuqrLM16y" +
+ "nbJn4sPwwdcCAwEAAaOCAbswggG3MCUGA1UdEQQeMBygGgYKKwMGAQQB3BkCAaAM" +
+ "DAoxNzYyODk2ODgzMGkGA1UdHwRiMGAwHqAcoBqGGGh0dHA6Ly9xLmljYS5jei9x" +
+ "aWNhLmNybDAeoBygGoYYaHR0cDovL2IuaWNhLmN6L3FpY2EuY3JsMB6gHKAahhho" +
+ "dHRwOi8vci5pY2EuY3ovcWljYS5jcmwwHwYDVR0jBBgwFoAUK1oKfvvlDYUsZTBy" +
+ "vGN701mca/UwHQYDVR0OBBYEFPAs70DB+LS0PnA6niPUfJ5wdQH5MIG4BgNVHSAE" +
+ "gbAwga0wgaoGCysGAQQBs2EBAQQEMIGaMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3" +
+ "LmljYS5jei9xY3AvY3BxcGljYTAyLnBkZjBnBggrBgEFBQcCAjBbGllUZW50byBj" +
+ "ZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28gS3ZhbGlmaWtvdmFueSBjZXJ0aWZpa2F0" +
+ "IHYgc291bGFkdSBzZSB6YWtvbmVtIDIyNy8yMDAwIFNiLjAYBggrBgEFBQcBAwQM" +
+ "MAowCAYGBACORgEBMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQUFAAOCAQEA" +
+ "v2V+nnYYMIgabmmgHx49CtlZIHdGS3TuWKXw130xFhbXDnNhEbx3alaskNsvjQQR" +
+ "Lqs1ZwKy58yynse+eJYHqenmHDACpAfVpCF9PXC/mDarVsoQw7NTcUpsAFhSd/zT" +
+ "v9jIf3twECyxx/RVzONVcob7nPePESHiKoG4FbtcuUh0wSHvCmTwRIQqPDCIuHcF" +
+ "StSt3Jr9iXcbXEhe4mSccOZ8N+r7Rv3ncKcevlRl7uFfDKDTyd43SZeRS/7J8KRf" +
+ "hD/h2nawrCFwc5gJW10aLJGFL/mcS7ViAIT9HCVk23j4TuBjsVmnZ0VKxB5edux+" +
+ "LIEqtU428UVHZWU/I5ngLw==");
+
+ equal(cert.nickname, "(no nickname)",
+ "Actual and expected nickname should match");
+ equal(cert.emailAddress, "ludek.rasek@centrum.cz",
+ "Actual and expected emailAddress should match");
+ equal(cert.subjectName, "serialNumber=ICA - 10003769,SN=Rašek,name=Luděk Rašek,initials=LR,givenName=Luděk,E=ludek.rasek@centrum.cz,L=\"Pacov, Nádražní 769\",ST=Vysočina,CN=Luděk Rašek,C=CZ",
+ "Actual and expected subjectName should match");
+ equal(cert.commonName, "Luděk Rašek",
+ "Actual and expected commonName should match");
+ equal(cert.organization, "",
+ "Actual and expected organization should match");
+ equal(cert.organizationalUnit, "",
+ "Actual and expected organizationalUnit should match");
+ equal(cert.windowTitle, "Luděk Rašek",
+ "Actual and expected windowTitle should match");
+ equal(cert.issuerName, "OU=Akreditovaný poskytovatel certifikačních služeb,O=První certifikační autorita a.s.,L=\"Podvinný mlýn 2178/6, 190 00 Praha 9\",C=CZ,CN=I.CA - Qualified root certificate (kvalifikovaný certifikát poskytovatele) - PSEUDONYM",
+ "Actual and expected issuerName should match");
+ equal(cert.issuerCommonName, "I.CA - Qualified root certificate (kvalifikovaný certifikát poskytovatele) - PSEUDONYM",
+ "Actual and expected issuerCommonName should match");
+ equal(cert.issuerOrganization, "První certifikační autorita a.s.",
+ "Actual and expected issuerOrganization should match");
+ equal(cert.issuerOrganizationUnit, "Akreditovaný poskytovatel certifikačních služeb",
+ "Actual and expected issuerOrganizationUnit should match");
+}
diff --git a/security/manager/ssl/tests/unit/test_nss_shutdown.js b/security/manager/ssl/tests/unit/test_nss_shutdown.js
new file mode 100644
index 000000000..0c467cbd4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_nss_shutdown.js
@@ -0,0 +1,44 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// This test attempts to ensure that PSM doesn't deadlock or crash when shutting
+// down NSS while a background thread is attempting to use NSS.
+// Uses test_signed_apps/valid_app_1.zip from test_signed_apps.js.
+
+function startAsyncNSSOperation(certdb, appFile) {
+ return new Promise((resolve, reject) => {
+ certdb.openSignedAppFileAsync(Ci.nsIX509CertDB.AppXPCShellRoot, appFile,
+ function(rv, aZipReader, aSignerCert) {
+ // rv will either indicate success (if NSS hasn't been shut down yet) or
+ // it will be some error code that varies depending on when NSS got shut
+ // down. As such, there's nothing really to check here. Just resolve the
+ // promise to continue execution.
+ resolve();
+ });
+ });
+}
+
+add_task(function* () {
+ do_get_profile();
+ let psm = Cc["@mozilla.org/psm;1"]
+ .getService(Ci.nsISupports)
+ .QueryInterface(Ci.nsIObserver);
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ let appFile = do_get_file("test_signed_apps/valid_app_1.zip");
+
+ let promises = [];
+ for (let i = 0; i < 25; i++) {
+ promises.push(startAsyncNSSOperation(certdb, appFile));
+ }
+ // Trick PSM into thinking it should shut down NSS. If this test doesn't
+ // hang or crash, we're good.
+ psm.observe(null, "profile-before-change", null);
+ for (let i = 0; i < 25; i++) {
+ promises.push(startAsyncNSSOperation(certdb, appFile));
+ }
+ yield Promise.all(promises);
+});
diff --git a/security/manager/ssl/tests/unit/test_ocsp_caching.js b/security/manager/ssl/tests/unit/test_ocsp_caching.js
new file mode 100644
index 000000000..d0897fccd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_caching.js
@@ -0,0 +1,299 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Checks various aspects of the OCSP cache, mainly to to ensure we do not fetch
+// responses more than necessary.
+
+var gFetchCount = 0;
+var gGoodOCSPResponse = null;
+var gResponsePattern = [];
+var gMessage = "";
+
+function respondWithGoodOCSP(request, response) {
+ do_print("returning 200 OK");
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "application/ocsp-response");
+ response.write(gGoodOCSPResponse);
+}
+
+function respondWithSHA1OCSP(request, response) {
+ do_print("returning 200 OK with sha-1 delegated response");
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "application/ocsp-response");
+
+ let args = [ ["good-delegated", "default-ee", "delegatedSHA1Signer" ] ];
+ let responses = generateOCSPResponses(args, "ocsp_certs");
+ response.write(responses[0]);
+}
+
+function respondWithError(request, response) {
+ do_print("returning 500 Internal Server Error");
+ response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
+ let body = "Refusing to return a response";
+ response.bodyOutputStream.write(body, body.length);
+}
+
+function generateGoodOCSPResponse() {
+ let args = [ ["good", "default-ee", "unused" ] ];
+ let responses = generateOCSPResponses(args, "ocsp_certs");
+ return responses[0];
+}
+
+function add_ocsp_test(aHost, aExpectedResult, aResponses, aMessage,
+ aOriginAttributes) {
+ add_connection_test(aHost, aExpectedResult,
+ function() {
+ clearSessionCache();
+ gFetchCount = 0;
+ gResponsePattern = aResponses;
+ gMessage = aMessage;
+ },
+ function() {
+ // check the number of requests matches the size of aResponses
+ equal(gFetchCount, aResponses.length,
+ "should have made " + aResponses.length +
+ " OCSP request" + (aResponses.length == 1 ? "" : "s"));
+ }, null, aOriginAttributes);
+}
+
+function run_test() {
+ do_get_profile();
+ Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+ Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+
+ let ocspResponder = new HttpServer();
+ ocspResponder.registerPrefixHandler("/", function(request, response) {
+
+ do_print("gFetchCount: " + gFetchCount);
+ let responseFunction = gResponsePattern[gFetchCount];
+ Assert.notEqual(undefined, responseFunction);
+
+ ++gFetchCount;
+ responseFunction(request, response);
+ });
+ ocspResponder.start(8888);
+
+ add_tests();
+
+ add_test(function() { ocspResponder.stop(run_next_test); });
+ run_next_test();
+}
+
+function add_tests() {
+ // Test that verifying a certificate with a "short lifetime" doesn't result
+ // in OCSP fetching. Due to longevity requirements in our testing
+ // infrastructure, the certificate we encounter is valid for a very long
+ // time, so we have to define a "short lifetime" as something very long.
+ add_test(function() {
+ Services.prefs.setIntPref("security.pki.cert_short_lifetime_in_days",
+ 12000);
+ run_next_test();
+ });
+
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess, [],
+ "expected zero OCSP requests for a short-lived certificate");
+
+ add_test(function() {
+ Services.prefs.setIntPref("security.pki.cert_short_lifetime_in_days", 100);
+ run_next_test();
+ });
+
+ // If a "short lifetime" is something more reasonable, ensure that we do OCSP
+ // fetching for this long-lived certificate.
+
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
+ [respondWithError],
+ "expected one OCSP request for a long-lived certificate");
+ add_test(function() {
+ Services.prefs.clearUserPref("security.pki.cert_short_lifetime_in_days");
+ run_next_test();
+ });
+ //---------------------------------------------------------------------------
+
+ // Reset state
+ add_test(function() { clearOCSPCache(); run_next_test(); });
+
+ // This test assumes that OCSPStaplingServer uses the same cert for
+ // ocsp-stapling-unknown.example.com and ocsp-stapling-none.example.com.
+
+ // Get an Unknown response for the *.example.com cert and put it in the
+ // OCSP cache.
+ add_ocsp_test("ocsp-stapling-unknown.example.com",
+ SEC_ERROR_OCSP_UNKNOWN_CERT, [],
+ "Stapled Unknown response -> a fetch should not have been" +
+ " attempted");
+
+ // A failure to retrieve an OCSP response must result in the cached Unknown
+ // response being recognized and honored.
+ add_ocsp_test("ocsp-stapling-none.example.com", SEC_ERROR_OCSP_UNKNOWN_CERT,
+ [
+ respondWithError,
+ respondWithError,
+ respondWithError,
+ respondWithError,
+ respondWithError,
+ respondWithError,
+ ],
+ "No stapled response -> a fetch should have been attempted");
+
+ // A valid Good response from the OCSP responder must override the cached
+ // Unknown response.
+ //
+ // Note that We need to make sure that the Unknown response and the Good
+ // response have different thisUpdate timestamps; otherwise, the Good
+ // response will be seen as "not newer" and it won't replace the existing
+ // entry.
+ add_test(function() {
+ let duration = 1200;
+ do_print("Sleeping for " + duration + "ms");
+ let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.initWithCallback(run_next_test, duration, Ci.nsITimer.TYPE_ONE_SHOT);
+ });
+ add_test(function() {
+ gGoodOCSPResponse = generateGoodOCSPResponse();
+ run_next_test();
+ });
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
+ [respondWithGoodOCSP],
+ "Cached Unknown response, no stapled response -> a fetch" +
+ " should have been attempted");
+
+ // The Good response retrieved from the previous fetch must have replaced
+ // the Unknown response in the cache, resulting in the catched Good response
+ // being returned and no fetch.
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
+ [],
+ "Cached Good response -> a fetch should not have been" +
+ " attempted");
+
+
+ //---------------------------------------------------------------------------
+
+ // Reset state
+ add_test(function() { clearOCSPCache(); run_next_test(); });
+
+ // A failure to retrieve an OCSP response will result in an error entry being
+ // added to the cache.
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
+ [respondWithError],
+ "No stapled response -> a fetch should have been attempted");
+
+ // The error entry will prevent a fetch from happening for a while.
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess, [],
+ "Noted OCSP server failure -> a fetch should not have been" +
+ " attempted");
+
+ // The error entry must not prevent a stapled OCSP response from being
+ // honored.
+ add_ocsp_test("ocsp-stapling-revoked.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE, [],
+ "Stapled Revoked response -> a fetch should not have been" +
+ " attempted");
+
+ //---------------------------------------------------------------------------
+
+ // Ensure OCSP responses from signers with SHA1 certificates are OK. This
+ // is included in the OCSP caching tests since there were OCSP cache-related
+ // regressions when sha-1 telemetry probes were added.
+ add_test(function() {
+ clearOCSPCache();
+ // set security.OCSP.require so that checking the OCSP signature fails
+ Services.prefs.setBoolPref("security.OCSP.require", true);
+ run_next_test();
+ });
+
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
+ [respondWithSHA1OCSP],
+ "signing cert is good (though sha1) - should succeed");
+
+ add_test(function() {
+ Services.prefs.setBoolPref("security.OCSP.require", false);
+ run_next_test();
+ });
+
+ //---------------------------------------------------------------------------
+
+ // Reset state
+ add_test(function() { clearOCSPCache(); run_next_test(); });
+
+ // This test makes sure that OCSP cache are isolated by firstPartyDomain.
+
+ let gObservedCnt = 0;
+ let protocolProxyService = Cc["@mozilla.org/network/protocol-proxy-service;1"]
+ .getService(Ci.nsIProtocolProxyService);
+
+ // Observe all channels and make sure the firstPartyDomain in their loadInfo's
+ // origin attributes are aFirstPartyDomain.
+ function startObservingChannels(aFirstPartyDomain) {
+ // We use a dummy proxy filter to catch all channels, even those that do not
+ // generate an "http-on-modify-request" notification.
+ let proxyFilter = {
+ applyFilter: function (aProxyService, aChannel, aProxy) {
+ // We have the channel; provide it to the callback.
+ if (aChannel.originalURI.spec == "http://localhost:8888/") {
+ gObservedCnt++;
+ equal(aChannel.loadInfo.originAttributes.firstPartyDomain,
+ aFirstPartyDomain, "firstPartyDomain should match");
+ }
+ // Pass on aProxy unmodified.
+ return aProxy;
+ }
+ };
+ protocolProxyService.registerChannelFilter(proxyFilter, 0);
+ // Return the stop() function:
+ return () => protocolProxyService.unregisterChannelFilter(proxyFilter);
+ }
+
+ let stopObservingChannels;
+ add_test(function() {
+ stopObservingChannels = startObservingChannels("foo.com");
+ run_next_test();
+ });
+
+ // A good OCSP response will be cached.
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
+ [respondWithGoodOCSP],
+ "No stapled response (firstPartyDomain = foo.com) -> a fetch " +
+ "should have been attempted", { firstPartyDomain: "foo.com" });
+
+ // The cache will prevent a fetch from happening.
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess, [],
+ "Noted OCSP server failure (firstPartyDomain = foo.com) -> a " +
+ "fetch should not have been attempted",
+ { firstPartyDomain: "foo.com" });
+
+ add_test(function() {
+ stopObservingChannels();
+ equal(gObservedCnt, 1, "should have observed only 1 OCSP requests");
+ gObservedCnt = 0;
+ run_next_test();
+ });
+
+ add_test(function() {
+ stopObservingChannels = startObservingChannels("bar.com");
+ run_next_test();
+ });
+
+ // But using a different firstPartyDomain should result in a fetch.
+ add_ocsp_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
+ [respondWithGoodOCSP],
+ "No stapled response (firstPartyDomain = bar.com) -> a fetch " +
+ "should have been attempted", { firstPartyDomain: "bar.com" });
+
+ add_test(function() {
+ stopObservingChannels();
+ equal(gObservedCnt, 1, "should have observed only 1 OCSP requests");
+ gObservedCnt = 0;
+ run_next_test();
+ });
+
+ //---------------------------------------------------------------------------
+
+ // Reset state
+ add_test(function() { clearOCSPCache(); run_next_test(); });
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_enabled_pref.js b/security/manager/ssl/tests/unit/test_ocsp_enabled_pref.js
new file mode 100644
index 000000000..ba648b9e6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_enabled_pref.js
@@ -0,0 +1,141 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Checks that the security.OCSP.enabled pref correctly controls OCSP fetching
+// behavior.
+
+do_get_profile(); // Must be called before getting nsIX509CertDB
+const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+const SERVER_PORT = 8888;
+
+function certFromFile(filename) {
+ return constructCertFromFile(`test_ev_certs/${filename}.pem`);
+}
+
+function loadCert(certName, trustString) {
+ addCertFromFile(gCertDB, `test_ev_certs/${certName}.pem`, trustString);
+}
+
+function getFailingOCSPResponder() {
+ return getFailingHttpServer(SERVER_PORT, ["www.example.com"]);
+}
+
+function getOCSPResponder(expectedCertNames) {
+ return startOCSPResponder(SERVER_PORT, "www.example.com", "test_ev_certs",
+ expectedCertNames, []);
+}
+
+// Tests that in ocspOff mode, OCSP fetches are never done.
+function testOff() {
+ add_test(() => {
+ Services.prefs.setIntPref("security.OCSP.enabled", 0);
+ do_print("Setting security.OCSP.enabled to 0");
+ run_next_test();
+ });
+
+ // EV chains should verify successfully but never get EV status.
+ add_test(() => {
+ clearOCSPCache();
+ let ocspResponder = getFailingOCSPResponder();
+ checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), certificateUsageSSLServer,
+ false);
+ ocspResponder.stop(run_next_test);
+ });
+
+ // A DV chain should verify successfully.
+ add_test(() => {
+ clearOCSPCache();
+ let ocspResponder = getFailingOCSPResponder();
+ checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
+ PRErrorCodeSuccess, certificateUsageSSLServer);
+ ocspResponder.stop(run_next_test);
+ });
+}
+
+// Tests that in ocspOn mode, OCSP fetches are done for both EV and DV certs.
+function testOn() {
+ add_test(() => {
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+ do_print("Setting security.OCSP.enabled to 1");
+ run_next_test();
+ });
+
+ // If a successful OCSP response is fetched, then an EV chain should verify
+ // successfully and get EV status as well.
+ add_test(() => {
+ clearOCSPCache();
+ let ocspResponder =
+ getOCSPResponder(gEVExpected ? ["test-oid-path-int", "test-oid-path-ee"]
+ : ["test-oid-path-ee"]);
+ checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), certificateUsageSSLServer,
+ gEVExpected);
+ ocspResponder.stop(run_next_test);
+ });
+
+ // If a successful OCSP response is fetched, then a DV chain should verify
+ // successfully.
+ add_test(() => {
+ clearOCSPCache();
+ let ocspResponder = getOCSPResponder(["non-ev-root-path-ee"]);
+ checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
+ PRErrorCodeSuccess, certificateUsageSSLServer);
+ ocspResponder.stop(run_next_test);
+ });
+}
+
+// Tests that in ocspEVOnly mode, OCSP fetches are done for EV certs only.
+function testEVOnly() {
+ add_test(() => {
+ Services.prefs.setIntPref("security.OCSP.enabled", 2);
+ do_print("Setting security.OCSP.enabled to 2");
+ run_next_test();
+ });
+
+ // If a successful OCSP response is fetched, then an EV chain should verify
+ // successfully and get EV status as well.
+ add_test(() => {
+ clearOCSPCache();
+ let ocspResponder = gEVExpected
+ ? getOCSPResponder(["test-oid-path-int", "test-oid-path-ee"])
+ : getFailingOCSPResponder();
+ checkEVStatus(gCertDB, certFromFile("test-oid-path-ee"), certificateUsageSSLServer,
+ gEVExpected);
+ ocspResponder.stop(run_next_test);
+ });
+
+ // A DV chain should verify successfully even without doing OCSP fetches.
+ add_test(() => {
+ clearOCSPCache();
+ let ocspResponder = getFailingOCSPResponder();
+ checkCertErrorGeneric(gCertDB, certFromFile("non-ev-root-path-ee"),
+ PRErrorCodeSuccess, certificateUsageSSLServer);
+ ocspResponder.stop(run_next_test);
+ });
+}
+
+function run_test() {
+ do_register_cleanup(() => {
+ Services.prefs.clearUserPref("network.dns.localDomains");
+ Services.prefs.clearUserPref("security.OCSP.enabled");
+ Services.prefs.clearUserPref("security.OCSP.require");
+ });
+ Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
+ // Enable hard fail to ensure chains that should only succeed because they get
+ // a good OCSP response do not succeed due to soft fail leniency.
+ Services.prefs.setBoolPref("security.OCSP.require", true);
+
+ loadCert("evroot", "CTu,,");
+ loadCert("test-oid-path-int", ",,");
+ loadCert("non-evroot-ca", "CTu,,");
+ loadCert("non-ev-root-path-int", ",,");
+
+ testOff();
+ testOn();
+ testEVOnly();
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method.js b/security/manager/ssl/tests/unit/test_ocsp_fetch_method.js
new file mode 100644
index 000000000..de89a4131
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method.js
@@ -0,0 +1,59 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+// In which we try to validate several ocsp responses, checking in particular
+// that we use the specified method for fetching ocsp. We also check what
+// POST fallback when an invalid GET response is received.
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+const SERVER_PORT = 8888;
+
+function start_ocsp_responder(expectedCertNames, expectedPaths,
+ expectedMethods) {
+ return startOCSPResponder(SERVER_PORT, "www.example.com",
+ "test_ocsp_fetch_method", expectedCertNames,
+ expectedPaths, expectedMethods);
+}
+
+function check_cert_err(cert_name, expected_error) {
+ let cert = constructCertFromFile("test_ocsp_fetch_method/" + cert_name + ".pem");
+ return checkCertErrorGeneric(certdb, cert, expected_error,
+ certificateUsageSSLServer);
+}
+
+function run_test() {
+ addCertFromFile(certdb, "test_ocsp_fetch_method/ca.pem", 'CTu,CTu,CTu');
+ addCertFromFile(certdb, "test_ocsp_fetch_method/int.pem", ',,');
+
+ // Enabled so that we can force ocsp failure responses.
+ Services.prefs.setBoolPref("security.OCSP.require", true);
+
+ Services.prefs.setCharPref("network.dns.localDomains",
+ "www.example.com");
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+
+ add_test(function() {
+ clearOCSPCache();
+ Services.prefs.setBoolPref("security.OCSP.GET.enabled", false);
+ let ocspResponder = start_ocsp_responder(["a"], [], ["POST"]);
+ check_cert_err("a", PRErrorCodeSuccess);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ Services.prefs.setBoolPref("security.OCSP.GET.enabled", true);
+ let ocspResponder = start_ocsp_responder(["a"], [], ["GET"]);
+ check_cert_err("a", PRErrorCodeSuccess);
+ ocspResponder.stop(run_next_test);
+ });
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/a.pem b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/a.pem
new file mode 100644
index 000000000..67961e695
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/a.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5DCCAc6gAwIBAgIUG4s0As2WcZndVBOEXzU8uA26EUIwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAMMQowCAYDVQQDDAFhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozwwOjA4BggrBgEFBQcBAQQsMCowKAYI
+KwYBBQUHMAGGHGh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC8wCwYJKoZIhvcN
+AQELA4IBAQAbh10OV6scfCpc71hMzfOhmxFlicFVlqWr9saGAg6renUfoq/ZDsDK
+F+gQOMyv4gtO0nAoXJ206ONNJZwAEFAusNFlfjk/sxKvmDwkGWwi/lSCtwk41loG
+UNH4YV2Y6IDLIuzvHzQgkhRJZ98nQhyPiBSZy5LoqGIi1+zTQkhYtB9yR0hwoFey
+JVTso2OwSwasZixBQ0NZ9WGOSupihYBJJI4BQyOwf75u2WWqTP4Yj59eZTEOIoP0
+u+5fG+mUKOrxVuZoEh6zse49IpuaOok0dW+o3soEVQqos/GuOL/sYhARfwCQT1MW
+kBdICJFXSTDPuXoOk58Y2QwUtsYq3Ifb
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/a.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/a.pem.certspec
new file mode 100644
index 000000000..d3a3f86ef
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/a.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:a
+extension:authorityInformationAccess:http://www.example.com:8888/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/ca.pem b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/ca.pem
new file mode 100644
index 000000000..1a18e2bf0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUL5zykZEc2ro5d6th43aWGfm735cwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
+DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHPYBjNnv//Ssc8Elepb8SWIXRdahKbL
+/dcPoMR+7yhJVaelUaxdwUytJWJAGdkkuv+P+G4b82RVYEXT+9k1S/aAfByFyR9q
+vS7POfdy/ZPfGTXltlnmYX/84a6QeYQa4Nl4JpIOXBCesLxmErBhczka6D26iqsz
+GeseKRSjVPgF3mXc2CRGZnTDRhUmd7wOABLmj7GtuFvOm96363M3IUByMohvoj1G
+dic3s5D0seXwTKnEc5B27lJt7Q0oIXEldL+UW8Mo1hfGWQeXzqTZbpOVLnVWvHBH
+H8yYs5hyH01qFJZbztJ1JJ3F2NpYLlr4P5I6fW2e9w5MG/VMQRU3wzQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/ca.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/ca.pem.certspec
new file mode 100644
index 000000000..6660f5d47
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.key b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.key
new file mode 100644
index 000000000..8af23e068
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAECggEBAJ7LzjhhpFTsseD+j4XdQ8kvWCXOLpl4hNDhqUnaosWs
+VZskBFDlrJ/gw+McDu+mUlpl8MIhlABO4atGPd6e6CKHzJPnRqkZKcXmrD2IdT9s
+JbpZeec+XY+yOREaPNq4pLDN9fnKsF8SM6ODNcZLVWBSXn47kq18dQTPHcfLAFeI
+r8vh6Pld90AqFRUw1YCDRoZOs3CqeZVqWHhiy1M3kTB/cNkcltItABppAJuSPGgz
+iMnzbLm16+ZDAgQceNkIIGuHAJy4yrrK09vbJ5L7kRss9NtmA1hb6a4Mo7jmQXqg
+SwbkcOoaO1gcoDpngckxW2KzDmAR8iRyWUbuxXxtlEECgYEA3W4dT//r9o2InE0R
+TNqqnKpjpZN0KGyKXCmnF7umA3VkTVyqZ0xLi8cyY1hkYiDkVQ12CKwn1Vttt0+N
+gSfvj6CQmLaRR94GVXNEfhg9Iv59iFrOtRPZWB3V4HwakPXOCHneExNx7O/JznLp
+xD3BJ9I4GQ3oEXc8pdGTAfSMdCsCgYEA16dz2evDgKdn0v7Ak0rU6LVmckB3Gs3r
+ta15b0eP7E1FmF77yVMpaCicjYkQL63yHzTi3UlA66jAnW0fFtzClyl3TEMnXpJR
+3b5JCeH9O/Hkvt9Go5uLODMo70rjuVuS8gcK8myefFybWH/t3gXo59hspXiG+xZY
+EKd7mEW8MScCgYEAlkcrQaYQwK3hryJmwWAONnE1W6QtS1oOtOnX6zWBQAul3RMs
+2xpekyjHu8C7sBVeoZKXLt+X0SdR2Pz2rlcqMLHqMJqHEt1OMyQdse5FX8CT9byb
+WS11bmYhR08ywHryL7J100B5KzK6JZC7smGu+5WiWO6lN2VTFb6cJNGRmS0CgYAo
+tFCnp1qFZBOyvab3pj49lk+57PUOOCPvbMjo+ibuQT+LnRIFVA8Su+egx2got7pl
+rYPMpND+KiIBFOGzXQPVqFv+Jwa9UPzmz83VcbRspiG47UfWBbvnZbCqSgZlrCU2
+TaIBVAMuEgS4VZ0+NPtbF3yaVv+TUQpaSmKHwVHeLQKBgCgGe5NVgB0u9S36ltit
+tYlnPPjuipxv9yruq+nva+WKT0q/BfeIlH3IUf2qNFQhR6caJGv7BU7naqNGq80m
+ks/J5ExR5vBpxzXgc7oBn2pyFJYckbJoccrqv48GRBigJpDjmo1f8wZ7fNt/ULH1
+NBinA5ZsT8d0v3QCr2xDJH9D
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.key.keyspec b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.key.keyspec
new file mode 100644
index 000000000..4ad96d515
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.key.keyspec
@@ -0,0 +1 @@
+default
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.pem b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.pem
new file mode 100644
index 000000000..fd60e5fe2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxjCCAbCgAwIBAgIUazy/vTocAuxP85PTc+O1JXs8WWEwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA4xDDAKBgNVBAMMA2ludDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAab
+bhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmts
+Du0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhI
+H6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8
+rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kX
+Mbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNV
+HQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQA6lr0lbqcaGYjYAAcA5BngiUobuYFn
+4jdYK9eR6hiT5PmYRQZ9/y+2aYNF/ygiBBqBdEq/Nhrm35WeUHvDBaT8OZLBjf+g
+krEAmu2ivrHZWrx16HBVDd9JdTUCx8j1HUo5fadFnsQh7nuh/VIoemox+/e8mKfh
++fW3noAoH/MRfP9VYoS0KzkW8ILiWOR1joNOHDZzanMiM/YCHO1nckq2ntI2T+kO
+MNMkB+j1w5Fu6P8pgyToleHs3WmlWAeDjXygZkEhg+9uuBXb8/IyuS3cYt9ovhSh
+++A25JRmqaQn2Ywd+CMsGe4MTYOsRnZPK0Co6TBteRWRdwSpqzb+UOqY
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.pem.certspec
new file mode 100644
index 000000000..ebb4c376d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/int.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
diff --git a/security/manager/ssl/tests/unit/test_ocsp_fetch_method/moz.build b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/moz.build
new file mode 100644
index 000000000..c7a62b6f2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_fetch_method/moz.build
@@ -0,0 +1,22 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'a.pem',
+# 'ca.pem',
+# 'int.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
+#
+#test_keys = (
+# 'int.key',
+#)
+#
+#for test_key in test_keys:
+# GeneratedTestKey(test_key)
diff --git a/security/manager/ssl/tests/unit/test_ocsp_must_staple.js b/security/manager/ssl/tests/unit/test_ocsp_must_staple.js
new file mode 100644
index 000000000..24b32d6bc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_must_staple.js
@@ -0,0 +1,116 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Tests OCSP Must Staple handling by connecting to various domains (as faked by
+// a server running locally) that correspond to combinations of whether the
+// extension is present in intermediate and end-entity certificates.
+
+var gExpectOCSPRequest;
+
+function add_ocsp_test(aHost, aExpectedResult, aStaplingEnabled) {
+ add_connection_test(aHost, aExpectedResult,
+ function() {
+ gExpectOCSPRequest = !aStaplingEnabled;
+ clearOCSPCache();
+ clearSessionCache();
+ Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling",
+ aStaplingEnabled);
+ });
+}
+
+function add_tests() {
+ // ensure that the chain is checked for required features in children:
+ // First a case where intermediate and ee both have the extension
+ add_ocsp_test("ocsp-stapling-must-staple-ee-with-must-staple-int.example.com",
+ PRErrorCodeSuccess, true);
+
+ add_test(() => {
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1);
+ Services.prefs.setBoolPref("security.cert_pinning.process_headers_from_non_builtin_roots", true);
+ let uri = Services.io.newURI("https://ocsp-stapling-must-staple-ee-with-must-staple-int.example.com",
+ null, null);
+ let keyHash = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
+ let backupKeyHash = "KHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN=";
+ let header = `max-age=1000; pin-sha256="${keyHash}"; pin-sha256="${backupKeyHash}"`;
+ let ssservice = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ let sslStatus = new FakeSSLStatus();
+ sslStatus.serverCert = constructCertFromFile("ocsp_certs/must-staple-ee-with-must-staple-int.pem");
+ ssservice.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri, header, sslStatus, 0);
+ ok(ssservice.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0),
+ "ocsp-stapling-must-staple-ee-with-must-staple-int.example.com should have HPKP set");
+
+ // Clear accumulated state.
+ ssservice.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
+ Services.prefs.clearUserPref("security.cert_pinning.process_headers_from_non_builtin_roots");
+ Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
+ run_next_test();
+ });
+
+ // Next, a case where it's present in the intermediate, not the ee
+ add_ocsp_test("ocsp-stapling-plain-ee-with-must-staple-int.example.com",
+ MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING, true);
+
+ // We disable OCSP stapling in the next two tests so we can perform checks
+ // on TLS Features in the chain without needing to support the TLS
+ // extension values used.
+ // Test an issuer with multiple TLS features in matched in the EE
+ add_ocsp_test("multi-tls-feature-good.example.com",
+ PRErrorCodeSuccess, false);
+
+ // Finally, an issuer with multiple TLS features not matched by the EE.
+ add_ocsp_test("multi-tls-feature-bad.example.com",
+ MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING, false);
+
+ // Now a bunch of operations with only a must-staple ee
+ add_ocsp_test("ocsp-stapling-must-staple.example.com",
+ PRErrorCodeSuccess, true);
+
+ add_ocsp_test("ocsp-stapling-must-staple-revoked.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE, true);
+
+ add_ocsp_test("ocsp-stapling-must-staple-missing.example.com",
+ MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING, true);
+
+ add_ocsp_test("ocsp-stapling-must-staple-empty.example.com",
+ SEC_ERROR_OCSP_MALFORMED_RESPONSE, true);
+
+ add_ocsp_test("ocsp-stapling-must-staple-missing.example.com",
+ PRErrorCodeSuccess, false);
+
+ // check that disabling must-staple works
+ add_test(function() {
+ clearSessionCache();
+ Services.prefs.setBoolPref("security.ssl.enable_ocsp_must_staple", false);
+ run_next_test();
+ });
+
+ add_ocsp_test("ocsp-stapling-must-staple-missing.example.com",
+ PRErrorCodeSuccess, true);
+}
+
+function run_test() {
+ do_get_profile();
+ Services.prefs.setBoolPref("security.ssl.enable_ocsp_must_staple", true);
+
+ let fakeOCSPResponder = new HttpServer();
+ fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
+ response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
+ ok(gExpectOCSPRequest,
+ "Should be getting an OCSP request only when expected");
+ });
+ fakeOCSPResponder.start(8888);
+
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+
+ add_tests();
+
+ add_test(function () {
+ fakeOCSPResponder.stop(run_next_test);
+ });
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_no_hsts_upgrade.js b/security/manager/ssl/tests/unit/test_ocsp_no_hsts_upgrade.js
new file mode 100644
index 000000000..62ff1ba25
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_no_hsts_upgrade.js
@@ -0,0 +1,54 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Test that if an OCSP request is made to a domain that (erroneously)
+// has HSTS status, the request is not upgraded from HTTP to HTTPS.
+
+function run_test() {
+ do_get_profile();
+ // OCSP required means this test will only pass if the request succeeds.
+ Services.prefs.setBoolPref("security.OCSP.require", true);
+
+ // We don't actually make use of stapling in this test. This is just how we
+ // get a TLS connection.
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+
+ let args = [["good", "default-ee", "unused"]];
+ let ocspResponses = generateOCSPResponses(args, "ocsp_certs");
+ let goodOCSPResponse = ocspResponses[0];
+
+ let ocspResponder = new HttpServer();
+ ocspResponder.registerPrefixHandler("/", function (request, response) {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "application/ocsp-response");
+ response.write(goodOCSPResponse);
+ });
+ ocspResponder.start(8888);
+
+ // ocsp-stapling-none.example.com does not staple an OCSP response in the
+ // handshake, so the revocation checking code will attempt to fetch one.
+ // Since the domain of the certificate's OCSP AIA URI is an HSTS host
+ // (as added in the setup of this test, below), a buggy implementation would
+ // upgrade the OCSP request to HTTPS. We specifically prevent this. This
+ // test demonstrates that our implementation is correct in this regard.
+ add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess);
+ add_test(function () { run_next_test(); });
+
+ add_test(function () { ocspResponder.stop(run_next_test); });
+
+ let SSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ let uri = Services.io.newURI("http://localhost", null, null);
+ let sslStatus = new FakeSSLStatus();
+ SSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=10000", sslStatus, 0);
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "localhost", 0),
+ "Domain for the OCSP AIA URI should be considered a HSTS host, otherwise" +
+ " we wouldn't be testing what we think we're testing");
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_required.js b/security/manager/ssl/tests/unit/test_ocsp_required.js
new file mode 100644
index 000000000..81b8677bc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_required.js
@@ -0,0 +1,55 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// In which we connect to a domain (as faked by a server running locally)
+// and start up an OCSP responder (also basically faked) that gives a
+// response with a bad signature. With security.OCSP.require set to true,
+// this should fail (but it also shouldn't cause assertion failures).
+
+var gOCSPRequestCount = 0;
+
+function run_test() {
+ do_get_profile();
+ Services.prefs.setBoolPref("security.OCSP.require", true);
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+
+ // We don't actually make use of stapling in this test. This is just how we
+ // get a TLS connection.
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+
+ let args = [["bad-signature", "default-ee", "unused"]];
+ let ocspResponses = generateOCSPResponses(args, "ocsp_certs");
+ let ocspResponseBadSignature = ocspResponses[0];
+
+ let ocspResponder = new HttpServer();
+ ocspResponder.registerPrefixHandler("/", function (request, response) {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "application/ocsp-response");
+ response.write(ocspResponseBadSignature);
+ gOCSPRequestCount++;
+ });
+ ocspResponder.start(8888);
+
+ add_tests();
+
+ add_test(function () { ocspResponder.stop(run_next_test); });
+
+ run_next_test();
+}
+
+function add_tests()
+{
+ add_connection_test("ocsp-stapling-none.example.com",
+ SEC_ERROR_OCSP_BAD_SIGNATURE);
+ add_connection_test("ocsp-stapling-none.example.com",
+ SEC_ERROR_OCSP_BAD_SIGNATURE);
+ add_test(function () {
+ equal(gOCSPRequestCount, 1,
+ "OCSP request count should be 1 due to OCSP response caching");
+ gOCSPRequestCount = 0;
+ run_next_test();
+ });
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_stapling.js b/security/manager/ssl/tests/unit/test_ocsp_stapling.js
new file mode 100644
index 000000000..36c8aeaaf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling.js
@@ -0,0 +1,209 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// In which we connect to a number of domains (as faked by a server running
+// locally) with and without OCSP stapling enabled to determine that good
+// things happen and bad things don't.
+
+var gExpectOCSPRequest;
+
+function add_ocsp_test(aHost, aExpectedResult, aStaplingEnabled) {
+ add_connection_test(aHost, aExpectedResult,
+ function() {
+ gExpectOCSPRequest = !aStaplingEnabled;
+ clearOCSPCache();
+ clearSessionCache();
+ Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling",
+ aStaplingEnabled);
+ });
+}
+
+function add_tests() {
+ // In the absence of OCSP stapling, these should actually all work.
+ add_ocsp_test("ocsp-stapling-good.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-revoked.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-good-other-ca.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-malformed.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-srverr.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-trylater.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-needssig.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-unauthorized.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-unknown.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-good-other.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-none.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-expired.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-skip-responseBytes.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-critical-extension.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-noncritical-extension.example.com",
+ PRErrorCodeSuccess, false);
+ add_ocsp_test("ocsp-stapling-empty-extensions.example.com",
+ PRErrorCodeSuccess, false);
+
+ // Now test OCSP stapling
+ // The following error codes are defined in security/nss/lib/util/SECerrs.h
+
+ add_ocsp_test("ocsp-stapling-good.example.com", PRErrorCodeSuccess, true);
+
+ add_ocsp_test("ocsp-stapling-revoked.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE, true);
+
+ // SEC_ERROR_OCSP_INVALID_SIGNING_CERT vs SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
+ // depends on whether the CA that signed the response is a trusted CA
+ // (but only with the classic implementation - mozilla::pkix always
+ // results in the error SEC_ERROR_OCSP_INVALID_SIGNING_CERT).
+
+ // This stapled response is from a CA that is untrusted and did not issue
+ // the server's certificate.
+ let certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+ let otherTestCA = constructCertFromFile("ocsp_certs/other-test-ca.pem");
+ add_test(function() {
+ certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.UNTRUSTED);
+ run_next_test();
+ });
+ add_ocsp_test("ocsp-stapling-good-other-ca.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+
+ // The stapled response is from a CA that is trusted but did not issue the
+ // server's certificate.
+ add_test(function() {
+ certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT,
+ Ci.nsIX509CertDB.TRUSTED_SSL);
+ run_next_test();
+ });
+ // TODO(bug 979055): When using ByName instead of ByKey, the error here is
+ // SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE. We should be testing both cases.
+ add_ocsp_test("ocsp-stapling-good-other-ca.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+
+ // TODO: Test the case where the signing cert can't be found at all, which
+ // will result in SEC_ERROR_BAD_DATABASE in the NSS classic case.
+
+ add_ocsp_test("ocsp-stapling-malformed.example.com",
+ SEC_ERROR_OCSP_MALFORMED_REQUEST, true);
+ add_ocsp_test("ocsp-stapling-srverr.example.com",
+ SEC_ERROR_OCSP_SERVER_ERROR, true);
+ add_ocsp_test("ocsp-stapling-trylater.example.com",
+ SEC_ERROR_OCSP_TRY_SERVER_LATER, true);
+ add_ocsp_test("ocsp-stapling-needssig.example.com",
+ SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, true);
+ add_ocsp_test("ocsp-stapling-unauthorized.example.com",
+ SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, true);
+ add_ocsp_test("ocsp-stapling-unknown.example.com",
+ SEC_ERROR_OCSP_UNKNOWN_CERT, true);
+ add_ocsp_test("ocsp-stapling-good-other.example.com",
+ MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING, true);
+ // If the server doesn't staple an OCSP response, we continue as normal
+ // (this means that even though stapling is enabled, we expect an OCSP
+ // request).
+ add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
+ function() {
+ gExpectOCSPRequest = true;
+ clearOCSPCache();
+ clearSessionCache();
+ Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
+ }
+ );
+ add_ocsp_test("ocsp-stapling-empty.example.com",
+ SEC_ERROR_OCSP_MALFORMED_RESPONSE, true);
+
+ add_ocsp_test("ocsp-stapling-skip-responseBytes.example.com",
+ SEC_ERROR_OCSP_MALFORMED_RESPONSE, true);
+
+ add_ocsp_test("ocsp-stapling-critical-extension.example.com",
+ SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, true);
+ add_ocsp_test("ocsp-stapling-noncritical-extension.example.com",
+ PRErrorCodeSuccess, true);
+ // TODO(bug 997994): Disallow empty Extensions in responses
+ add_ocsp_test("ocsp-stapling-empty-extensions.example.com",
+ PRErrorCodeSuccess, true);
+
+ add_ocsp_test("ocsp-stapling-delegated-included.example.com",
+ PRErrorCodeSuccess, true);
+ add_ocsp_test("ocsp-stapling-delegated-included-last.example.com",
+ PRErrorCodeSuccess, true);
+ add_ocsp_test("ocsp-stapling-delegated-missing.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+ add_ocsp_test("ocsp-stapling-delegated-missing-multiple.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+ add_ocsp_test("ocsp-stapling-delegated-no-extKeyUsage.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+ add_ocsp_test("ocsp-stapling-delegated-from-intermediate.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+ add_ocsp_test("ocsp-stapling-delegated-keyUsage-crlSigning.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+ add_ocsp_test("ocsp-stapling-delegated-wrong-extKeyUsage.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+
+ // ocsp-stapling-expired.example.com and
+ // ocsp-stapling-expired-fresh-ca.example.com are handled in
+ // test_ocsp_stapling_expired.js
+
+ // Check that OCSP responder certificates with key sizes below 1024 bits are
+ // rejected, even when the main certificate chain keys are at least 1024 bits.
+ add_ocsp_test("keysize-ocsp-delegated.example.com",
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT, true);
+
+ add_ocsp_test("revoked-ca-cert-used-as-end-entity.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE, true);
+}
+
+function check_ocsp_stapling_telemetry() {
+ let histogram = Cc["@mozilla.org/base/telemetry;1"]
+ .getService(Ci.nsITelemetry)
+ .getHistogramById("SSL_OCSP_STAPLING")
+ .snapshot();
+ equal(histogram.counts[0], 0,
+ "Should have 0 connections for unused histogram bucket 0");
+ equal(histogram.counts[1], 5,
+ "Actual and expected connections with a good response should match");
+ equal(histogram.counts[2], 18,
+ "Actual and expected connections with no stapled response should match");
+ equal(histogram.counts[3], 0,
+ "Actual and expected connections with an expired response should match");
+ equal(histogram.counts[4], 21,
+ "Actual and expected connections with bad responses should match");
+ run_next_test();
+}
+
+function run_test() {
+ do_get_profile();
+
+ let fakeOCSPResponder = new HttpServer();
+ fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
+ response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
+ ok(gExpectOCSPRequest,
+ "Should be getting an OCSP request only when expected");
+ });
+ fakeOCSPResponder.start(8888);
+
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+
+ add_tests();
+
+ add_test(function () {
+ fakeOCSPResponder.stop(check_ocsp_stapling_telemetry);
+ });
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js b/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js
new file mode 100644
index 000000000..b49be85e7
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js
@@ -0,0 +1,184 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// In which we connect to a number of domains (as faked by a server running
+// locally) with OCSP stapling enabled to determine that good things happen
+// and bad things don't, specifically with respect to various expired OCSP
+// responses (stapled and otherwise).
+
+var gCurrentOCSPResponse = null;
+var gOCSPRequestCount = 0;
+
+function add_ocsp_test(aHost, aExpectedResult, aOCSPResponseToServe,
+ aExpectedRequestCount) {
+ add_connection_test(aHost, aExpectedResult,
+ function() {
+ clearOCSPCache();
+ clearSessionCache();
+ gCurrentOCSPResponse = aOCSPResponseToServe;
+ gOCSPRequestCount = 0;
+ },
+ function() {
+ equal(gOCSPRequestCount, aExpectedRequestCount,
+ "Should have made " + aExpectedRequestCount +
+ " fallback OCSP request" + (aExpectedRequestCount == 1 ? "" : "s"));
+ });
+}
+
+do_get_profile();
+Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
+Services.prefs.setIntPref("security.OCSP.enabled", 1);
+Services.prefs.setIntPref("security.pki.sha1_enforcement_level", 4);
+var args = [["good", "default-ee", "unused"],
+ ["expiredresponse", "default-ee", "unused"],
+ ["oldvalidperiod", "default-ee", "unused"],
+ ["revoked", "default-ee", "unused"],
+ ["unknown", "default-ee", "unused"],
+ ];
+var ocspResponses = generateOCSPResponses(args, "ocsp_certs");
+// Fresh response, certificate is good.
+var ocspResponseGood = ocspResponses[0];
+// Expired response, certificate is good.
+var expiredOCSPResponseGood = ocspResponses[1];
+// Fresh signature, old validity period, certificate is good.
+var oldValidityPeriodOCSPResponseGood = ocspResponses[2];
+// Fresh signature, certificate is revoked.
+var ocspResponseRevoked = ocspResponses[3];
+// Fresh signature, certificate is unknown.
+var ocspResponseUnknown = ocspResponses[4];
+
+// sometimes we expect a result without re-fetch
+var willNotRetry = 1;
+// but sometimes, since a bad response is in the cache, OCSP fetch will be
+// attempted for each validation - in practice, for these test certs, this
+// means 6 requests because various hash algorithm and key size combinations
+// are tried.
+var willRetry = 6;
+
+function run_test() {
+ let ocspResponder = new HttpServer();
+ ocspResponder.registerPrefixHandler("/", function(request, response) {
+ if (gCurrentOCSPResponse) {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.setHeader("Content-Type", "application/ocsp-response");
+ response.write(gCurrentOCSPResponse);
+ } else {
+ response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
+ response.write("Internal Server Error");
+ }
+ gOCSPRequestCount++;
+ });
+ ocspResponder.start(8888);
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+
+ // In these tests, the OCSP stapling server gives us a stapled
+ // response based on the host name ("ocsp-stapling-expired" or
+ // "ocsp-stapling-expired-fresh-ca"). We then ensure that we're
+ // properly falling back to fetching revocation information.
+ // For ocsp-stapling-expired.example.com, the OCSP stapling server
+ // staples an expired OCSP response. The certificate has not expired.
+ // For ocsp-stapling-expired-fresh-ca.example.com, the OCSP stapling
+ // server staples an OCSP response with a recent signature but with an
+ // out-of-date validity period. The certificate has not expired.
+ add_ocsp_test("ocsp-stapling-expired.example.com", PRErrorCodeSuccess,
+ ocspResponseGood, willNotRetry);
+ add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", PRErrorCodeSuccess,
+ ocspResponseGood, willNotRetry);
+ // if we can't fetch a more recent response when
+ // given an expired stapled response, we terminate the connection.
+ add_ocsp_test("ocsp-stapling-expired.example.com",
+ SEC_ERROR_OCSP_OLD_RESPONSE,
+ expiredOCSPResponseGood, willRetry);
+ add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
+ SEC_ERROR_OCSP_OLD_RESPONSE,
+ expiredOCSPResponseGood, willRetry);
+ add_ocsp_test("ocsp-stapling-expired.example.com",
+ SEC_ERROR_OCSP_OLD_RESPONSE,
+ oldValidityPeriodOCSPResponseGood, willRetry);
+ add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
+ SEC_ERROR_OCSP_OLD_RESPONSE,
+ oldValidityPeriodOCSPResponseGood, willRetry);
+ add_ocsp_test("ocsp-stapling-expired.example.com",
+ SEC_ERROR_OCSP_OLD_RESPONSE,
+ null, willNotRetry);
+ add_ocsp_test("ocsp-stapling-expired.example.com",
+ SEC_ERROR_OCSP_OLD_RESPONSE,
+ null, willNotRetry);
+ // Of course, if the newer response indicates Revoked or Unknown,
+ // that status must be returned.
+ add_ocsp_test("ocsp-stapling-expired.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE,
+ ocspResponseRevoked, willNotRetry);
+ add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE,
+ ocspResponseRevoked, willNotRetry);
+ add_ocsp_test("ocsp-stapling-expired.example.com",
+ SEC_ERROR_OCSP_UNKNOWN_CERT,
+ ocspResponseUnknown, willRetry);
+ add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
+ SEC_ERROR_OCSP_UNKNOWN_CERT,
+ ocspResponseUnknown, willRetry);
+
+ // If the response is expired but indicates Revoked or Unknown and a
+ // newer status can't be fetched, the Revoked or Unknown status will
+ // be returned.
+ add_ocsp_test("ocsp-stapling-revoked-old.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE,
+ null, willNotRetry);
+ add_ocsp_test("ocsp-stapling-unknown-old.example.com",
+ SEC_ERROR_OCSP_UNKNOWN_CERT,
+ null, willNotRetry);
+ // If the response is expired but indicates Revoked or Unknown and
+ // a newer status can be fetched and successfully verified, this
+ // should result in a successful certificate verification.
+ add_ocsp_test("ocsp-stapling-revoked-old.example.com", PRErrorCodeSuccess,
+ ocspResponseGood, willNotRetry);
+ add_ocsp_test("ocsp-stapling-unknown-old.example.com", PRErrorCodeSuccess,
+ ocspResponseGood, willNotRetry);
+ // If a newer status can be fetched but it fails to verify, the
+ // Revoked or Unknown status of the expired stapled response
+ // should be returned.
+ add_ocsp_test("ocsp-stapling-revoked-old.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE,
+ expiredOCSPResponseGood, willRetry);
+ add_ocsp_test("ocsp-stapling-unknown-old.example.com",
+ SEC_ERROR_OCSP_UNKNOWN_CERT,
+ expiredOCSPResponseGood, willRetry);
+
+ // These tests are verifying that an valid but very old response
+ // is rejected as a valid stapled response, requiring a fetch
+ // from the ocsp responder.
+ add_ocsp_test("ocsp-stapling-ancient-valid.example.com", PRErrorCodeSuccess,
+ ocspResponseGood, willNotRetry);
+ add_ocsp_test("ocsp-stapling-ancient-valid.example.com",
+ SEC_ERROR_REVOKED_CERTIFICATE,
+ ocspResponseRevoked, willNotRetry);
+ add_ocsp_test("ocsp-stapling-ancient-valid.example.com",
+ SEC_ERROR_OCSP_UNKNOWN_CERT,
+ ocspResponseUnknown, willRetry);
+
+ add_test(function () { ocspResponder.stop(run_next_test); });
+ add_test(check_ocsp_stapling_telemetry);
+ run_next_test();
+}
+
+function check_ocsp_stapling_telemetry() {
+ let histogram = Cc["@mozilla.org/base/telemetry;1"]
+ .getService(Ci.nsITelemetry)
+ .getHistogramById("SSL_OCSP_STAPLING")
+ .snapshot();
+ equal(histogram.counts[0], 0,
+ "Should have 0 connections for unused histogram bucket 0");
+ equal(histogram.counts[1], 0,
+ "Actual and expected connections with a good response should match");
+ equal(histogram.counts[2], 0,
+ "Actual and expected connections with no stapled response should match");
+ equal(histogram.counts[3], 21,
+ "Actual and expected connections with an expired response should match");
+ equal(histogram.counts[4], 0,
+ "Actual and expected connections with bad responses should match");
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_stapling_with_intermediate.js b/security/manager/ssl/tests/unit/test_ocsp_stapling_with_intermediate.js
new file mode 100644
index 000000000..21676f1d5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling_with_intermediate.js
@@ -0,0 +1,45 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// In which we connect to a server that staples an OCSP response for a
+// certificate signed by an intermediate that has an OCSP AIA to ensure
+// that an OCSP request is not made for the intermediate.
+
+var gOCSPRequestCount = 0;
+
+function add_ocsp_test(aHost, aExpectedResult) {
+ add_connection_test(aHost, aExpectedResult,
+ function() {
+ clearOCSPCache();
+ clearSessionCache();
+ });
+}
+
+function run_test() {
+ do_get_profile();
+ Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
+
+ let ocspResponder = new HttpServer();
+ ocspResponder.registerPrefixHandler("/", function(request, response) {
+ gOCSPRequestCount++;
+ response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
+ let body = "Refusing to return a response";
+ response.bodyOutputStream.write(body, body.length);
+ });
+ ocspResponder.start(8888);
+
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+
+ add_ocsp_test("ocsp-stapling-with-intermediate.example.com",
+ PRErrorCodeSuccess);
+
+ add_test(function () { ocspResponder.stop(run_next_test); });
+ add_test(function() {
+ equal(gOCSPRequestCount, 0, "No OCSP requests should have been made");
+ run_next_test();
+ });
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_timeout.js b/security/manager/ssl/tests/unit/test_ocsp_timeout.js
new file mode 100644
index 000000000..1c4803371
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_timeout.js
@@ -0,0 +1,88 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// This test connects to ocsp-stapling-none.example.com to test that OCSP
+// requests are cancelled if they're taking too long.
+// ocsp-stapling-none.example.com doesn't staple an OCSP response, so
+// connecting to it will cause a request to the OCSP responder. As with all of
+// these tests, the OCSP AIA (i.e. the url of the responder) in the certificate
+// is http://localhost:8888. Since this test opens a TCP socket listening on
+// port 8888 that just accepts connections and then ignores them (with
+// connect/read/write timeouts of 30 seconds), the OCSP requests should cancel
+// themselves. When OCSP hard-fail is enabled, connections will be terminated.
+// Otherwise, they will succeed.
+
+var gSocketListener = {
+ onSocketAccepted: function(serverSocket, socketTransport) {
+ socketTransport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 30);
+ socketTransport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 30);
+ },
+
+ onStopListening: function(serverSocket, status) {}
+};
+
+function run_test() {
+ do_get_profile();
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+
+ add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
+
+ let socket = Cc["@mozilla.org/network/server-socket;1"]
+ .createInstance(Ci.nsIServerSocket);
+ socket.init(8888, true, -1);
+ socket.asyncListen(gSocketListener);
+
+ add_tests_in_mode(true);
+ add_tests_in_mode(false);
+
+ add_test(function() { socket.close(); run_next_test(); });
+ run_next_test();
+}
+
+function add_tests_in_mode(useHardFail) {
+ let startTime;
+ add_test(function () {
+ Services.prefs.setBoolPref("security.OCSP.require", useHardFail);
+ startTime = new Date();
+ run_next_test();
+ });
+
+ add_connection_test("ocsp-stapling-none.example.com", useHardFail
+ ? SEC_ERROR_OCSP_SERVER_ERROR
+ : PRErrorCodeSuccess, clearSessionCache);
+
+ // Reset state
+ add_test(function() {
+ let endTime = new Date();
+ let timeDifference = endTime - startTime;
+ do_print(`useHardFail = ${useHardFail}`);
+ do_print(`startTime = ${startTime.getTime()} (${startTime})`);
+ do_print(`endTime = ${endTime.getTime()} (${endTime})`);
+ do_print(`timeDifference = ${timeDifference}ms`);
+
+ // With OCSP hard-fail on, we timeout after 10 seconds.
+ // With OCSP soft-fail, we timeout after 2 seconds.
+ // Date() is not guaranteed to be monotonic, so add extra fuzz time to
+ // prevent intermittent failures (this only appeared to be a problem on
+ // Windows XP). See Bug 1121117.
+ const FUZZ_MS = 300;
+ if (useHardFail) {
+ ok(timeDifference + FUZZ_MS > 10000,
+ "Automatic OCSP timeout should be about 10s for hard-fail");
+ } else {
+ ok(timeDifference + FUZZ_MS > 2000,
+ "Automatic OCSP timeout should be about 2s for soft-fail");
+ }
+ // Make sure we didn't wait too long.
+ // (Unfortunately, we probably can't have a tight upper bound on
+ // how long is too long for this test, because we might be running
+ // on slow hardware.)
+ ok(timeDifference < 60000,
+ "Automatic OCSP timeout shouldn't be more than 60s");
+ clearOCSPCache();
+ run_next_test();
+ });
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url.js b/security/manager/ssl/tests/unit/test_ocsp_url.js
new file mode 100644
index 000000000..799c934d0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url.js
@@ -0,0 +1,137 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"use strict";
+
+// In which we try to validate several ocsp responses, checking in particular
+// if the ocsp url is valid and the path expressed is correctly passed to
+// the caller.
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+const SERVER_PORT = 8888;
+
+function failingOCSPResponder() {
+ return getFailingHttpServer(SERVER_PORT, ["www.example.com"]);
+}
+
+function start_ocsp_responder(expectedCertNames, expectedPaths) {
+ return startOCSPResponder(SERVER_PORT, "www.example.com",
+ "test_ocsp_url", expectedCertNames, expectedPaths);
+}
+
+function check_cert_err(cert_name, expected_error) {
+ let cert = constructCertFromFile("test_ocsp_url/" + cert_name + ".pem");
+ return checkCertErrorGeneric(certdb, cert, expected_error,
+ certificateUsageSSLServer);
+}
+
+function run_test() {
+ addCertFromFile(certdb, "test_ocsp_url/ca.pem", 'CTu,CTu,CTu');
+ addCertFromFile(certdb, "test_ocsp_url/int.pem", ',,');
+
+ // Enabled so that we can force ocsp failure responses.
+ Services.prefs.setBoolPref("security.OCSP.require", true);
+
+ Services.prefs.setCharPref("network.dns.localDomains",
+ "www.example.com");
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+
+ // Note: We don't test the case of a well-formed HTTP URL with an empty port
+ // because the OCSP code would then send a request to port 80, which we
+ // can't use in tests.
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ check_cert_err("bad-scheme", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ check_cert_err("empty-scheme-url", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(() => {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ check_cert_err("ftp-url", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ check_cert_err("https-url", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = start_ocsp_responder(["hTTp-url"], ["hTTp-url"]);
+ check_cert_err("hTTp-url", PRErrorCodeSuccess);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ check_cert_err("negative-port", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ // XXX Bug 1013615 parser accepts ":8888" as hostname
+ check_cert_err("no-host-url", SEC_ERROR_OCSP_SERVER_ERROR);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = start_ocsp_responder(["no-path-url"], ['']);
+ check_cert_err("no-path-url", PRErrorCodeSuccess);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ check_cert_err("no-scheme-host-port", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ check_cert_err("no-scheme-url", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+ ocspResponder.stop(run_next_test);
+ });
+
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = failingOCSPResponder();
+ check_cert_err("unknown-scheme", SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
+ ocspResponder.stop(run_next_test);
+ });
+
+ // Note: We currently don't have anything that ensures user:pass sections
+ // weren't sent. The following test simply checks that such sections
+ // don't cause failures.
+ add_test(() => {
+ clearOCSPCache();
+ let ocspResponder = start_ocsp_responder(["user-pass"], [""]);
+ check_cert_err("user-pass", PRErrorCodeSuccess);
+ ocspResponder.stop(run_next_test);
+ });
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/bad-scheme.pem b/security/manager/ssl/tests/unit/test_ocsp_url/bad-scheme.pem
new file mode 100644
index 000000000..861b9aafa
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/bad-scheme.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4jCCAcygAwIBAgIUCaJzhLV6+ZV0VKdbJAcMFrvd69gwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAVMRMwEQYDVQQDDApiYWQtc2NoZW1lMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo
+4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDD
+SeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFX
+kD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUx
+owyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/
+Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozEwLzAtBggrBgEFBQcB
+AQQhMB8wHQYIKwYBBQUHMAGGES93d3cuZXhhbXBsZS5jb20vMAsGCSqGSIb3DQEB
+CwOCAQEAXYD4EqSv7TXWNlkAHZHg5LCCmbM9pRzAsw/tkYPAiW0OvWQsIfqQpQQG
+1e5A4ENvTtOmZbvLTsqjx4k6+mAFHUl/Q/FaelMAHYSGOLivbWeAAVKz6gB862Vy
+tP9+vkhT6KvefbylPNMXpa0vJME5n+CbA0NM2s0DRaE/rfADfYS8sh2rC0RaJ0yz
+aqy833FmHhMgwkzOICo/RJawd+9qBbksa5O+Dq1ybYMVKA3m4IkeIBup/5AHz30n
+hKX1oU/kO+/eDb9nr/lzEmRwBPP9w93rBdEE6210278nzfTj6qzIHYAqpxt60eqR
+BDL9i3piPxTmjj46SHBwQ29i5bcbuA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/bad-scheme.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/bad-scheme.pem.certspec
new file mode 100644
index 000000000..12cc07279
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/bad-scheme.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:bad-scheme
+extension:authorityInformationAccess:/www.example.com/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/ca.pem b/security/manager/ssl/tests/unit/test_ocsp_url/ca.pem
new file mode 100644
index 000000000..1a18e2bf0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUL5zykZEc2ro5d6th43aWGfm735cwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
+DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHPYBjNnv//Ssc8Elepb8SWIXRdahKbL
+/dcPoMR+7yhJVaelUaxdwUytJWJAGdkkuv+P+G4b82RVYEXT+9k1S/aAfByFyR9q
+vS7POfdy/ZPfGTXltlnmYX/84a6QeYQa4Nl4JpIOXBCesLxmErBhczka6D26iqsz
+GeseKRSjVPgF3mXc2CRGZnTDRhUmd7wOABLmj7GtuFvOm96363M3IUByMohvoj1G
+dic3s5D0seXwTKnEc5B27lJt7Q0oIXEldL+UW8Mo1hfGWQeXzqTZbpOVLnVWvHBH
+H8yYs5hyH01qFJZbztJ1JJ3F2NpYLlr4P5I6fW2e9w5MG/VMQRU3wzQ=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/ca.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/ca.pem.certspec
new file mode 100644
index 000000000..d809dbd63
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/ca.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:ca
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/empty-scheme-url.pem b/security/manager/ssl/tests/unit/test_ocsp_url/empty-scheme-url.pem
new file mode 100644
index 000000000..94d4ba65e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/empty-scheme-url.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7zCCAdmgAwIBAgIUOTJ+sDQz8pANxE2LQvwLOgmcu/EwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAbMRkwFwYDVQQDDBBlbXB0eS1zY2hlbWUtdXJsMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFds
+JHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4
+ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25
+iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu3
+4pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42
+yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozgwNjA0Bggr
+BgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGDovL3d3dy5leGFtcGxlLmNvbTo4ODg4
+LzALBgkqhkiG9w0BAQsDggEBAGVsX7ECTXpR66t/SCCb+ff6dAjsrc2FxrsToTav
+WNMumGFeVeBE/oTi2c1UNuWM1Lui1Dm6ZpK8Meau7r97ZtumhLF1T0Mqg9cr2ZPf
+WCGaaO/BS/bby4e9o2pxWkGcSD10vXjwZvEPVBB6JF6CW9vSV1bqutig08aNw7na
++73sRHgWbeXMDBbcbtbgR4F0CY5SCqkrPvclP89mC8Qn1yWjM0xuJLAcIaNupdzr
+H7RHiUVTmf6VIBjuOuSGpXGTpxPCn63rDo1DO0o4z/UFwjrEUrSnQ4/4ouRc3V2/
+BdUN/myc0Ao/kPKK/w/oB4YchP44YxTIwKL22I5DhsOJuGE=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/empty-scheme-url.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/empty-scheme-url.pem.certspec
new file mode 100644
index 000000000..e8959653f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/empty-scheme-url.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:empty-scheme-url
+extension:authorityInformationAccess:://www.example.com:8888/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/ftp-url.pem b/security/manager/ssl/tests/unit/test_ocsp_url/ftp-url.pem
new file mode 100644
index 000000000..4ddeaa0e5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/ftp-url.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6TCCAdOgAwIBAgIUX8TTEyzTjyKkXvlNDjfOeVgdwUkwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjASMRAwDgYDVQQDDAdmdHAtdXJsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4Ngf
+vbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTb
+uUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3S
+O8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR
+3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv
+5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozswOTA3BggrBgEFBQcBAQQr
+MCkwJwYIKwYBBQUHMAGGG2Z0cDovL3d3dy5leGFtcGxlLmNvbTo4ODg4LzALBgkq
+hkiG9w0BAQsDggEBAD8v/SRKYMHiPDPVJayeugI6KhLXFpXFxwzUK5Aq1mjGjIz1
+ibRoY2JcrXFrZ13V8Gtb+MjMLIi72UcLyIVvEaUhFo7X8rcP5zajmaetGuaKKV61
+E7LOuXLaGY/zQOidgpHgU7QCix/MyGoVuqHvOrwGH9V5UalxZKTOrJ4Dd66XTd3p
++5cy158BhzJRbi1y0XST/ePfQAlA3dQmI0m7UINiAQofSvzZbybR/dyDWhLQTNsG
+NtQ2QbilokejHOqrt/XJ+BGx5ebvY8U9pS26+r0k4CfDtxSYgIc7/mK9LIT5KyhU
+LuTdXpdddngkOMKHQ0XgF39F3cgkg3IcjjAbjOE=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/ftp-url.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/ftp-url.pem.certspec
new file mode 100644
index 000000000..9f50a7d79
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/ftp-url.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:ftp-url
+extension:authorityInformationAccess:ftp://www.example.com:8888/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/hTTp-url.pem b/security/manager/ssl/tests/unit/test_ocsp_url/hTTp-url.pem
new file mode 100644
index 000000000..35b5b0fbf
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/hTTp-url.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8zCCAd2gAwIBAgIUDVa/q45VECP/2micfLYGBWXE7aMwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjATMREwDwYDVQQDDAhoVFRwLXVybDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODY
+H72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk
+27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A9
+0jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMM
+kd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaL
+L+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaNEMEIwQAYIKwYBBQUHAQEE
+NDAyMDAGCCsGAQUFBzABhiRoVFRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgvaFRU
+cC11cmwwCwYJKoZIhvcNAQELA4IBAQCPVRLwtymkJVeBFO8jZ/WitBfyAqTH3PN8
+8HXxYbN3Cx49MqEwET+zUj/irQsKx59vZcY5UUO3icqgbcUGidxgMoOxlXxdsQjZ
+Xe6ThY27HPnV5c7mI2SQwdr/IAhHxml7OfjiZ0VoFl4RsUKghU77z0x0NMDQWN6m
+Tg19Hqyy5t2fC4zpRUQifBNEaz9tHYKN/AC8Fu2iFYPOQcz+g+KGDvwCiKdSZJba
+9yVMJolq6DWbKr20aSdJIOqQV0S4Ww2G88uxUcpwZ5wRa2WOW8a/FnusNP3Anhiy
+RrEJh/Dzdpsi24YBfQ9m6+D9SFfqEjfKJLLcLI6jrCc68v2OfJfa
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/hTTp-url.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/hTTp-url.pem.certspec
new file mode 100644
index 000000000..10b1504b2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/hTTp-url.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:hTTp-url
+extension:authorityInformationAccess:hTTp://www.example.com:8888/hTTp-url
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/https-url.pem b/security/manager/ssl/tests/unit/test_ocsp_url/https-url.pem
new file mode 100644
index 000000000..3229f8b6b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/https-url.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC9jCCAeCgAwIBAgIUdyMaqHO/yYxno+R+AgpRtlTqEHEwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAUMRIwEAYDVQQDDAlodHRwcy11cmwwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjRjBEMEIGCCsGAQUFBwEB
+BDYwNDAyBggrBgEFBQcwAYYmaHR0cHM6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9o
+dHRwcy11cmwwCwYJKoZIhvcNAQELA4IBAQB4H70+zX9CJm7Y6AitWnaUheWOow2l
+JdO+iOAFM6HsxWu/X/ukZ+p6IEj79KiwyYJuyDPxms3ZUYmKEGHfChFalJbZqT8U
+DNhgKUZYGMM4VK94plUGl8yaiW0r7kCygLrsWT7+NkkLdsZ8AV2R64brTa6BcvO6
+msbyHZ6XX+W0IzlWvnNVTbTVaHu+YIi5oY+z9Zn7Q9cn8mUGn3Txk6/o7iZ8HSGo
+f0RHw6WphwniPmYy6En8mOHJca30iu960Q4KVHZ0NzrVSvRjZugbkSdEp5XPbzn1
+27jMaOWtst30JTMmLtKKkeb6rhDgIhF8jhSbFaygIERYLSuTryh31yRn
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/https-url.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/https-url.pem.certspec
new file mode 100644
index 000000000..891005bf5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/https-url.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:https-url
+extension:authorityInformationAccess:https://www.example.com:8888/https-url
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/int.key b/security/manager/ssl/tests/unit/test_ocsp_url/int.key
new file mode 100644
index 000000000..8af23e068
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/int.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAECggEBAJ7LzjhhpFTsseD+j4XdQ8kvWCXOLpl4hNDhqUnaosWs
+VZskBFDlrJ/gw+McDu+mUlpl8MIhlABO4atGPd6e6CKHzJPnRqkZKcXmrD2IdT9s
+JbpZeec+XY+yOREaPNq4pLDN9fnKsF8SM6ODNcZLVWBSXn47kq18dQTPHcfLAFeI
+r8vh6Pld90AqFRUw1YCDRoZOs3CqeZVqWHhiy1M3kTB/cNkcltItABppAJuSPGgz
+iMnzbLm16+ZDAgQceNkIIGuHAJy4yrrK09vbJ5L7kRss9NtmA1hb6a4Mo7jmQXqg
+SwbkcOoaO1gcoDpngckxW2KzDmAR8iRyWUbuxXxtlEECgYEA3W4dT//r9o2InE0R
+TNqqnKpjpZN0KGyKXCmnF7umA3VkTVyqZ0xLi8cyY1hkYiDkVQ12CKwn1Vttt0+N
+gSfvj6CQmLaRR94GVXNEfhg9Iv59iFrOtRPZWB3V4HwakPXOCHneExNx7O/JznLp
+xD3BJ9I4GQ3oEXc8pdGTAfSMdCsCgYEA16dz2evDgKdn0v7Ak0rU6LVmckB3Gs3r
+ta15b0eP7E1FmF77yVMpaCicjYkQL63yHzTi3UlA66jAnW0fFtzClyl3TEMnXpJR
+3b5JCeH9O/Hkvt9Go5uLODMo70rjuVuS8gcK8myefFybWH/t3gXo59hspXiG+xZY
+EKd7mEW8MScCgYEAlkcrQaYQwK3hryJmwWAONnE1W6QtS1oOtOnX6zWBQAul3RMs
+2xpekyjHu8C7sBVeoZKXLt+X0SdR2Pz2rlcqMLHqMJqHEt1OMyQdse5FX8CT9byb
+WS11bmYhR08ywHryL7J100B5KzK6JZC7smGu+5WiWO6lN2VTFb6cJNGRmS0CgYAo
+tFCnp1qFZBOyvab3pj49lk+57PUOOCPvbMjo+ibuQT+LnRIFVA8Su+egx2got7pl
+rYPMpND+KiIBFOGzXQPVqFv+Jwa9UPzmz83VcbRspiG47UfWBbvnZbCqSgZlrCU2
+TaIBVAMuEgS4VZ0+NPtbF3yaVv+TUQpaSmKHwVHeLQKBgCgGe5NVgB0u9S36ltit
+tYlnPPjuipxv9yruq+nva+WKT0q/BfeIlH3IUf2qNFQhR6caJGv7BU7naqNGq80m
+ks/J5ExR5vBpxzXgc7oBn2pyFJYckbJoccrqv48GRBigJpDjmo1f8wZ7fNt/ULH1
+NBinA5ZsT8d0v3QCr2xDJH9D
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/int.key.keyspec b/security/manager/ssl/tests/unit/test_ocsp_url/int.key.keyspec
new file mode 100644
index 000000000..4ad96d515
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/int.key.keyspec
@@ -0,0 +1 @@
+default
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/int.pem b/security/manager/ssl/tests/unit/test_ocsp_url/int.pem
new file mode 100644
index 000000000..fd60e5fe2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/int.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxjCCAbCgAwIBAgIUazy/vTocAuxP85PTc+O1JXs8WWEwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMA4xDDAKBgNVBAMMA2ludDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAab
+bhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmts
+Du0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhI
+H6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8
+rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kX
+Mbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNV
+HQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQA6lr0lbqcaGYjYAAcA5BngiUobuYFn
+4jdYK9eR6hiT5PmYRQZ9/y+2aYNF/ygiBBqBdEq/Nhrm35WeUHvDBaT8OZLBjf+g
+krEAmu2ivrHZWrx16HBVDd9JdTUCx8j1HUo5fadFnsQh7nuh/VIoemox+/e8mKfh
++fW3noAoH/MRfP9VYoS0KzkW8ILiWOR1joNOHDZzanMiM/YCHO1nckq2ntI2T+kO
+MNMkB+j1w5Fu6P8pgyToleHs3WmlWAeDjXygZkEhg+9uuBXb8/IyuS3cYt9ovhSh
+++A25JRmqaQn2Ywd+CMsGe4MTYOsRnZPK0Co6TBteRWRdwSpqzb+UOqY
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/int.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/int.pem.certspec
new file mode 100644
index 000000000..a7f6d8141
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/int.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:int
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/moz.build b/security/manager/ssl/tests/unit/test_ocsp_url/moz.build
new file mode 100644
index 000000000..5fd0335fb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/moz.build
@@ -0,0 +1,33 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'bad-scheme.pem',
+# 'ca.pem',
+# 'empty-scheme-url.pem',
+# 'ftp-url.pem',
+# 'hTTp-url.pem',
+# 'https-url.pem',
+# 'int.pem',
+# 'negative-port.pem',
+# 'no-host-url.pem',
+# 'no-path-url.pem',
+# 'no-scheme-host-port.pem',
+# 'no-scheme-url.pem',
+# 'unknown-scheme.pem',
+# 'user-pass.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
+#
+#test_keys = (
+# 'int.key',
+#)
+#
+#for test_key in test_keys:
+# GeneratedTestKey(test_key)
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/negative-port.pem b/security/manager/ssl/tests/unit/test_ocsp_url/negative-port.pem
new file mode 100644
index 000000000..d5da47063
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/negative-port.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7jCCAdigAwIBAgIUOYKMbwiA6Ox6tlyXbkCVolKaQrUwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAYMRYwFAYDVQQDDA1uZWdhdGl2ZS1wb3J0MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvB
+xyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmT
+qyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5
+kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYS
+wHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwk
+BCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozowODA2BggrBgEF
+BQcBAQQqMCgwJgYIKwYBBQUHMAGGGmh0dHA6Ly93d3cuZXhhbXBsZS5jb206LTEv
+MAsGCSqGSIb3DQEBCwOCAQEADBQNEPkXMARLS21MqOa2IrMxwTEJruvmt52cmdpP
+5g3D6U+YNrCS3sBXz4iHOpTJzPq6bcA4l2MsozaXuNXGxtYmqKVAOQaeZEkfkidH
+VRRrYlDx9krWWmbwMdXpHMdEvaa8ALbmdVHZGFvr/SULQJZ0bOJlS0T9QsbGvPJN
+85O5sB92GF3xX1/PfSEE4adoNHjoi3iBwkCHbt8l+8Yrxi0NFv+jyZ1Cjl6HgA4H
+/5QAdQK1QRSOcWdoiUKZnmS7R7lV4TUZ4ddmd1xKo6ZkM7lqKJWZRJaYyBk/2oLC
+J1VpmiIPGzU8pqavEiJkI73wsKqIvLhzXE30+cmHu6lx/Q==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/negative-port.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/negative-port.pem.certspec
new file mode 100644
index 000000000..fce6d4384
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/negative-port.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:negative-port
+extension:authorityInformationAccess:http://www.example.com:-1/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/no-host-url.pem b/security/manager/ssl/tests/unit/test_ocsp_url/no-host-url.pem
new file mode 100644
index 000000000..e1dd6e432
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/no-host-url.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3zCCAcmgAwIBAgIUdxTe9sPzOgKwgY0vD+1x2d7atJkwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAWMRQwEgYDVQQDDAtuby1ob3N0LXVybDCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMtMCswKQYIKwYBBQUH
+AQEEHTAbMBkGCCsGAQUFBzABhg1odHRwOi8vOjg4ODgvMAsGCSqGSIb3DQEBCwOC
+AQEAYLCyovqbhUruG91y2BOZo79Hios1jHFDSQQaiJPnCWv5wwDo6ZNaIDO4HZGz
+WOyHUVeau3OHN2j1xSPJa2e9q+mHocU7NPMYT9GTbFOrvq6wKNl0ySpPDA87EqFa
+Xumc/iMxIEqbTM85MTBQoMwBXH7Dn4YGbiGyKldHTeiHdBNYk7ck3810hTh5In6n
+sJjeH04x6HnX2bN87w5ydW8IupdQtRRlyi7D+Xrh5/P6DgKQeBYYgZYP8pm1c1sv
+ElZJ5HC8zNSdpbox8NQ+TeKJSH66Uzp4xzC5fC387bhT3pqF+L0mXey5+PAirPwe
+2qCSHS1Wrob1dEOL2F2OtxCc7A==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/no-host-url.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/no-host-url.pem.certspec
new file mode 100644
index 000000000..4ac76e7eb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/no-host-url.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:no-host-url
+extension:authorityInformationAccess:http://:8888/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/no-path-url.pem b/security/manager/ssl/tests/unit/test_ocsp_url/no-path-url.pem
new file mode 100644
index 000000000..0a2b18870
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/no-path-url.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7TCCAdegAwIBAgIUAXS6lqxRzJJJN9dWf3AQsJXfmrQwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAWMRQwEgYDVQQDDAtuby1wYXRoLXVybDCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaM7MDkwNwYIKwYBBQUH
+AQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vd3d3LmV4YW1wbGUuY29tOjg4ODgw
+CwYJKoZIhvcNAQELA4IBAQARmP6mnoEp1iAK4icGW3lqQK4bv94YAIn+h2d6lWqS
+I1ccW2lfzPowYNfcbvdPqgytOkBzxVZGjMfWhtWQrTHhxKh+qp8oQPEtGcGMYma7
+tuaeN5BZnoRMbRmGw/i/Wl7MgByjGRvrcwyZF+zb5SxUqgt4fRYY0IsaWQP5Zdmu
+tk31gvNbRhT4aFeteb8XuyEt4zRwk30bjXHRWSbWO29fqTx5PpVXJzdRYZr1fLqL
+6ytWx/Wri5WgvQgqYCL8aHng9qOzJPz8/ASNXzwmHjiPxEKf+Ebw3Nxo4NZ/3NdW
+AcWN8hLLSnGun0gkTEuzYhgN/lglftInFXvEWYCLc/a7
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/no-path-url.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/no-path-url.pem.certspec
new file mode 100644
index 000000000..497bb2879
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/no-path-url.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:no-path-url
+extension:authorityInformationAccess:http://www.example.com:8888
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-host-port.pem b/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-host-port.pem
new file mode 100644
index 000000000..cee29837d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-host-port.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAcWgAwIBAgIUP1Op7k2Kxth54BUkOFVzyl/3GBgwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAeMRwwGgYDVQQDDBNuby1zY2hlbWUtaG9zdC1wb3J0MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoyEwHzAd
+BggrBgEFBQcBAQQRMA8wDQYIKwYBBQUHMAGGAS8wCwYJKoZIhvcNAQELA4IBAQAQ
+t9S6Ca0G+iUIlFzRZWzt/yrSSYNqKN0GZkMEEQc0CuPK7y55UxsO0reNHatBjFMN
+6UMJa6GpIimFOcRmEvGHo5N26O0glZr+lUv66Z+/YszzG6EY3W3QLo9TUBIfkonv
+Fvt5F/EygyjUq8JoOMjuFZrGrGuLA2wkbD/xQZdZSwZKfOVuPcShPnCZZIFm6Wyu
+qzg7IKcHonKqt4ClHnCWJp1gSjbpGLwZnnjkQWOpOavnVdCxMFh+soPUqmZfomAd
+NMM/OXt3T8SqTh6zLykKPmT7mLvdT0oK/wMOQAAqYnZ1lL/TaDl9JiWmiUHJV6wK
+Iwd64wWH42VHvJa7RkGx
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-host-port.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-host-port.pem.certspec
new file mode 100644
index 000000000..42a555e41
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-host-port.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:no-scheme-host-port
+extension:authorityInformationAccess:/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-url.pem b/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-url.pem
new file mode 100644
index 000000000..58d799cb1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-url.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6TCCAdOgAwIBAgIUU9pq10HPzAkXsubwVrSbSByUa0MwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAYMRYwFAYDVQQDDA1uby1zY2hlbWUtdXJsMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvB
+xyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmT
+qyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5
+kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYS
+wHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwk
+BCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABozUwMzAxBggrBgEF
+BQcBAQQlMCMwIQYIKwYBBQUHMAGGFXd3dy5leGFtcGxlLmNvbTo4ODg4LzALBgkq
+hkiG9w0BAQsDggEBAKpD33VUYjJ48aRC30LmPfcncPdPb6TshHzLEWVk17sojkVl
+UqzljaHcoE5yj76qG30POy/Kdy3XC7Ml3divY3feIPF9OhW5Ajt1pMMLPbIhGTK2
+vW3VXR4eD3VesXyPaJqm6xp0kKjOi0E/tHmnVCVeSdv9VxPmiBcEK8vfnA0H5qHH
+KeV/ZX1DQSAS+naG8aEPhUFKa9x815Xj1t7r6xDkGOvLfvVtw1Md9lP62numDRc0
+nDC/qu8qcZUGXDJgEpqWgBpF6jfjqIAWQfioMI02xFIOqq5fSq6BCbKgpHAkVKp7
+rWobSHnjDNlPTfjW7m9U/0evheZ6ICz404fUENw=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-url.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-url.pem.certspec
new file mode 100644
index 000000000..a82196a6d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/no-scheme-url.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:no-scheme-url
+extension:authorityInformationAccess:www.example.com:8888/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/unknown-scheme.pem b/security/manager/ssl/tests/unit/test_ocsp_url/unknown-scheme.pem
new file mode 100644
index 000000000..1ab089a8c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/unknown-scheme.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC6zCCAdWgAwIBAgIUK9u6obbJ2SPIjRSDpKRrgdRN/awwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAZMRcwFQYDVQQDDA51bmtub3duLXNjaGVtZTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7
+wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCAp
+k6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhh
+eZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KW
+EsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONssc
+JAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaM2MDQwMgYIKwYB
+BQUHAQEEJjAkMCIGCCsGAQUFBzABhhZ0dHA6Ly93d3cuZXhhbXBsZS5jb20vMAsG
+CSqGSIb3DQEBCwOCAQEANVw4eInvNA1+4oQxbmPEZ7IDm/Cq5u2kn0/Dm6NqI1YS
+YmQtw7F6ooE1MDKuCo0nVvvbRjlv68WiIYSaGZjpD8mcZJEDGXXUaVivcPO9jakQ
+pu+wzUjo41YmvvSCgBlHu7w0QWvQL4Ybk6hxZxDGIBM9HoiNnxaxKPehfc2Knb8V
+RyAZvPA/0Nwtm3L+lZYmNA3i9WBWSC3p2jblCTt62UhevnmKX9ASX2TNpLDI6Brn
+hoBpQUzQrXWYklC2GxBL28kx0in4NrQ264vNLO9weJacQY/Hxn/gJNyUguFDE/hk
+nhc9SA29F8YtLJ6fKzizMypqQEtn1oTW3wPORruoDw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/unknown-scheme.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/unknown-scheme.pem.certspec
new file mode 100644
index 000000000..008945539
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/unknown-scheme.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:unknown-scheme
+extension:authorityInformationAccess:ttp://www.example.com/
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/user-pass.pem b/security/manager/ssl/tests/unit/test_ocsp_url/user-pass.pem
new file mode 100644
index 000000000..aead46e41
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/user-pass.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC9jCCAeCgAwIBAgIUJYO4u8rbDNc65pazTgjE2dK2ZPgwCwYJKoZIhvcNAQEL
+MA4xDDAKBgNVBAMMA2ludDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAw
+MDAwWjAUMRIwEAYDVQQDDAl1c2VyLXBhc3MwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
+2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
+5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQ
+PdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGj
+DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
+iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjRjBEMEIGCCsGAQUFBwEB
+BDYwNDAyBggrBgEFBQcwAYYmaHR0cDovL3VzZXI6cGFzc0B3d3cuZXhhbXBsZS5j
+b206ODg4OC8wCwYJKoZIhvcNAQELA4IBAQA4qxh5V92DpwQWEvVz0NH9NPwQdIyv
+vgAtHigtX7BEtLp3HfLZX4xb8vOmg9X2Qd921zJIBgMIFtmn2oHjeKrceu2sL7pj
+tccHrCYabr5IlcRH8oub8RerRV6tW6X3Ulo6lcdY2LvZJkYuvLyKKuTB6qSfNyD2
+2xzxgSUMRtT6eBMZoCU+N6MQiwv0FzR67dZrXOkpYnKQ95+NVC2eiXnjPi4eLAv1
+7Qvafih2nXmZ0LL3oGcls8WITBNCdqYyXolAIJJQau73Yrhal0nQJGbSSedguhsG
+CEpuoTou4gFhR0DTiLuWMNfF4WNTIUvmnNYfqvSzUUyFyA9msyQ0YkAj
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_ocsp_url/user-pass.pem.certspec b/security/manager/ssl/tests/unit/test_ocsp_url/user-pass.pem.certspec
new file mode 100644
index 000000000..337e67e5f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_ocsp_url/user-pass.pem.certspec
@@ -0,0 +1,3 @@
+issuer:int
+subject:user-pass
+extension:authorityInformationAccess:http://user:pass@www.example.com:8888/
diff --git a/security/manager/ssl/tests/unit/test_onecrl/moz.build b/security/manager/ssl/tests/unit/test_onecrl/moz.build
new file mode 100644
index 000000000..560826d89
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_onecrl/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'same-issuer-ee.pem',
+# 'test-int-ee.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_onecrl/same-issuer-ee.pem b/security/manager/ssl/tests/unit/test_onecrl/same-issuer-ee.pem
new file mode 100644
index 000000000..c48cd895b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_onecrl/same-issuer-ee.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHTCCAgegAwIBAgIUI9484x9tR8knqKhzbTfed86/unswCwYJKoZIhvcNAQEL
+MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
+NTAwMDAwMFowIjEgMB4GA1UEAwwXQW5vdGhlciBUZXN0IEVuZC1lbnRpdHkwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
+2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
+JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
+jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
+BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
+He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
+AAGjWzBZMCMGA1UdEQQcMBqCCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbTAyBggr
+BgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9sb2NhbGhvc3Q6ODg4OC8w
+CwYJKoZIhvcNAQELA4IBAQB5uSG64u2JLPE1TsnPQfJT8bmzhov2VGvdyHHS1ANM
+zj900qpH4qNDGAaJwHSPhGdvPuJkd7Gzz/1i3kEKX/4FFkl0Md7O2xnqMn6shzKn
+kt4QAWFE+3Y5qloHLZxLAJ7xoCqxTsh+BXBgsnxR0YIJsjTXomB7kiyw5YWgRVlG
+iBlDCLuv/BEmOWXADF1Ly3qXPKWsr+tXfNl5IKjUUDdDcGHKFNYq6QyScgDokCE+
+PXEZwSiHdPpHhK1/eMIegl2rMycvw0vptPznr8MqF5COXGI9/W4ObHtXJnt6/I/C
+re6JOK6abYxpOJsLRXSovFc+RQQPrb6J7QA8Imt7FDkX
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_onecrl/same-issuer-ee.pem.certspec b/security/manager/ssl/tests/unit/test_onecrl/same-issuer-ee.pem.certspec
new file mode 100644
index 000000000..8b20f03f5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_onecrl/same-issuer-ee.pem.certspec
@@ -0,0 +1,4 @@
+issuer:Test CA
+subject:Another Test End-entity
+extension:subjectAlternativeName:localhost,*.example.com
+extension:authorityInformationAccess:http://localhost:8888/
diff --git a/security/manager/ssl/tests/unit/test_onecrl/sample_revocations.txt b/security/manager/ssl/tests/unit/test_onecrl/sample_revocations.txt
new file mode 100644
index 000000000..e8d9db746
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_onecrl/sample_revocations.txt
@@ -0,0 +1,39 @@
+# a sample revocations.txt for tests
+# Lines starting with '#' are ignored - as are empty lines like this:
+
+# otherwise:
+# non-empty lines are treated as base-64 encoded DER DN data (e.g. issuer or
+# subject)
+# ...unless the line starts with a ' ' (space) character, in which case it's
+# assumed to be base-64 encoded DER serial data, or
+# the line starts with a '\t' (tab) character, in which case it's assumed to
+# be a base-64 encoded SHA256 hash of a public key
+
+# First a serial with no issuer to ensure this doesn't cause parsing to fail
+# (there should be an issuer first, but we need to test this won't fail)
+ dGVzdA==
+# next, let's ensure data that isn't valid base64 doesn't cause breakage.
+ this serial isn't valid base64 (but then there's no issuer anyway)
+Neither is this issuer, though the serial is fine
+ dGVzdA==
+dGVzdA==
+ in this case, issuer is fine but not the serial
+# Next two entries; we can add valid base-64 encoded data for some basic tests:
+# issuer is "some imaginary issuer" base-64 encoded
+# and serial "serial." base-64 encoded
+c29tZSBpbWFnaW5hcnkgaXNzdWVy
+ c2VyaWFsLg==
+# issuer is "another imaginary issuer" base-64 encoded
+# serials are "serial." and "serial2." base-64 encoded
+YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy
+ c2VyaWFsLg==
+ c2VyaWFsMi4=
+# subject is "some imaginary subject", base-64 encoded
+# pubKeyHash is the sha256 hash of "some imaginary pubkey" base-64 encoded
+c29tZSBpbWFnaW5hcnkgc3ViamVjdA==
+ blBNgTxORaii2Sqe9bQcYsmfJ3kiXOLiKLzQNJ2wZYE=
+# and some more data to ensure that mixed items don't cause parsing failure
+a DN
+ a serial
+ a hash
+ another serial
diff --git a/security/manager/ssl/tests/unit/test_onecrl/test-int-ee.pem b/security/manager/ssl/tests/unit/test_onecrl/test-int-ee.pem
new file mode 100644
index 000000000..34d2cf669
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_onecrl/test-int-ee.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5jCCAdCgAwIBAgIUQyYXainIoMjK+7Pogg88tLd6ERgwCwYJKoZIhvcNAQEL
+MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAwMDAw
+WhgPMjAxODAyMDUwMDAwMDBaMCQxIjAgBgNVBAMMGUVFIGlzc3VlZCBieSBpbnRl
+cm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W
+1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtq
+ZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx
+0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthV
+t2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo
+4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx
+1QOs2hgKNe2NAgMBAAGjGDAWMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDALBgkqhkiG
+9w0BAQsDggEBAG5fRtX3qlA/A0hm3SwbARbljUehHxdHTeiz8qAbX5aEo7LRCxjr
+BccpjzVqwiZxfwqcAyHT/+CrFrgKvpN6rnuNnmNvScH3BeTmXEkImiHc0nZTYyOH
+Xep3I0ZEDa+2H5WDXfCbwF6JIQKJ2j3TR+c5/PzS3RLIkXG8wKcmv6Ldi5vwrIM7
+DDZ+k3a65JYSQwg9Q8gZoEBKmcalVD86+OQcs1HijU7ylS9PO8HB/sYakDPuKqRM
+xZgIBTDctRET07KtAIpBEnbfiWkI6xh4tTYj4IrRA5Yz8ajRImdn0IhJSld5Wgoy
+cQ1L2ia/hgcTIdQ+pIIV2lcepTaNMeIpCoI=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_onecrl/test-int-ee.pem.certspec b/security/manager/ssl/tests/unit/test_onecrl/test-int-ee.pem.certspec
new file mode 100644
index 000000000..24792d540
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_onecrl/test-int-ee.pem.certspec
@@ -0,0 +1,3 @@
+issuer:Test Intermediate
+subject:EE issued by intermediate
+extension:subjectAlternativeName:localhost
diff --git a/security/manager/ssl/tests/unit/test_password_prompt.js b/security/manager/ssl/tests/unit/test_password_prompt.js
new file mode 100644
index 000000000..cdf4227cb
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_password_prompt.js
@@ -0,0 +1,78 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that PSM can successfully ask for a password from the user and relay it
+// back to NSS. Does so by mocking out the actual dialog and "filling in" the
+// password. Also tests that providing an incorrect password will fail (well,
+// technically the user will just get prompted again, but if they then cancel
+// the dialog the overall operation will fail).
+
+var gMockPrompter = {
+ passwordToTry: null,
+ numPrompts: 0,
+
+ // This intentionally does not use arrow function syntax to avoid an issue
+ // where in the context of the arrow function, |this != gMockPrompter| due to
+ // how objects get wrapped when going across xpcom boundaries.
+ promptPassword: function(dialogTitle, text, password, checkMsg, checkValue) {
+ this.numPrompts++;
+ if (this.numPrompts > 1) { // don't keep retrying a bad password
+ return false;
+ }
+ equal(text,
+ "Please enter the master password for the Software Security Device.",
+ "password prompt text should be as expected");
+ equal(checkMsg, null, "checkMsg should be null");
+ ok(this.passwordToTry, "passwordToTry should be non-null");
+ password.value = this.passwordToTry;
+ return true;
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]),
+};
+
+// Mock nsIWindowWatcher. PSM calls getNewPrompter on this to get an nsIPrompt
+// to call promptPassword. We return the mock one, above.
+var gWindowWatcher = {
+ getNewPrompter: () => gMockPrompter,
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]),
+};
+
+function run_test() {
+ do_get_profile();
+
+ let windowWatcherCID =
+ MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1",
+ gWindowWatcher);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(windowWatcherCID);
+ });
+
+ // Set an initial password.
+ let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+ .getService(Ci.nsIPK11TokenDB);
+ let token = tokenDB.getInternalKeyToken();
+ token.initPassword("hunter2");
+ token.logoutSimple();
+
+ // Try with the correct password.
+ gMockPrompter.passwordToTry = "hunter2";
+ // Using nsISecretDecoderRing will cause the password prompt to come up if the
+ // token has a password and is logged out.
+ let sdr = Cc["@mozilla.org/security/sdr;1"]
+ .getService(Ci.nsISecretDecoderRing);
+ sdr.encryptString("poke");
+ equal(gMockPrompter.numPrompts, 1, "should have prompted for password once");
+
+ // Reset state.
+ gMockPrompter.numPrompts = 0;
+ token.logoutSimple();
+
+ // Try with an incorrect password.
+ gMockPrompter.passwordToTry = "*******";
+ throws(() => sdr.encryptString("poke2"), /NS_ERROR_FAILURE/,
+ "logging in with the wrong password should fail");
+ equal(gMockPrompter.numPrompts, 2, "should have prompted for password twice");
+}
diff --git a/security/manager/ssl/tests/unit/test_pinning.js b/security/manager/ssl/tests/unit/test_pinning.js
new file mode 100644
index 000000000..4d3c2fac8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning.js
@@ -0,0 +1,263 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// For all cases, the acceptable pinset includes only certificates pinned to
+// Test End Entity Cert (signed by issuer testCA). Other certificates
+// are issued by otherCA, which is never in the pinset but is a user-specified
+// trust anchor. This test covers multiple cases:
+//
+// Pinned domain include-subdomains.pinning.example.com includes subdomains
+// - PASS: include-subdomains.pinning.example.com serves a correct cert
+// - PASS: good.include-subdomains.pinning.example.com serves a correct cert
+// - FAIL (strict): bad.include-subdomains.pinning.example.com serves a cert
+// not in the pinset
+// - PASS (mitm): bad.include-subdomains.pinning.example.com serves a cert not
+// in the pinset, but issued by a user-specified trust domain
+//
+// Pinned domain exclude-subdomains.pinning.example.com excludes subdomains
+// - PASS: exclude-subdomains.pinning.example.com serves a correct cert
+// - FAIL: exclude-subdomains.pinning.example.com serves an incorrect cert
+// (TODO: test using verifyCertNow)
+// - PASS: sub.exclude-subdomains.pinning.example.com serves an incorrect cert
+
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function add_clear_override(host) {
+ add_test(function() {
+ let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
+ .getService(Ci.nsICertOverrideService);
+ certOverrideService.clearValidityOverride(host, 8443);
+ run_next_test();
+ });
+}
+
+function test_strict() {
+ // In strict mode, we always evaluate pinning data, regardless of whether the
+ // issuer is a built-in trust anchor. We only enforce pins that are not in
+ // test mode.
+ add_test(function() {
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
+ run_next_test();
+ });
+
+ // Normally this is overridable. But, since we have pinning information for
+ // this host, we don't allow overrides.
+ add_prevented_cert_override_test(
+ "unknownissuer.include-subdomains.pinning.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
+
+ // Issued by otherCA, which is not in the pinset for pinning.example.com.
+ add_connection_test("bad.include-subdomains.pinning.example.com",
+ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
+
+ // Check that using a FQDN doesn't bypass pinning.
+ add_connection_test("bad.include-subdomains.pinning.example.com.",
+ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
+ // For some reason this is also navigable (see bug 1118522).
+ add_connection_test("bad.include-subdomains.pinning.example.com..",
+ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
+
+ // These domains serve certs that match the pinset.
+ add_connection_test("include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("good.include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("exclude-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+
+ // This domain serves a cert that doesn't match the pinset, but subdomains
+ // are excluded.
+ add_connection_test("sub.exclude-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+
+ // This domain's pinset is exactly the same as
+ // include-subdomains.pinning.example.com, serves the same cert as
+ // bad.include-subdomains.pinning.example.com, but it should pass because
+ // it's in test_mode.
+ add_connection_test("test-mode.pinning.example.com",
+ PRErrorCodeSuccess);
+ // Similarly, this pin is in test-mode, so it should be overridable.
+ add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_clear_override("unknownissuer.test-mode.pinning.example.com");
+}
+
+function test_mitm() {
+ // In MITM mode, we allow pinning to pass if the chain resolves to any
+ // user-specified trust anchor, even if it is not in the pinset.
+ add_test(function() {
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1);
+ run_next_test();
+ });
+
+ add_connection_test("include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("good.include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+
+ // Normally this is overridable. But, since we have pinning information for
+ // this host, we don't allow overrides (since building a trusted chain fails,
+ // we have no reason to believe this was issued by a user-added trust
+ // anchor, so we can't allow overrides for it).
+ add_prevented_cert_override_test(
+ "unknownissuer.include-subdomains.pinning.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
+
+ // In this case, even though otherCA is not in the pinset, it is a
+ // user-specified trust anchor and the pinning check succeeds.
+ add_connection_test("bad.include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+
+ add_connection_test("exclude-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("sub.exclude-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
+ add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_clear_override("unknownissuer.test-mode.pinning.example.com");
+}
+
+function test_disabled() {
+ // Disable pinning.
+ add_test(function() {
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 0);
+ run_next_test();
+ });
+
+ add_connection_test("include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("good.include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("bad.include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("exclude-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("sub.exclude-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
+
+ add_cert_override_test("unknownissuer.include-subdomains.pinning.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
+ add_cert_override_test("unknownissuer.test-mode.pinning.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_clear_override("unknownissuer.test-mode.pinning.example.com");
+}
+
+function test_enforce_test_mode() {
+ // In enforce test mode, we always enforce all pins, even test pins.
+ add_test(function() {
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 3);
+ run_next_test();
+ });
+
+ // Normally this is overridable. But, since we have pinning information for
+ // this host, we don't allow overrides.
+ add_prevented_cert_override_test(
+ "unknownissuer.include-subdomains.pinning.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
+
+ // Issued by otherCA, which is not in the pinset for pinning.example.com.
+ add_connection_test("bad.include-subdomains.pinning.example.com",
+ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
+
+ // These domains serve certs that match the pinset.
+ add_connection_test("include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("good.include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+ add_connection_test("exclude-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+
+ // This domain serves a cert that doesn't match the pinset, but subdomains
+ // are excluded.
+ add_connection_test("sub.exclude-subdomains.pinning.example.com",
+ PRErrorCodeSuccess);
+
+ // This domain's pinset is exactly the same as
+ // include-subdomains.pinning.example.com, serves the same cert as
+ // bad.include-subdomains.pinning.example.com, is in test-mode, but we are
+ // enforcing test mode pins.
+ add_connection_test("test-mode.pinning.example.com",
+ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE);
+ // Normally this is overridable. But, since we have pinning information for
+ // this host (and since we're enforcing test mode), we don't allow overrides.
+ add_prevented_cert_override_test(
+ "unknownissuer.test-mode.pinning.example.com",
+ Ci.nsICertOverrideService.ERROR_UNTRUSTED,
+ SEC_ERROR_UNKNOWN_ISSUER);
+ add_clear_override("unknownissuer.test-mode.pinning.example.com");
+}
+
+function check_pinning_telemetry() {
+ let service = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
+ let prod_histogram = service.getHistogramById("CERT_PINNING_RESULTS")
+ .snapshot();
+ let test_histogram = service.getHistogramById("CERT_PINNING_TEST_RESULTS")
+ .snapshot();
+ // Because all of our test domains are pinned to user-specified trust
+ // anchors, effectively only strict mode and enforce test-mode get evaluated
+ equal(prod_histogram.counts[0], 4,
+ "Actual and expected prod (non-Mozilla) failure count should match");
+ equal(prod_histogram.counts[1], 4,
+ "Actual and expected prod (non-Mozilla) success count should match");
+ equal(test_histogram.counts[0], 2,
+ "Actual and expected test (non-Mozilla) failure count should match");
+ equal(test_histogram.counts[1], 0,
+ "Actual and expected test (non-Mozilla) success count should match");
+
+ let moz_prod_histogram = service.getHistogramById("CERT_PINNING_MOZ_RESULTS")
+ .snapshot();
+ let moz_test_histogram =
+ service.getHistogramById("CERT_PINNING_MOZ_TEST_RESULTS").snapshot();
+ equal(moz_prod_histogram.counts[0], 0,
+ "Actual and expected prod (Mozilla) failure count should match");
+ equal(moz_prod_histogram.counts[1], 0,
+ "Actual and expected prod (Mozilla) success count should match");
+ equal(moz_test_histogram.counts[0], 0,
+ "Actual and expected test (Mozilla) failure count should match");
+ equal(moz_test_histogram.counts[1], 0,
+ "Actual and expected test (Mozilla) success count should match");
+
+ let per_host_histogram =
+ service.getHistogramById("CERT_PINNING_MOZ_RESULTS_BY_HOST").snapshot();
+ equal(per_host_histogram.counts[0], 0,
+ "Actual and expected per host (Mozilla) failure count should match");
+ equal(per_host_histogram.counts[1], 2,
+ "Actual and expected per host (Mozilla) success count should match");
+ run_next_test();
+}
+
+function run_test() {
+ add_tls_server_setup("BadCertServer", "bad_certs");
+
+ // Add a user-specified trust anchor.
+ addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u");
+
+ test_strict();
+ test_mitm();
+ test_disabled();
+ test_enforce_test_mode();
+
+ add_test(function () {
+ check_pinning_telemetry();
+ });
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic.js b/security/manager/ssl/tests/unit/test_pinning_dynamic.js
new file mode 100644
index 000000000..2c314b53a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic.js
@@ -0,0 +1,246 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to create a site security service state file
+// and see that the site security service reads it properly.
+
+function writeLine(aLine, aOutputStream) {
+ aOutputStream.write(aLine, aLine.length);
+}
+
+var gSSService = null;
+var gSSSStateSeen = false;
+var gPreloadStateSeen = false;
+
+var profileDir = do_get_profile();
+var certdb;
+
+function certFromFile(cert_name) {
+ return constructCertFromFile("test_pinning_dynamic/" + cert_name + ".pem");
+}
+
+function loadCert(cert_name, trust_string) {
+ let cert_filename = "test_pinning_dynamic/" + cert_name + ".pem";
+ addCertFromFile(certdb, cert_filename, trust_string);
+ return constructCertFromFile(cert_filename);
+}
+
+function checkOK(cert, hostname) {
+ return checkCertErrorGeneric(certdb, cert, PRErrorCodeSuccess,
+ certificateUsageSSLServer, {}, hostname);
+}
+
+function checkFail(cert, hostname) {
+ return checkCertErrorGeneric(certdb, cert, MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE,
+ certificateUsageSSLServer, {}, hostname);
+}
+
+const NON_ISSUED_KEY_HASH = "KHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN=";
+const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
+
+function run_test() {
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
+
+ let stateFile = profileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ // Assuming we're working with a clean slate, the SSS_STATE file shouldn't
+ // exist until we create it.
+ ok(!stateFile.exists(),
+ "State file should not exist when working with a clean slate");
+ let outputStream = FileUtils.openFileOutputStream(stateFile);
+ let now = (new Date()).getTime();
+ writeLine(`a.pinning2.example.com:HPKP\t0\t0\t${now + 100000},1,0,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
+ writeLine(`b.pinning2.example.com:HPKP\t0\t0\t${now + 100000},1,1,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
+
+ outputStream.close();
+
+ let preloadFile = profileDir.clone();
+ preloadFile.append(PRELOAD_STATE_FILE_NAME);
+ ok(!preloadFile.exists(),
+ "Preload file should not exist when working with a clean slate");
+
+ outputStream = FileUtils.openFileOutputStream(preloadFile);
+ writeLine(`a.preload.example.com:HPKP\t0\t0\t${now + 100000},1,1,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
+ outputStream.close();
+
+ Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
+ do_test_pending();
+ gSSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ notEqual(gSSService, null,
+ "SiteSecurityService should have initialized successfully using" +
+ " the generated state file");
+}
+
+function checkDefaultSiteHPKPStatus() {
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "a.pinning2.example.com", 0),
+ "a.pinning2.example.com should have HPKP status");
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "x.a.pinning2.example.com", 0),
+ "x.a.pinning2.example.com should not have HPKP status");
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "b.pinning2.example.com", 0),
+ "b.pinning2.example.com should have HPKP status");
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "x.b.pinning2.example.com", 0),
+ "x.b.pinning2.example.com should have HPKP status");
+}
+
+function checkStateRead(aSubject, aTopic, aData) {
+ if (aData == SSS_STATE_FILE_NAME) {
+ gSSSStateSeen = true;
+ } else if (aData == PRELOAD_STATE_FILE_NAME) {
+ gPreloadStateSeen = true;
+ } else {
+ throw new Error("Observed data should either be the Site Security " +
+ "Service state file name or the preload file name");
+ }
+
+ if (!gSSSStateSeen || !gPreloadStateSeen) {
+ return;
+ }
+
+ notEqual(gSSService, null, "SiteSecurityService should be initialized");
+
+ // Initializing the certificate DB will cause NSS-initialization, which in
+ // turn initializes the site security service. Since we're in part testing
+ // that the site security service correctly reads its state file, we have to
+ // make sure it doesn't start up before we've populated the file
+ certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+ loadCert("pinningroot", "CTu,CTu,CTu");
+ loadCert("badca", "CTu,CTu,CTu");
+
+ // the written entry is for a.pinning2.example.com without subdomains
+ // and b.pinning2.example.com with subdomains
+ checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
+ checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
+
+ checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
+ checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
+ checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
+ checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
+
+ checkDefaultSiteHPKPStatus();
+
+
+ // add includeSubdomains to a.pinning2.example.com
+ gSSService.setKeyPins("a.pinning2.example.com", true,
+ new Date().getTime() + 1000000, 2,
+ [NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH]);
+ checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
+ checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
+ checkFail(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
+ checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
+ checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
+ checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
+ checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
+
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "a.pinning2.example.com", 0),
+ "a.pinning2.example.com should still have HPKP status after adding" +
+ " includeSubdomains to a.pinning2.example.com");
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "x.a.pinning2.example.com", 0),
+ "x.a.pinning2.example.com should now have HPKP status after adding" +
+ " includeSubdomains to a.pinning2.example.com");
+
+ // Now setpins without subdomains
+ gSSService.setKeyPins("a.pinning2.example.com", false,
+ new Date().getTime() + 1000000, 2,
+ [NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH]);
+ checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
+ checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
+
+ checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
+ checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
+ checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
+ checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
+
+ checkDefaultSiteHPKPStatus();
+
+ // failure to insert new pin entry leaves previous pin behavior
+ throws(() => {
+ gSSService.setKeyPins("a.pinning2.example.com", true,
+ new Date().getTime() + 1000000, 1, ["not a hash"]);
+ }, /NS_ERROR_ILLEGAL_VALUE/, "Attempting to set an invalid pin should fail");
+ checkFail(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
+ checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
+
+ checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
+ checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
+ checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
+ checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
+
+ checkDefaultSiteHPKPStatus();
+
+ // Incorrect size results in failure
+ throws(() => {
+ gSSService.setKeyPins("a.pinning2.example.com", true,
+ new Date().getTime() + 1000000, 2, ["not a hash"]);
+ }, /NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY/,
+ "Attempting to set a pin with an incorrect size should fail");
+
+ // Ensure built-in pins work as expected
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "nonexistent.example.com", 0),
+ "Not built-in nonexistent.example.com should not have HPKP status");
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "include-subdomains.pinning.example.com", 0),
+ "Built-in include-subdomains.pinning.example.com should have HPKP status");
+
+ gSSService.setKeyPins("a.pinning2.example.com", false, new Date().getTime(),
+ 1, [NON_ISSUED_KEY_HASH]);
+
+ // Check that a preload pin loaded from file works as expected
+ checkFail(certFromFile("a.preload.example.com-badca"), "a.preload.example.com");
+ checkOK(certFromFile("a.preload.example.com-pinningroot"), "a.preload.example.com");
+
+ // Check a dynamic addition works as expected
+ // first, it should succeed with the badCA - because there's no pin
+ checkOK(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
+ // then we add a pin, and we should get a failure (ensuring the expiry is
+ // after the test timeout)
+ gSSService.setKeyPins("b.preload.example.com", false,
+ new Date().getTime() + 1000000, 2,
+ [NON_ISSUED_KEY_HASH, PINNING_ROOT_KEY_HASH], true);
+ checkFail(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
+
+ do_timeout(1250, checkExpiredState);
+}
+
+function checkExpiredState() {
+ checkOK(certFromFile('a.pinning2.example.com-badca'), "a.pinning2.example.com");
+ checkOK(certFromFile('a.pinning2.example.com-pinningroot'), "a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-badca'), "x.a.pinning2.example.com");
+ checkOK(certFromFile('x.a.pinning2.example.com-pinningroot'), "x.a.pinning2.example.com");
+
+ checkFail(certFromFile('b.pinning2.example.com-badca'), "b.pinning2.example.com");
+ checkOK(certFromFile('b.pinning2.example.com-pinningroot'), "b.pinning2.example.com");
+ checkFail(certFromFile('x.b.pinning2.example.com-badca'), "x.b.pinning2.example.com");
+ checkOK(certFromFile('x.b.pinning2.example.com-pinningroot'), "x.b.pinning2.example.com");
+ checkPreloadClear();
+}
+
+function checkPreloadClear() {
+ // Check that the preloaded pins still work after private data is cleared
+ gSSService.clearAll();
+ checkFail(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
+
+ // Check that the preloaded pins are cleared when we clear preloads
+ gSSService.clearPreloads();
+ checkOK(certFromFile('b.preload.example.com-badca'), "b.preload.example.com");
+
+ do_test_finished();
+}
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-badca.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-badca.pem
new file mode 100644
index 000000000..102a3bbda
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-badca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3TCCAcegAwIBAgIUXdB7LgBGZoRV1UmEFcsOhMigpB0wCwYJKoZIhvcNAQEL
+MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
+MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
+plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
+YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
+5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
+JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMlMCMwIQYD
+VR0RBBowGIIWYS5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEB
+AAKhpX2t/Bz9//u1DYyLZ6dLSJt121Vb58s8gQvI/7n6MdUP1IniQLbtPW+7wnV0
+6LYagJQ11ZUJMxYUs6lB91yhwAO9NoN4QJWWB0i23DoZ6cg4dHmYKmQQ/HRndwm+
+EATkJSnBAk8O2xmIm8CXbJ0W0lvaXEjzRfeoiEjQ0/THeo4hXvGOMPm31d+r4ji5
+/u2+9jrpTII0kjCwFjqC97lPID14s9QRMqMB1CCV6fgT19EGYi9I7H6mnyukkmfX
+9wOhLHSk6A2l5+5eJrZYXLOhcS31VBd54sb1Vvg+Bp05HMYjo051JcRlvxoIUsHT
+JQDn8QrzwZBDBh4Pie3AwOM=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-badca.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-badca.pem.certspec
new file mode 100644
index 000000000..f365b8a18
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-badca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:badca
+subject:test end-entity
+issuerKey:alternate
+subjectKey:alternate
+extension:subjectAlternativeName:a.pinning2.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem
new file mode 100644
index 000000000..2439b5775
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4zCCAc2gAwIBAgIUPQgjdPeWdWy/0oKRi+5Lr7JJorMwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
+zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
+zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
+KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
+mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
+kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMl
+MCMwIQYDVR0RBBowGIIWYS5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0B
+AQsDggEBAFUlxnwpxOFbSxtsBthWu6xmDxeFAzP+u5YOfuKeiIGnAx70k8ODQufJ
+Vm1rXvKtN5r8jR6AZh/hdA+tGhnu4+pGi9/aqWnaF1FEs2mW0saUV8atQZwNGRBO
+E9FXdAHA8WmGIfRf8TOuWpmEWejjJt5Zsfs+V3ARIxjCrVE7ixyfJ/hYpmthLtYJ
+5vgp0iiPjzorKeFnqooLVAfzeayRX0bE5H79NISIWq4CN/9J50ZFkRORURlANU95
+2Dcuw416b3BGrWVmWlKWOpA6NZ+Rj+AI+z9UTDpqCczTfMXMabX4EveW1GKMMYiA
+eLD8SY4VQ4403eaCp6rxYFrCNOeDczs=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem.certspec
new file mode 100644
index 000000000..aef72ce39
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.pinning2.example.com-pinningroot.pem.certspec
@@ -0,0 +1,4 @@
+issuer:pinningroot
+subject:test end-entity
+subjectKey:alternate
+extension:subjectAlternativeName:a.pinning2.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-badca.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-badca.pem
new file mode 100644
index 000000000..2a157d8e6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-badca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAcagAwIBAgIUKUG7kBZ72CvuLQ0uPfjKHLkKDQAwCwYJKoZIhvcNAQEL
+MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
+MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
+plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
+YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
+5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
+JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMkMCIwIAYD
+VR0RBBkwF4IVYS5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOCAQEA
+tx5YO8uvYac92scnMEswv4ZIslou8UYV/2mtxA+MaXf/g+MizOKeZgTI1+b9hR48
+IDOgvrqPCbn1hKY6gb2gtRI1mC5dg9T8EYEXcC1TM+ncY/l4SZUjfMhzY2iOf62x
+jhDqMMt4V5uaHUxVmJQI82X5qpxH3yJ3WOC87iGZNfMB8MSbLM3lxor9OHeTlTHQ
+vPb/r7cLW+ikxirDGyBBvThkvDA/8qyN5Qp6Ae1BiPeEMoScNf3fChvNV6Jyb8g8
+e9q0LnTlTuVgaDWtg7PVOxeiI+wf3Jhv9uqXQLX8JHZDKebLbQEkNcbR4DK/8wsP
+uFhj0j8DY6+/YZbcF7Jgfw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-badca.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-badca.pem.certspec
new file mode 100644
index 000000000..c1cb36576
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-badca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:badca
+subject:test end-entity
+issuerKey:alternate
+subjectKey:alternate
+extension:subjectAlternativeName:a.preload.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-pinningroot.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-pinningroot.pem
new file mode 100644
index 000000000..5fa43f052
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-pinningroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4jCCAcygAwIBAgIURV3mf9Dz42lALe31OAm2SYbpFaEwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
+zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
+zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
+KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
+mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
+kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMk
+MCIwIAYDVR0RBBkwF4IVYS5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEB
+CwOCAQEATOA0bbfg81JieQkTzr4oxBqPuFamtLSAsLpbKakikYQo2znMGNnHV7Xe
+uxMGMhCIPRsiJ6jj6ZTQJNqQRKzXWEiBgREsarmJxA53ITIcO2cK2rqyetNAAwzZ
+oViENmK3tLA5KT2VC9IGgMXdSE7IfXn+5yCdpKZ2ohwtkYHNkCbQIU+4KaCPa/dB
+yAelZZPE0mVHJLkd5HoOsFmjFOBQuOkn9/AAOmkgBZIk1Dp833ywn/mnwLZdVsdV
++TjqWKenDJXxhO2+aCCtZbUVxKMn0TACpAA+rhjS5vigCyIZh7V4rxki9UXaOfVq
+EVy4rFlRIYYtXV40HavDZoPgxuCHDw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-pinningroot.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-pinningroot.pem.certspec
new file mode 100644
index 000000000..5c1865314
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/a.preload.example.com-pinningroot.pem.certspec
@@ -0,0 +1,4 @@
+issuer:pinningroot
+subject:test end-entity
+subjectKey:alternate
+extension:subjectAlternativeName:a.preload.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-badca.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-badca.pem
new file mode 100644
index 000000000..cffb37c1f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-badca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3TCCAcegAwIBAgIUV89JsAhywp3graSGqjeSpMzd1B0wCwYJKoZIhvcNAQEL
+MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
+MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
+plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
+YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
+5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
+JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMlMCMwIQYD
+VR0RBBowGIIWYi5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0BAQsDggEB
+ABevzhH9/hjTBgTtUk4ytZX0A7Tu0DR5F9ooFnlUwzupHFihO+9NzEoCSIvCy3L9
++i3LbkaiUWEHQItLjIg+aice13ZkuMp+DeZ+D/YR9ulxyY1QBYeZLQj/gSdkj/fK
+uDm0Izgt8OBsgP+KFX2c2cGZyOcXmFFAwSfkLz7p2qzrmuM7r5ploNpxeHBUIxUW
+jJzSFeQMfy5wflcKDBY+PDejzN9Ik4weRyERsckVgmZSJXuodb8xgYkNPvl/GOVJ
+o+eDw+E3uOsdBIDrsyb+bcQTG7nBkQoSqG8M0610h0OqFhksfv/0HcB/wfW8VdU+
++C4+tR2KfvqTCm3T6gzRWX8=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-badca.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-badca.pem.certspec
new file mode 100644
index 000000000..5aa8aaa5e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-badca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:badca
+subject:test end-entity
+issuerKey:alternate
+subjectKey:alternate
+extension:subjectAlternativeName:b.pinning2.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-pinningroot.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-pinningroot.pem
new file mode 100644
index 000000000..791f64b4c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-pinningroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4zCCAc2gAwIBAgIUVQNTrx+mRE96ggRLuZeFm+9uBdcwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
+zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
+zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
+KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
+mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
+kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMl
+MCMwIQYDVR0RBBowGIIWYi5waW5uaW5nMi5leGFtcGxlLmNvbTALBgkqhkiG9w0B
+AQsDggEBAHYCfQaolF6z4IicBDTEQQVfYi4A3BcCNLTdInQlal/DHNytNRufM5TB
+ccNpau5U9e10NBYWbMqRUBb/7wtYE4O7jhEWxjaHBOz5KTYLv8hjEc2wcHXfhlYM
+QKmxOnA7SguSNYBdfXywav//ssLmDnB06nc2vv5NaKvIWbUv3HvfM8oRAr+NICUs
+UMcIb+hjY+u/qrnOeFJxXzeqPYKMa7H+33baRgy7xnL95PxAwkz0XL8vcMFupTX5
+dL5HsSKku23C0BoE6pK39TVh758fQjCAnD+QRTH/o+dfE2sIFpRiyszdXGmh2IRR
+gMSy+gJbH+zh0D9ncL0Kev0PyEuBYR4=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-pinningroot.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-pinningroot.pem.certspec
new file mode 100644
index 000000000..17f22dab5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.pinning2.example.com-pinningroot.pem.certspec
@@ -0,0 +1,4 @@
+issuer:pinningroot
+subject:test end-entity
+subjectKey:alternate
+extension:subjectAlternativeName:b.pinning2.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-badca.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-badca.pem
new file mode 100644
index 000000000..4ef23a2c2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-badca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAcagAwIBAgIUf2T4BVvxeCgWVp/FL3tCFNjuZYQwCwYJKoZIhvcNAQEL
+MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
+MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
+plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
+YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
+5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
+JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMkMCIwIAYD
+VR0RBBkwF4IVYi5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOCAQEA
+okmxK2NDRYWSAn6b1YZpLiZnoaNrM0HXHY6fkARY/9EiAApvNPxT663EKtTZn27a
+JtwXP2zzlYQDRc9cxa1zBX9Tp+0sn5aqokqzoVWx4VIe/emzi9FDf3lgaYewHLez
+RINv3kUZmqlw6tmMQxjd51UGyvNsi52+gcet1cPr5kBzGQv/q7iNs/lcetL3+KQF
+klJ3PfI4VjFwRRYNhScxiRczklPVDySvxSNw+csUxNRunFLXIi3+WqQzYhw7R8ga
+ASwozTfvVAUySOmDipCZZXAHFtlpBr6vAllfD9v8hAsrE7Bkivafr+i5HMD3DtJE
+4ZedqFCkTkqKvd0fMIbOIA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-badca.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-badca.pem.certspec
new file mode 100644
index 000000000..9901ead60
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-badca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:badca
+subject:test end-entity
+issuerKey:alternate
+subjectKey:alternate
+extension:subjectAlternativeName:b.preload.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-pinningroot.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-pinningroot.pem
new file mode 100644
index 000000000..c6ea38a12
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-pinningroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC4jCCAcygAwIBAgIUI5rdRX/x0w0bDx6hQhc8ZhGLfqQwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
+zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
+zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
+KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
+mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
+kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMk
+MCIwIAYDVR0RBBkwF4IVYi5wcmVsb2FkLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEB
+CwOCAQEAg2VdHBLmFLJ03N9VT4uUrnpjuYY9bsvPJF2JCk9817nxBbeMf+Qn0C/o
+OeoQnZRqsaFbKZ80JXmh/j4RO6T/aaQUMpk+NXrdSPddy2B3eUByF/NJqipV3M2a
+CRNWUUVF+msjRWwbzJafju2nEZcD4d4cUkHHYAaRRxAHH3ylEvWmdv/brgfAPCPH
+WDVaCMc3OXgHkyrLAfkMKSYTNPJ7DJn/BXET5tCzqYGRUgRnME4ON2Mmp19lsdig
+dIFbm76wg6l5M+s9pqiYzODUxJXUOd6BkAR5pqB9WyIRVfBr5LGT72nv00LHVcSm
+hnsti9nAtFdJx4E1lJilrnQwu0q4Iw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-pinningroot.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-pinningroot.pem.certspec
new file mode 100644
index 000000000..6f5807700
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/b.preload.example.com-pinningroot.pem.certspec
@@ -0,0 +1,4 @@
+issuer:pinningroot
+subject:test end-entity
+subjectKey:alternate
+extension:subjectAlternativeName:b.preload.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/badca.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/badca.pem
new file mode 100644
index 000000000..9443a4c91
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/badca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyzCCAbWgAwIBAgIUXQevdaeXMieCrG6ZqhI2yfACBq4wCwYJKoZIhvcNAQEL
+MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
+MDAwMDBaMBAxDjAMBgNVBAMMBWJhZGNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAwXXGUmYJn3cIKmeR8bh2w39c5TiwbErNIrHL1G+mWtoq3UHIwkmK
+xKOzwfYUh/QbaYlBvYClHDwSAkTFhKTESDMF5ROMAQbPCL6ahidguuai6PNvI8XZ
+gxO53683g0XazlHU1tzSpss8xwbrzTBw7JjM5AqlkdcpWn9xxb5maR0rLf7ISURZ
+C8Wj6kn9k7HXU0BfF3N2mZWGZiVHl+1CaQiICBFCIGmYikP+5Izmh4HdIramnNKD
+dRMfkysSjOKG+n0lHAYq0n7wFvGHzdVOgys1uJMPdLqQqovHYWckKrH9bWIUDRjE
+wLjGj8N0hFcyStfehuZVLx0eGR1xIWjTuwIDAQABox0wGzAMBgNVHRMEBTADAQH/
+MAsGA1UdDwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHitWfZzPxR/UWEKQgz9zzm2
+NXszG7nV82w8qfC9pq8mU3f7eqbHJ2HNFkZzttJsH9DNl30OK2Y5IVLUiZHckz2e
+OFUyxK0tBCCBYd79FiK4BgP/Ys/7LK+4UaDhbRQP//MGuofwjsrNxgPgtkNaeKtF
+EXKCuDrHoa4ua7afrkUWKzPZ6JbDOEjJIyuJ3ISI0Q20Oc3ERxGwG1SQ1EldgWBr
+0dJJWBHZtNpIVvSm1dRfjMYtSrBoUXwbn6kDrdk4T98OHnFP0V0KW4j4umLHK7Gi
+OSAwvWtir3fSJaLJClTCFe1XoNvJnQ53PJs0JR26mAixV2VuylStO2KlbYy7fOc=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/badca.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/badca.pem.certspec
new file mode 100644
index 000000000..311bbb3f8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/badca.pem.certspec
@@ -0,0 +1,6 @@
+issuer:badca
+subject:badca
+issuerKey:alternate
+subjectKey:alternate
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/moz.build b/security/manager/ssl/tests/unit/test_pinning_dynamic/moz.build
new file mode 100644
index 000000000..eb8b582f5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/moz.build
@@ -0,0 +1,26 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'badca.pem',
+# 'a.pinning2.example.com-badca.pem',
+# 'a.pinning2.example.com-pinningroot.pem',
+# 'a.preload.example.com-badca.pem',
+# 'a.preload.example.com-pinningroot.pem',
+# 'b.pinning2.example.com-badca.pem',
+# 'b.pinning2.example.com-pinningroot.pem',
+# 'b.preload.example.com-badca.pem',
+# 'b.preload.example.com-pinningroot.pem',
+# 'x.a.pinning2.example.com-badca.pem',
+# 'x.a.pinning2.example.com-pinningroot.pem',
+# 'x.b.pinning2.example.com-badca.pem',
+# 'x.b.pinning2.example.com-pinningroot.pem',
+# 'pinningroot.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.pem
new file mode 100644
index 000000000..9a041991a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1zCCAcGgAwIBAgIUMwSUmBShbg5sMNZSTiPd5Tb1udkwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
+aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
+adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
+pH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62W
+YVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauR
+CE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAM
+BgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjALBgkqhkiG9w0BAQsDggEBADNuQnKg
+y8zWnKlfBq/50UOtdSlvevg6u6tsUTvay2kVgB8BRTvm76aw4yOLgk84eHHkrX5c
+TqdutWh2JZarUWbO7JnPTdDE2CAkDh1smSe9L/XJENbgVXleg/VYLgnfnuSQCCnK
+WjjExcorX6IKDks1ZoBJ1HIvBzMRMWzIQgBL9B2Y1V05lgfn0bwZD+TjUJBmN1w0
+NTaPgrxE7FWZ2CTcowrYRKEEDAUX4cTFoce5YMwALCgW59KfVQfQdHaiCCcdNbfi
+qSQGZu+59JrrasmgK9VTahukYWcaQCz8HBCasdknGodLAzThuWMkjXU3D2IZYl15
+GfE5yrRFop/89xo=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.pem.certspec
new file mode 100644
index 000000000..86500e16b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/pinningroot.pem.certspec
@@ -0,0 +1,4 @@
+issuer:pinningroot
+subject:pinningroot
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-badca.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-badca.pem
new file mode 100644
index 000000000..e4b6e72c0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-badca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3zCCAcmgAwIBAgIUe11LKIzCrdnRTgrLsfuGMoOpL1QwCwYJKoZIhvcNAQEL
+MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
+MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
+plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
+YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
+5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
+JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMnMCUwIwYD
+VR0RBBwwGoIYeC5hLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOC
+AQEAgdFC/SwBLRp6A+n3znR+sEuU8UvmbgbXp7pIFVh6cbC6lNF0nXk9ywPeIWyh
+B7TCn3YHj4uc/PbvzRj9Py0gQLXcimKpmLoxclV5g1uTAydgXPiPulv/kaL9NOME
+lm88pyQeDwfEkUz7VijabIzFRTEVRmOudb8mX4SuzjhxsdzSMjffpae335beJ4Im
+lxgJgMsuJdEoK0WyG5nlBhVdzrT/kwdiwULeVNV//UHid1YZy56G5Lo22Hgd4wT3
+1W3LXQelBdHhee7Hf7mg4rjCUPulFAr8qBLdywf1Hnu1o7rXUcn46PLwKLOWJPOM
+SKpiqRKqvzlrzLaHPejfT0IMrw==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-badca.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-badca.pem.certspec
new file mode 100644
index 000000000..ad8636d43
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-badca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:badca
+subject:test end-entity
+issuerKey:alternate
+subjectKey:alternate
+extension:subjectAlternativeName:x.a.pinning2.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-pinningroot.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-pinningroot.pem
new file mode 100644
index 000000000..ed58de323
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-pinningroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5TCCAc+gAwIBAgIUefEeE+Sj5fBSec+97B6UmZFQEncwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
+zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
+zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
+KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
+mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
+kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMn
+MCUwIwYDVR0RBBwwGoIYeC5hLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3
+DQEBCwOCAQEAT2fxisiLJvVdFTba07a2Pc6UHBE+O0tOaLfMmHx/ET2FZdd9sLTL
+X2f+hQCmXEBQ7Au2eYTew8hTyXYGYFauMJNk+XHHUIaSOhmnYTccye4d6j5bXRCp
+7zA1qPlReCDLjp7o/34whkvngvdgdLYf60EkBO/NJfj+zsR1JTVfyVzIKXl6veLz
+0xKicBAq9vS0Yqq10japVYKKqAw6gDpbNkSAd3xsl4+EbMRq+BnMB4W2anw1gM/e
+hV11JQVA/MREtmUiTkvJFF6chHVCn5aL7JzVM2miZjZC8Ix59LUBoyO3SrxgrzZw
+xeYuwoDhzTCrcFxn8gdKNajbGHuW5ekQpg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-pinningroot.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-pinningroot.pem.certspec
new file mode 100644
index 000000000..260f2184b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.a.pinning2.example.com-pinningroot.pem.certspec
@@ -0,0 +1,4 @@
+issuer:pinningroot
+subject:test end-entity
+subjectKey:alternate
+extension:subjectAlternativeName:x.a.pinning2.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-badca.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-badca.pem
new file mode 100644
index 000000000..dc24247e8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-badca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3zCCAcmgAwIBAgIUYcTc5Pz7KlQldGOO+KzbuBdf8TswCwYJKoZIhvcNAQEL
+MBAxDjAMBgNVBAMMBWJhZGNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUw
+MDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxKzSKxy9Rv
+plraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEGzwi+moYn
+YLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHXKVp/ccW+
+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBpmIpD/uSM
+5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6kKqLx2Fn
+JCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMnMCUwIwYD
+VR0RBBwwGoIYeC5iLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3DQEBCwOC
+AQEAd6HusXqftFBpSUzivIY6icTZ95+wY+xIOsf1QOgyzZ/CDx4Tly+rgue2xSNT
+59FmnFvh8jW202K8TykamsAX20A8ArzubNoc/+soA752YEvrMmOgWjmH2arqTfqg
+zcfNdgUDESwnOoy123F+PkT3rRDXwINzCwftxhKbvmqhO6YENteqyWWmSZoMClsJ
+xtm+bmPN+m26k6zMMYWzIu2HIXI3CgqOmJltfyqea02Y58S1+XlajrcewPpC17xD
+r5a1sizecCFrmV0ssbK8wvEYo9Xs+PNj8Vhi1DUwGjtnjrYn/WQ6v/luMEEO7EMD
+b3BbEziS3Pqej2JyprUKqOjv1g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-badca.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-badca.pem.certspec
new file mode 100644
index 000000000..592bdcc58
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-badca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:badca
+subject:test end-entity
+issuerKey:alternate
+subjectKey:alternate
+extension:subjectAlternativeName:x.b.pinning2.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-pinningroot.pem b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-pinningroot.pem
new file mode 100644
index 000000000..642135994
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-pinningroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC5TCCAc+gAwIBAgIUNXGolw8M2HU/gP4dOSMD2bdTQ+MwCwYJKoZIhvcNAQEL
+MBYxFDASBgNVBAMMC3Bpbm5pbmdyb290MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAx
+ODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD3Rlc3QgZW5kLWVudGl0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93CCpnkfG4dsN/XOU4sGxK
+zSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8EgJExYSkxEgzBeUTjAEG
+zwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbLPMcG680wcOyYzOQKpZHX
+KVp/ccW+ZmkdKy3+yElEWQvFo+pJ/ZOx11NAXxdzdpmVhmYlR5ftQmkIiAgRQiBp
+mIpD/uSM5oeB3SK2ppzSg3UTH5MrEozihvp9JRwGKtJ+8Bbxh83VToMrNbiTD3S6
+kKqLx2FnJCqx/W1iFA0YxMC4xo/DdIRXMkrX3obmVS8dHhkdcSFo07sCAwEAAaMn
+MCUwIwYDVR0RBBwwGoIYeC5iLnBpbm5pbmcyLmV4YW1wbGUuY29tMAsGCSqGSIb3
+DQEBCwOCAQEAevN1gW64H2kCjW5W4wbQFkJIITjcdEUsw+8GPzDuBDJCvgGirhOi
+ArBie8Bz+JlqzgNCXSe6pFVLoNfLosG5xksLwHljEit/7gFQ5twFazdg7dwPXs9Z
+MIV2iv3vHmKYTFTcjfw07UWy0rHHt6EH+zXqpZFtFkJHqSgngKxAHgQlvSKeyynM
+albu5YAX/hzJ7TyAVGxVN8uxnvYqPbLCy3wKf9ILFiDer6B9pE4Ii+dUyUbqVQFZ
+tY2ac1474nkcfj3uj5qbV0TTpd9EL9HMvixTnoUrT3bqkRX7orvL4gXpnJJyRjvC
+/LvTh/Vt1mYKkNLc/ruOj7WfUUC0SJIDzQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-pinningroot.pem.certspec b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-pinningroot.pem.certspec
new file mode 100644
index 000000000..7e6d33d50
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_dynamic/x.b.pinning2.example.com-pinningroot.pem.certspec
@@ -0,0 +1,4 @@
+issuer:pinningroot
+subject:test end-entity
+subjectKey:alternate
+extension:subjectAlternativeName:x.b.pinning2.example.com
diff --git a/security/manager/ssl/tests/unit/test_pinning_header_parsing.js b/security/manager/ssl/tests/unit/test_pinning_header_parsing.js
new file mode 100644
index 000000000..fb4b32353
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pinning_header_parsing.js
@@ -0,0 +1,141 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to check that parsing of HPKP headers
+// is correct.
+
+var profileDir = do_get_profile();
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+var gSSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+
+function certFromFile(cert_name) {
+ return constructCertFromFile("test_pinning_dynamic/" + cert_name + ".pem");
+}
+
+function loadCert(cert_name, trust_string) {
+ let cert_filename = "test_pinning_dynamic/" + cert_name + ".pem";
+ addCertFromFile(certdb, cert_filename, trust_string);
+ return constructCertFromFile(cert_filename);
+}
+
+function checkFailParseInvalidPin(pinValue) {
+ let sslStatus = new FakeSSLStatus(
+ certFromFile('a.pinning2.example.com-pinningroot'));
+ let uri = Services.io.newURI("https://a.pinning2.example.com", null, null);
+ throws(() => {
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
+ pinValue, sslStatus, 0);
+ }, /NS_ERROR_FAILURE/, `Invalid pin "${pinValue}" should be rejected`);
+}
+
+function checkPassValidPin(pinValue, settingPin, expectedMaxAge) {
+ let sslStatus = new FakeSSLStatus(
+ certFromFile('a.pinning2.example.com-pinningroot'));
+ let uri = Services.io.newURI("https://a.pinning2.example.com", null, null);
+ let maxAge = {};
+
+ // setup preconditions for the test, if setting ensure there is no previous
+ // state, if removing ensure there is a valid pin in place.
+ if (settingPin) {
+ gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
+ } else {
+ // add a known valid pin!
+ let validPinValue = "max-age=5000;" + VALID_PIN1 + BACKUP_PIN1;
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
+ validPinValue, sslStatus, 0);
+ }
+ try {
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HPKP, uri,
+ pinValue, sslStatus, 0, maxAge);
+ ok(true, "Valid pin should be accepted");
+ } catch (e) {
+ ok(false, "Valid pin should have been accepted");
+ }
+
+ // check that maxAge was processed correctly
+ if (settingPin && expectedMaxAge) {
+ ok(maxAge.value == expectedMaxAge, `max-age value should be ${expectedMaxAge}`);
+ }
+
+ // after processing ensure that the postconditions are true, if setting
+ // the host must be pinned, if removing the host must not be pinned
+ let hostIsPinned = gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
+ "a.pinning2.example.com", 0);
+ if (settingPin) {
+ ok(hostIsPinned, "Host should be considered pinned");
+ } else {
+ ok(!hostIsPinned, "Host should not be considered pinned");
+ }
+}
+
+function checkPassSettingPin(pinValue, expectedMaxAge) {
+ return checkPassValidPin(pinValue, true, expectedMaxAge);
+}
+
+function checkPassRemovingPin(pinValue) {
+ return checkPassValidPin(pinValue, false);
+}
+
+const MAX_MAX_AGE_SECONDS = 100000;
+const GOOD_MAX_AGE_SECONDS = 69403;
+const LONG_MAX_AGE_SECONDS = 2 * MAX_MAX_AGE_SECONDS;
+const NON_ISSUED_KEY_HASH1 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+const NON_ISSUED_KEY_HASH2 = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ=";
+const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
+const MAX_AGE_ZERO = "max-age=0;";
+const VALID_PIN1 = `pin-sha256="${PINNING_ROOT_KEY_HASH}";`;
+const BACKUP_PIN1 = `pin-sha256="${NON_ISSUED_KEY_HASH1}";`;
+const BACKUP_PIN2 = `pin-sha256="${NON_ISSUED_KEY_HASH2}";`;
+const BROKEN_PIN1 = "pin-sha256=\"jdjsjsjs\";";
+const GOOD_MAX_AGE = `max-age=${GOOD_MAX_AGE_SECONDS};`;
+const LONG_MAX_AGE = `max-age=${LONG_MAX_AGE_SECONDS};`;
+const INCLUDE_SUBDOMAINS = "includeSubdomains;";
+const REPORT_URI = "report-uri=\"https://www.example.com/report/\";";
+const UNRECOGNIZED_DIRECTIVE = "unreconized-dir=12343;";
+
+function run_test() {
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
+ Services.prefs.setIntPref("security.cert_pinning.max_max_age_seconds", MAX_MAX_AGE_SECONDS);
+ Services.prefs.setBoolPref("security.cert_pinning.process_headers_from_non_builtin_roots", true);
+
+ loadCert("pinningroot", "CTu,CTu,CTu");
+ loadCert("badca", "CTu,CTu,CTu");
+
+ checkFailParseInvalidPin("max-age=INVALID");
+ // check that incomplete headers are failure
+ checkFailParseInvalidPin(GOOD_MAX_AGE);
+ checkFailParseInvalidPin(VALID_PIN1);
+ checkFailParseInvalidPin(REPORT_URI);
+ checkFailParseInvalidPin(UNRECOGNIZED_DIRECTIVE);
+ checkFailParseInvalidPin(VALID_PIN1 + BACKUP_PIN1);
+ checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1);
+ checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BROKEN_PIN1);
+ // next ensure a backup pin is present
+ checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + VALID_PIN1);
+ // next section ensure duplicate directives result in failure
+ checkFailParseInvalidPin(GOOD_MAX_AGE + GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
+ checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + INCLUDE_SUBDOMAINS + INCLUDE_SUBDOMAINS);
+ checkFailParseInvalidPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + REPORT_URI + REPORT_URI);
+ checkFailParseInvalidPin("thisisinvalidtest");
+ checkFailParseInvalidPin("invalid" + GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
+
+ checkPassRemovingPin("max-age=0"); //test removal without terminating ';'
+ checkPassRemovingPin(MAX_AGE_ZERO);
+ checkPassRemovingPin(MAX_AGE_ZERO + VALID_PIN1);
+
+ checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1, GOOD_MAX_AGE_SECONDS);
+ checkPassSettingPin(LONG_MAX_AGE + VALID_PIN1 + BACKUP_PIN1, MAX_MAX_AGE_SECONDS);
+
+ checkPassRemovingPin(VALID_PIN1 + MAX_AGE_ZERO + VALID_PIN1);
+ checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1);
+ checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN2);
+ checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN2 + INCLUDE_SUBDOMAINS);
+ checkPassSettingPin(VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2 + INCLUDE_SUBDOMAINS);
+ checkPassSettingPin(VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2 + REPORT_URI + INCLUDE_SUBDOMAINS);
+ checkPassSettingPin(INCLUDE_SUBDOMAINS + VALID_PIN1 + GOOD_MAX_AGE + BACKUP_PIN2);
+ checkPassSettingPin(GOOD_MAX_AGE + VALID_PIN1 + BACKUP_PIN1 + UNRECOGNIZED_DIRECTIVE);
+}
diff --git a/security/manager/ssl/tests/unit/test_pkcs11_insert_remove.js b/security/manager/ssl/tests/unit/test_pkcs11_insert_remove.js
new file mode 100644
index 000000000..b0592906c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_insert_remove.js
@@ -0,0 +1,41 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// This test loads a testing PKCS #11 module that simulates a token being
+// inserted and removed from a slot every 50ms. This causes the observer
+// service to broadcast the observation topics "smartcard-insert" and
+// "smartcard-remove", respectively. This test ensures that one of each event
+// has been succssfully observed, and then it unloads the test module.
+
+// Ensure that the appropriate initialization has happened.
+do_get_profile();
+Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+
+const gExpectedTokenLabel = "Test PKCS11 Tokeñ Label";
+
+function SmartcardObserver(type) {
+ this.type = type;
+ do_test_pending();
+}
+
+SmartcardObserver.prototype = {
+ observe: function(subject, topic, data) {
+ equal(topic, this.type, "Observed and expected types should match");
+ equal(gExpectedTokenLabel, data,
+ "Expected and observed token labels should match");
+ Services.obs.removeObserver(this, this.type);
+ do_test_finished();
+ }
+};
+
+function run_test() {
+ Services.obs.addObserver(new SmartcardObserver("smartcard-insert"),
+ "smartcard-insert", false);
+ Services.obs.addObserver(new SmartcardObserver("smartcard-remove"),
+ "smartcard-remove", false);
+
+ loadPKCS11TestModule(false);
+}
diff --git a/security/manager/ssl/tests/unit/test_pkcs11_module.js b/security/manager/ssl/tests/unit/test_pkcs11_module.js
new file mode 100644
index 000000000..f00143187
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_module.js
@@ -0,0 +1,121 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests the methods and attributes for interfacing with a PKCS #11 module and
+// the module database.
+
+// Ensure that the appropriate initialization has happened.
+do_get_profile();
+
+const gModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
+ .getService(Ci.nsIPKCS11ModuleDB);
+
+function checkTestModuleNotPresent() {
+ let modules = gModuleDB.listModules();
+ ok(modules.hasMoreElements(),
+ "One or more modules should be present with test module not present");
+ while (modules.hasMoreElements()) {
+ let module = modules.getNext().QueryInterface(Ci.nsIPKCS11Module);
+ notEqual(module.name, "PKCS11 Test Module",
+ "Non-test module name shouldn't equal 'PKCS11 Test Module'");
+ ok(!(module.libName && module.libName.includes("pkcs11testmodule")),
+ "Non-test module lib name should not include 'pkcs11testmodule'");
+ }
+
+ throws(() => gModuleDB.findModuleByName("PKCS11 Test Module"),
+ /NS_ERROR_FAILURE/, "Test module should not be findable by name");
+}
+
+/**
+ * Checks that the test module exists in the module list.
+ * Also checks various attributes of the test module for correctness.
+ *
+ * @returns {nsIPKCS11Module}
+ * The test module.
+ */
+function checkTestModuleExists() {
+ let modules = gModuleDB.listModules();
+ ok(modules.hasMoreElements(),
+ "One or more modules should be present with test module present");
+ let testModule = null;
+ while (modules.hasMoreElements()) {
+ let module = modules.getNext().QueryInterface(Ci.nsIPKCS11Module);
+ if (module.name == "PKCS11 Test Module") {
+ testModule = module;
+ break;
+ }
+ }
+ notEqual(testModule, null, "Test module should have been found");
+ notEqual(testModule.libName, null, "Test module lib name should not be null");
+ ok(testModule.libName.includes(ctypes.libraryName("pkcs11testmodule")),
+ "Test module lib name should include lib name of 'pkcs11testmodule'");
+
+ notEqual(gModuleDB.findModuleByName("PKCS11 Test Module"), null,
+ "Test module should be findable by name");
+
+ return testModule;
+}
+
+function run_test() {
+ // Check that if we have never added the test module, that we don't find it
+ // in the module list.
+ checkTestModuleNotPresent();
+
+ // Check that adding the test module makes it appear in the module list.
+ loadPKCS11TestModule(true);
+ let testModule = checkTestModuleExists();
+
+ // Check that listing the slots for the test module works.
+ let slots = testModule.listSlots();
+ let testModuleSlotNames = [];
+ while (slots.hasMoreElements()) {
+ let slot = slots.getNext().QueryInterface(Ci.nsIPKCS11Slot);
+ testModuleSlotNames.push(slot.name);
+ }
+ testModuleSlotNames.sort();
+ const expectedSlotNames = ["Test PKCS11 Slot", "Test PKCS11 Slot 二"];
+ deepEqual(testModuleSlotNames, expectedSlotNames,
+ "Actual and expected slot names should be equal");
+
+ // Check that finding the test slot by name is possible, and that trying to
+ // find a non-present slot fails.
+ notEqual(testModule.findSlotByName("Test PKCS11 Slot"), null,
+ "Test slot should be findable by name");
+ throws(() => testModule.findSlotByName("Not Present"), /NS_ERROR_FAILURE/,
+ "Non-present slot should not be findable by name");
+
+ // Check that the strangely named nsIPKCS11ModuleDB.findSlotByName() works.
+ // In particular, a comment in nsPKCS11Slot.cpp notes that the method
+ // "is essentially the same as nsIPK11Token::findTokenByName, except that it
+ // returns an nsIPKCS11Slot".
+ let strBundleSvc = Cc["@mozilla.org/intl/stringbundle;1"]
+ .getService(Ci.nsIStringBundleService);
+ let bundle =
+ strBundleSvc.createBundle("chrome://pipnss/locale/pipnss.properties");
+ let internalTokenName = bundle.GetStringFromName("PrivateTokenDescription");
+ let internalTokenAsSlot = gModuleDB.findSlotByName(internalTokenName);
+ notEqual(internalTokenAsSlot, null,
+ "Internal 'slot' should be findable by name via the module DB");
+ ok(internalTokenAsSlot instanceof Ci.nsIPKCS11Slot,
+ "Module DB findSlotByName() should return a token as an nsIPKCS11Slot");
+ equal(internalTokenAsSlot.name,
+ bundle.GetStringFromName("PrivateSlotDescription"),
+ "Spot check: actual and expected internal 'slot' names should be equal");
+ throws(() => gModuleDB.findSlotByName("Not Present"), /NS_ERROR_FAILURE/,
+ "Non-present 'slot' should not be findable by name via the module DB");
+
+ // Check that deleting the test module makes it disappear from the module list.
+ let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
+ pkcs11.deleteModule("PKCS11 Test Module");
+ checkTestModuleNotPresent();
+
+ // Check miscellaneous module DB methods and attributes.
+ notEqual(gModuleDB.getInternal(), null,
+ "The internal module should be present");
+ notEqual(gModuleDB.getInternalFIPS(), null,
+ "The internal FIPS module should be present");
+ ok(gModuleDB.canToggleFIPS, "It should be possible to toggle FIPS");
+ ok(!gModuleDB.isFIPSEnabled, "FIPS should not be enabled");
+}
diff --git a/security/manager/ssl/tests/unit/test_pkcs11_no_events_after_removal.js b/security/manager/ssl/tests/unit/test_pkcs11_no_events_after_removal.js
new file mode 100644
index 000000000..f31d1d494
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_no_events_after_removal.js
@@ -0,0 +1,29 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// This test loads a testing PKCS #11 module that simulates a token being
+// inserted and removed from a slot every 50ms. This causes the observer
+// service to broadcast the observation topics "smartcard-insert" and
+// "smartcard-remove", respectively. This test ensures that these events
+// are no longer emitted once the module has been unloaded.
+
+// Ensure that the appropriate initialization has happened.
+do_get_profile();
+Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+
+function run_test() {
+ let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
+ loadPKCS11TestModule(true);
+ pkcs11.deleteModule("PKCS11 Test Module");
+ Services.obs.addObserver(function() {
+ ok(false, "smartcard-insert event should not have been emitted");
+ }, "smartcard-insert", false);
+ Services.obs.addObserver(function() {
+ ok(false, "smartcard-remove event should not have been emitted");
+ }, "smartcard-remove", false);
+ do_timeout(500, do_test_finished);
+ do_test_pending();
+}
diff --git a/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js b/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js
new file mode 100644
index 000000000..d64d194e4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js
@@ -0,0 +1,49 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// In safe mode, PKCS#11 modules should not be loaded. This test tests this by
+// simulating starting in safe mode and then attempting to load a module.
+
+function run_test() {
+ do_get_profile();
+
+ // Simulate starting in safe mode.
+ let xulRuntime = {
+ inSafeMode: true,
+ logConsoleErrors: true,
+ OS: "XPCShell",
+ XPCOMABI: "noarch-spidermonkey",
+ invalidateCachesOnRestart: function invalidateCachesOnRestart() {
+ // Do nothing
+ },
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULRuntime])
+ };
+
+ let xulRuntimeFactory = {
+ createInstance: function (outer, iid) {
+ if (outer != null) {
+ throw new Error(Cr.NS_ERROR_NO_AGGREGATION);
+ }
+ return xulRuntime.QueryInterface(iid);
+ }
+ };
+
+ let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+ const XULRUNTIME_CONTRACTID = "@mozilla.org/xre/runtime;1";
+ const XULRUNTIME_CID = Components.ID("{f0f0b230-5525-4127-98dc-7bca39059e70}");
+ registrar.registerFactory(XULRUNTIME_CID, "XULRuntime", XULRUNTIME_CONTRACTID,
+ xulRuntimeFactory);
+
+ // When starting in safe mode, the test module should fail to load.
+ let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
+ let libraryName = ctypes.libraryName("pkcs11testmodule");
+ let libraryFile = Services.dirsvc.get("CurWorkD", Ci.nsILocalFile);
+ libraryFile.append("pkcs11testmodule");
+ libraryFile.append(libraryName);
+ ok(libraryFile.exists(), "The pkcs11testmodule file should exist");
+ throws(() => pkcs11.addModule("PKCS11 Test Module", libraryFile.path, 0, 0),
+ /NS_ERROR_FAILURE/, "addModule should throw when in safe mode");
+}
diff --git a/security/manager/ssl/tests/unit/test_pkcs11_slot.js b/security/manager/ssl/tests/unit/test_pkcs11_slot.js
new file mode 100644
index 000000000..8aebf0439
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_slot.js
@@ -0,0 +1,38 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests the methods and attributes for interfacing with a PKCS #11 slot.
+
+// Ensure that the appropriate initialization has happened.
+do_get_profile();
+
+function run_test() {
+ loadPKCS11TestModule(false);
+
+ let moduleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
+ .getService(Ci.nsIPKCS11ModuleDB);
+ let testModule = moduleDB.findModuleByName("PKCS11 Test Module");
+ let testSlot = testModule.findSlotByName("Test PKCS11 Slot 二");
+
+ equal(testSlot.name, "Test PKCS11 Slot 二",
+ "Actual and expected name should match");
+ equal(testSlot.desc, "Test PKCS11 Slot 二",
+ "Actual and expected description should match");
+ equal(testSlot.manID, "Test PKCS11 Manufacturer ID",
+ "Actual and expected manufacturer ID should match");
+ equal(testSlot.HWVersion, "0.0",
+ "Actual and expected hardware version should match");
+ equal(testSlot.FWVersion, "0.0",
+ "Actual and expected firmware version should match");
+ equal(testSlot.status, Ci.nsIPKCS11Slot.SLOT_READY,
+ "Actual and expected status should match");
+ equal(testSlot.tokenName, "Test PKCS11 Tokeñ 2 Label",
+ "Actual and expected token name should match");
+
+ let testToken = testSlot.getToken();
+ notEqual(testToken, null, "getToken() should succeed");
+ equal(testToken.tokenLabel, "Test PKCS11 Tokeñ 2 Label",
+ "Spot check: the actual and expected test token labels should be equal");
+}
diff --git a/security/manager/ssl/tests/unit/test_pkcs11_token.js b/security/manager/ssl/tests/unit/test_pkcs11_token.js
new file mode 100644
index 000000000..69b2cb384
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_token.js
@@ -0,0 +1,119 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests the methods and attributes for interfacing with a PKCS #11 token, using
+// the internal key token.
+// We don't use either of the test tokens in the test PKCS #11 module because:
+// 1. Test token 1 cyclically inserts and removes itself in a tight loop.
+// Using token 1 would complicate the test and introduce intermittent
+// failures.
+// 2. Neither test token implements login or password related functionality.
+// We want to test such functionality.
+// 3. Using the internal token lets us actually test the internal token works
+// as expected.
+
+// Ensure that the appropriate initialization has happened.
+do_get_profile();
+
+function checkBasicAttributes(token) {
+ let strBundleSvc = Cc["@mozilla.org/intl/stringbundle;1"]
+ .getService(Ci.nsIStringBundleService);
+ let bundle =
+ strBundleSvc.createBundle("chrome://pipnss/locale/pipnss.properties");
+
+ let expectedTokenName = bundle.GetStringFromName("PrivateTokenDescription");
+ equal(token.tokenName, expectedTokenName,
+ "Actual and expected name should match");
+ equal(token.tokenLabel, expectedTokenName,
+ "Actual and expected label should match");
+ equal(token.tokenManID, bundle.GetStringFromName("ManufacturerID"),
+ "Actual and expected manufacturer ID should match");
+ equal(token.tokenHWVersion, "0.0",
+ "Actual and expected hardware version should match");
+ equal(token.tokenFWVersion, "0.0",
+ "Actual and expected firmware version should match");
+ equal(token.tokenSerialNumber, "0000000000000000",
+ "Actual and expected serial number should match");
+}
+
+/**
+ * Checks the various password related features of the given token.
+ * The token should already have been init with a password and be logged into.
+ * The password of the token will be reset after calling this function.
+ *
+ * @param {nsIPK11Token} token
+ * The token to test.
+ * @param {String} initialPW
+ * The password that the token should have been init with.
+ */
+function checkPasswordFeaturesAndResetPassword(token, initialPW) {
+ ok(!token.needsUserInit,
+ "Token should not need user init after setting a password");
+
+ equal(token.minimumPasswordLength, 0,
+ "Actual and expected min password length should match");
+
+ token.setAskPasswordDefaults(10, 20);
+ equal(token.getAskPasswordTimes(), 10,
+ "Actual and expected ask password times should match");
+ equal(token.getAskPasswordTimeout(), 20,
+ "Actual and expected ask password timeout should match");
+
+ ok(token.checkPassword(initialPW),
+ "checkPassword() should succeed if the correct initial password is given");
+ token.changePassword(initialPW, "newPW ÿ 一二三");
+ ok(token.checkPassword("newPW ÿ 一二三"),
+ "checkPassword() should succeed if the correct new password is given");
+
+ ok(!token.checkPassword("wrongPW"),
+ "checkPassword() should fail if an incorrect password is given");
+ ok(!token.isLoggedIn(),
+ "Token should be logged out after an incorrect password was given");
+ ok(!token.needsUserInit,
+ "Token should still be init with a password even if an incorrect " +
+ "password was given");
+
+ token.reset();
+ ok(token.needsUserInit,
+ "Token should need password init after reset");
+ ok(!token.isLoggedIn(), "Token should be logged out of after reset");
+}
+
+function run_test() {
+ let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+ .getService(Ci.nsIPK11TokenDB);
+ let token = tokenDB.getInternalKeyToken();
+ notEqual(token, null, "The internal token should be present");
+
+ checkBasicAttributes(token);
+
+ ok(!token.isLoggedIn(), "Token should not be logged into yet");
+ // Test that attempting to log out even when the token was not logged into
+ // does not result in an error.
+ token.logoutSimple();
+ ok(!token.isLoggedIn(), "Token should still not be logged into");
+
+ let initialPW = "foo 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/? 一二三";
+ token.initPassword(initialPW);
+ token.login(/*force*/ false);
+ ok(token.isLoggedIn(), "Token should now be logged into");
+
+ checkPasswordFeaturesAndResetPassword(token, initialPW);
+
+ // We reset the password previously, so we need to initialize again.
+ token.initPassword("arbitrary");
+ ok(token.isLoggedIn(),
+ "Token should be logged into after initializing password again");
+ token.logoutSimple();
+ ok(!token.isLoggedIn(),
+ "Token should be logged out after calling logoutSimple()");
+
+ ok(!token.isHardwareToken(),
+ "The internal token should not be considered a hardware token");
+ ok(token.isFriendly(),
+ "The internal token should always be considered friendly");
+ ok(token.needsLogin(),
+ "The internal token should always need authentication");
+}
diff --git a/security/manager/ssl/tests/unit/test_pkcs11_tokenDB.js b/security/manager/ssl/tests/unit/test_pkcs11_tokenDB.js
new file mode 100644
index 000000000..ac382ab82
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_pkcs11_tokenDB.js
@@ -0,0 +1,45 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests the methods for interfacing with the PKCS #11 token database.
+
+// Ensure that the appropriate initialization has happened.
+do_get_profile();
+
+function run_test() {
+ let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
+ .getService(Ci.nsIPK11TokenDB);
+
+ let tokenListPreLoad = tokenDB.listTokens();
+ while (tokenListPreLoad.hasMoreElements()) {
+ let token = tokenListPreLoad.getNext().QueryInterface(Ci.nsIPK11Token);
+ notEqual(token.tokenLabel, "Test PKCS11 Tokeñ Label",
+ "Test PKCS11 Token 1 should not be listed prior to module load");
+ notEqual(token.tokenLabel, "Test PKCS11 Tokeñ 2 Label",
+ "Test PKCS11 Token 2 should not be listed prior to module load");
+ }
+
+ throws(() => tokenDB.findTokenByName("Test PKCS11 Tokeñ Label"),
+ /NS_ERROR_FAILURE/,
+ "Non-present test token 1 should not be findable by name");
+ throws(() => tokenDB.findTokenByName("Test PKCS11 Tokeñ 2 Label"),
+ /NS_ERROR_FAILURE/,
+ "Non-present test token 2 should not be findable by name");
+
+ loadPKCS11TestModule(false);
+
+ // Test Token 1 is simulated to insert and remove itself in a tight loop, so
+ // we don't bother testing that it's present.
+ let tokenListPostLoad = tokenDB.listTokens();
+ let foundTokenNames = [];
+ while (tokenListPostLoad.hasMoreElements()) {
+ let token = tokenListPostLoad.getNext().QueryInterface(Ci.nsIPK11Token);
+ foundTokenNames.push(token.tokenName);
+ }
+ ok(foundTokenNames.includes("Test PKCS11 Tokeñ 2 Label"),
+ "Test PKCS11 Token 2 should be listed after module load");
+
+ notEqual(tokenDB.findTokenByName("Test PKCS11 Tokeñ 2 Label"), null,
+ "Test token 2 should be findable by name after loading test module");
+}
diff --git a/security/manager/ssl/tests/unit/test_sdr.js b/security/manager/ssl/tests/unit/test_sdr.js
new file mode 100644
index 000000000..3258ec901
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sdr.js
@@ -0,0 +1,87 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests various aspects of the nsISecretDecoderRing implementation.
+
+do_get_profile();
+
+let gSetPasswordShownCount = 0;
+
+// Mock implementation of nsITokenPasswordDialogs.
+const gTokenPasswordDialogs = {
+ setPassword: (ctx, tokenName, canceled) => {
+ gSetPasswordShownCount++;
+ do_print(`setPassword() called; shown ${gSetPasswordShownCount} times`);
+ do_print(`tokenName: ${tokenName}`);
+ canceled.value = false;
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsITokenPasswordDialogs])
+};
+
+function run_test() {
+ // We have to set a password and login before we attempt to encrypt anything.
+ // In particular, failing to do so will cause the Encrypt() implementation to
+ // pop up a dialog asking for a password to be set. This won't work in the
+ // xpcshell environment and will lead to an assertion.
+ loginToDBWithDefaultPassword();
+
+ let sdr = Cc["@mozilla.org/security/sdr;1"]
+ .getService(Ci.nsISecretDecoderRing);
+
+ // Test valid inputs for encryptString() and decryptString().
+ let inputs = [
+ "",
+ " ", // First printable latin1 character (code point 32).
+ "foo",
+ "1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?",
+ "¡äöüÿ", // Misc + last printable latin1 character (code point 255).
+ "aaa 一二三", // Includes Unicode with code points outside [0, 255].
+ ];
+ for (let input of inputs) {
+ let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+ .createInstance(Ci.nsIScriptableUnicodeConverter);
+ converter.charset = "UTF-8";
+
+ let convertedInput = converter.ConvertFromUnicode(input);
+ convertedInput += converter.Finish();
+
+ let encrypted = sdr.encryptString(convertedInput);
+
+ notEqual(convertedInput, encrypted,
+ "Encrypted input should not just be the input itself");
+
+ try {
+ atob(encrypted);
+ } catch (e) {
+ ok(false, `encryptString() should have returned Base64: ${e}`);
+ }
+
+ equal(convertedInput, sdr.decryptString(encrypted),
+ "decryptString(encryptString(input)) should return input");
+ }
+
+ // Test invalid inputs for decryptString().
+ throws(() => sdr.decryptString("*"), /NS_ERROR_ILLEGAL_VALUE/,
+ "decryptString() should throw if given non-Base64 input");
+
+ // Test calling changePassword() pops up the appropriate dialog.
+ // Note: On Android, nsITokenPasswordDialogs is apparently not implemented,
+ // which also seems to prevent us from mocking out the interface.
+ if (AppConstants.platform != "android") {
+ let tokenPasswordDialogsCID =
+ MockRegistrar.register("@mozilla.org/nsTokenPasswordDialogs;1",
+ gTokenPasswordDialogs);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(tokenPasswordDialogsCID);
+ });
+
+ equal(gSetPasswordShownCount, 0,
+ "changePassword() dialog should have been shown zero times");
+ sdr.changePassword();
+ equal(gSetPasswordShownCount, 1,
+ "changePassword() dialog should have been shown exactly once");
+ }
+}
diff --git a/security/manager/ssl/tests/unit/test_session_resumption.js b/security/manager/ssl/tests/unit/test_session_resumption.js
new file mode 100644
index 000000000..eea6b5f54
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_session_resumption.js
@@ -0,0 +1,159 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that PSM makes the correct determination of the security status of
+// loads involving session resumption (i.e. when a TLS handshake bypasses the
+// AuthCertificate callback).
+
+do_get_profile();
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+do_register_cleanup(() => {
+ Services.prefs.clearUserPref("security.OCSP.enabled");
+});
+
+Services.prefs.setIntPref("security.OCSP.enabled", 1);
+
+addCertFromFile(certdb, "bad_certs/evroot.pem", "CTu,,");
+addCertFromFile(certdb, "bad_certs/ev-test-intermediate.pem", ",,");
+
+// For expired.example.com, the platform will make a connection that will fail.
+// Using information gathered at that point, an override will be added and
+// another connection will be made. This connection will succeed. At that point,
+// as long as the session cache isn't cleared, subsequent new connections should
+// use session resumption, thereby bypassing the AuthCertificate hook. We need
+// to ensure that the correct security state is propagated to the new connection
+// information object.
+function add_resume_non_ev_with_override_test() {
+ // This adds the override and makes one successful connection.
+ add_cert_override_test("expired.example.com",
+ Ci.nsICertOverrideService.ERROR_TIME,
+ SEC_ERROR_EXPIRED_CERTIFICATE);
+
+ // This connects again, using session resumption. Note that we don't clear
+ // the TLS session cache between these operations (that would defeat the
+ // purpose).
+ add_connection_test("expired.example.com", PRErrorCodeSuccess, null,
+ (transportSecurityInfo) => {
+ ok(transportSecurityInfo.securityState &
+ Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN,
+ "expired.example.com should have STATE_CERT_USER_OVERRIDDEN flag");
+ let sslStatus = transportSecurityInfo
+ .QueryInterface(Ci.nsISSLStatusProvider)
+ .SSLStatus;
+ ok(!sslStatus.isDomainMismatch,
+ "expired.example.com should not have isDomainMismatch set");
+ ok(sslStatus.isNotValidAtThisTime,
+ "expired.example.com should have isNotValidAtThisTime set");
+ ok(!sslStatus.isUntrusted,
+ "expired.example.com should not have isUntrusted set");
+ ok(!sslStatus.isExtendedValidation,
+ "expired.example.com should not have isExtendedValidation set");
+ }
+ );
+}
+
+// Helper function that adds a test that connects to ev-test.example.com and
+// verifies that it validates as EV (or not, if we're running a non-debug
+// build). This assumes that an appropriate OCSP responder is running or that
+// good responses are cached.
+function add_one_ev_test() {
+ add_connection_test("ev-test.example.com", PRErrorCodeSuccess, null,
+ (transportSecurityInfo) => {
+ ok(!(transportSecurityInfo.securityState &
+ Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN),
+ "ev-test.example.com should not have STATE_CERT_USER_OVERRIDDEN flag");
+ let sslStatus = transportSecurityInfo
+ .QueryInterface(Ci.nsISSLStatusProvider)
+ .SSLStatus;
+ ok(!sslStatus.isDomainMismatch,
+ "ev-test.example.com should not have isDomainMismatch set");
+ ok(!sslStatus.isNotValidAtThisTime,
+ "ev-test.example.com should not have isNotValidAtThisTime set");
+ ok(!sslStatus.isUntrusted,
+ "ev-test.example.com should not have isUntrusted set");
+ ok(!gEVExpected || sslStatus.isExtendedValidation,
+ "ev-test.example.com should have isExtendedValidation set " +
+ "(or this is a non-debug build)");
+ }
+ );
+}
+
+// This test is similar, except with extended validation. We should connect
+// successfully, and the certificate should be EV in debug builds. Without
+// clearing the session cache, we should connect successfully again, this time
+// with session resumption. The certificate should again be EV in debug builds.
+function add_resume_ev_test() {
+ const SERVER_PORT = 8888;
+ let expectedRequestPaths = gEVExpected ? [ "ev-test-intermediate", "ev-test" ]
+ : [ "ev-test" ];
+ let responseTypes = gEVExpected ? [ "good", "good" ] : [ "good" ];
+ // Since we cache OCSP responses, we only ever actually serve one set.
+ let ocspResponder = startOCSPResponder(SERVER_PORT, "localhost", "bad_certs",
+ expectedRequestPaths,
+ expectedRequestPaths.slice(),
+ null, responseTypes);
+ // We should be able to connect and verify the certificate as EV (in debug
+ // builds).
+ add_one_ev_test();
+ // We should be able to connect again (using session resumption). In debug
+ // builds, the certificate should be noted as EV. Again, it's important that
+ // nothing clears the TLS cache in between these two operations.
+ add_one_ev_test();
+
+ add_test(() => {
+ ocspResponder.stop(run_next_test);
+ });
+}
+
+const statsPtr = getSSLStatistics();
+const toInt32 = ctypes.Int64.lo;
+const GOOD_DOMAIN = "good.include-subdomains.pinning.example.com";
+
+// Connect to the same domain with two origin attributes and check if any ssl
+// session is resumed.
+function add_origin_attributes_test(originAttributes1, originAttributes2,
+ resumeExpected) {
+ add_connection_test(GOOD_DOMAIN, PRErrorCodeSuccess, clearSessionCache, null,
+ null, originAttributes1);
+
+ let hitsBeforeConnect;
+ let missesBeforeConnect;
+ let expectedHits = resumeExpected ? 1 : 0;
+ let expectedMisses = 1 - expectedHits;
+
+ add_connection_test(GOOD_DOMAIN, PRErrorCodeSuccess,
+ function() {
+ // Add the hits and misses before connection.
+ let stats = statsPtr.contents;
+ hitsBeforeConnect = toInt32(stats.sch_sid_cache_hits);
+ missesBeforeConnect =
+ toInt32(stats.sch_sid_cache_misses);
+ },
+ function() {
+ let stats = statsPtr.contents;
+ equal(toInt32(stats.sch_sid_cache_hits),
+ hitsBeforeConnect + expectedHits,
+ "Unexpected cache hits");
+ equal(toInt32(stats.sch_sid_cache_misses),
+ missesBeforeConnect + expectedMisses,
+ "Unexpected cache misses");
+ }, null, originAttributes2);
+}
+
+function run_test() {
+ add_tls_server_setup("BadCertServer", "bad_certs");
+ add_resume_non_ev_with_override_test();
+ add_resume_ev_test();
+ add_origin_attributes_test({}, {}, true);
+ add_origin_attributes_test({ userContextId: 1 }, { userContextId: 2 }, false);
+ add_origin_attributes_test({ userContextId: 3 }, { userContextId: 3 }, true);
+ add_origin_attributes_test({ firstPartyDomain: "foo.com" },
+ { firstPartyDomain: "bar.com" }, false);
+ add_origin_attributes_test({ firstPartyDomain: "baz.com" },
+ { firstPartyDomain: "baz.com" }, true);
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_signed_apps-marketplace.js b/security/manager/ssl/tests/unit/test_signed_apps-marketplace.js
new file mode 100644
index 000000000..9f2af752d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps-marketplace.js
@@ -0,0 +1,42 @@
+"use strict";
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
+
+function run_test() {
+ run_next_test();
+}
+
+function check_open_result(name, expectedRv) {
+ return function openSignedAppFileCallback(rv, aZipReader, aSignerCert) {
+ do_print("openSignedAppFileCallback called for " + name);
+ equal(rv, expectedRv, "Actual and expected return value should match");
+ equal(aZipReader != null, Components.isSuccessCode(expectedRv),
+ "ZIP reader should be null only if the return value denotes failure");
+ equal(aSignerCert != null, Components.isSuccessCode(expectedRv),
+ "Signer cert should be null only if the return value denotes failure");
+ run_next_test();
+ };
+}
+
+function original_app_path(test_name) {
+ return do_get_file("test_signed_apps/" + test_name + ".zip", false);
+}
+
+// Test that we no longer trust the test root cert that was originally used
+// during development of B2G 1.0.
+add_test(function () {
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppMarketplaceProdPublicRoot,
+ original_app_path("test-privileged-app-test-1.0"),
+ check_open_result("test-privileged-app-test-1.0",
+ getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_ISSUER)));
+});
+
+// Test that we trust the root cert used by by the Firefox Marketplace.
+add_test(function () {
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppMarketplaceProdPublicRoot,
+ original_app_path("privileged-app-test-1.0"),
+ check_open_result("privileged-app-test-1.0", Cr.NS_OK));
+});
diff --git a/security/manager/ssl/tests/unit/test_signed_apps.js b/security/manager/ssl/tests/unit/test_signed_apps.js
new file mode 100644
index 000000000..819ea767a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps.js
@@ -0,0 +1,233 @@
+"use strict";
+/* To regenerate the certificates and apps for this test:
+
+ cd security/manager/ssl/tests/unit/test_signed_apps
+ PATH=$NSS/bin:$NSS/lib:$PATH ./generate.sh
+ cd ../../../../../..
+ make -C $OBJDIR/security/manager/ssl/tests
+
+ $NSS is the path to NSS binaries and libraries built for the host platform.
+ If you get error messages about "CertUtil" on Windows, then it means that
+ the Windows CertUtil.exe is ahead of the NSS certutil.exe in $PATH.
+
+ Check in the generated files. These steps are not done as part of the build
+ because we do not want to add a build-time dependency on the OpenSSL or NSS
+ tools or libraries built for the host platform.
+*/
+
+// XXX from prio.h
+const PR_RDWR = 0x04;
+const PR_CREATE_FILE = 0x08;
+const PR_TRUNCATE = 0x20;
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
+
+// Creates a new app package based in the inFilePath package, with a set of
+// modifications (including possibly deletions) applied to the existing entries,
+// and/or a set of new entries to be included.
+function tamper(inFilePath, outFilePath, modifications, newEntries) {
+ let writer = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
+ writer.open(outFilePath, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
+ try {
+ let reader = Cc["@mozilla.org/libjar/zip-reader;1"]
+ .createInstance(Ci.nsIZipReader);
+ reader.open(inFilePath);
+ try {
+ let entries = reader.findEntries("");
+ while (entries.hasMore()) {
+ let entryName = entries.getNext();
+ let inEntry = reader.getEntry(entryName);
+ let entryInput = reader.getInputStream(entryName);
+ try {
+ let f = modifications[entryName];
+ let outEntry, outEntryInput;
+ if (f) {
+ [outEntry, outEntryInput] = f(inEntry, entryInput);
+ delete modifications[entryName];
+ } else {
+ [outEntry, outEntryInput] = [inEntry, entryInput];
+ }
+ // if f does not want the input entry to be copied to the output entry
+ // at all (i.e. it wants it to be deleted), it will return null.
+ if (outEntryInput) {
+ try {
+ writer.addEntryStream(entryName,
+ outEntry.lastModifiedTime,
+ outEntry.compression,
+ outEntryInput,
+ false);
+ } finally {
+ if (entryInput != outEntryInput) {
+ outEntryInput.close();
+ }
+ }
+ }
+ } finally {
+ entryInput.close();
+ }
+ }
+ } finally {
+ reader.close();
+ }
+
+ // Any leftover modification means that we were expecting to modify an entry
+ // in the input file that wasn't there.
+ for (let name in modifications) {
+ if (modifications.hasOwnProperty(name)) {
+ throw new Error("input file was missing expected entries: " + name);
+ }
+ }
+
+ // Now, append any new entries to the end
+ newEntries.forEach(function(newEntry) {
+ let sis = Cc["@mozilla.org/io/string-input-stream;1"]
+ .createInstance(Ci.nsIStringInputStream);
+ try {
+ sis.setData(newEntry.content, newEntry.content.length);
+ writer.addEntryStream(newEntry.name,
+ new Date(),
+ Ci.nsIZipWriter.COMPRESSION_BEST,
+ sis,
+ false);
+ } finally {
+ sis.close();
+ }
+ });
+ } finally {
+ writer.close();
+ }
+}
+
+function removeEntry(entry, entryInput) { return [null, null]; }
+
+function truncateEntry(entry, entryInput) {
+ if (entryInput.available() == 0) {
+ throw new Error("Truncating already-zero length entry will result in " +
+ "identical entry.");
+ }
+
+ let content = Cc["@mozilla.org/io/string-input-stream;1"]
+ .createInstance(Ci.nsIStringInputStream);
+ content.data = "";
+
+ return [entry, content];
+}
+
+function run_test() {
+ run_next_test();
+}
+
+function check_open_result(name, expectedRv) {
+ return function openSignedAppFileCallback(rv, aZipReader, aSignerCert) {
+ do_print("openSignedAppFileCallback called for " + name);
+ equal(rv, expectedRv, "Actual and expected return value should match");
+ equal(aZipReader != null, Components.isSuccessCode(expectedRv),
+ "ZIP reader should be null only if the return value denotes failure");
+ equal(aSignerCert != null, Components.isSuccessCode(expectedRv),
+ "Signer cert should be null only if the return value denotes failure");
+ run_next_test();
+ };
+}
+
+function original_app_path(test_name) {
+ return do_get_file("test_signed_apps/" + test_name + ".zip", false);
+}
+
+function tampered_app_path(test_name) {
+ return FileUtils.getFile("TmpD", ["test_signed_app-" + test_name + ".zip"]);
+}
+
+add_test(function () {
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("valid_app_1"),
+ check_open_result("valid", Cr.NS_OK));
+});
+
+add_test(function () {
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("unsigned_app_1"),
+ check_open_result("unsigned", Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED));
+});
+
+add_test(function () {
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("unknown_issuer_app_1"),
+ check_open_result("unknown_issuer",
+ getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_ISSUER)));
+});
+
+// Sanity check to ensure a no-op tampering gives a valid result
+add_test(function () {
+ let tampered = tampered_app_path("identity_tampering");
+ tamper(original_app_path("valid_app_1"), tampered, { }, []);
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, original_app_path("valid_app_1"),
+ check_open_result("identity_tampering", Cr.NS_OK));
+});
+
+add_test(function () {
+ let tampered = tampered_app_path("missing_rsa");
+ tamper(original_app_path("valid_app_1"), tampered, { "META-INF/A.RSA": removeEntry }, []);
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, tampered,
+ check_open_result("missing_rsa", Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED));
+});
+
+add_test(function () {
+ let tampered = tampered_app_path("missing_sf");
+ tamper(original_app_path("valid_app_1"), tampered, { "META-INF/A.SF": removeEntry }, []);
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, tampered,
+ check_open_result("missing_sf", Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID));
+});
+
+add_test(function () {
+ let tampered = tampered_app_path("missing_manifest_mf");
+ tamper(original_app_path("valid_app_1"), tampered, { "META-INF/MANIFEST.MF": removeEntry }, []);
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, tampered,
+ check_open_result("missing_manifest_mf",
+ Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID));
+});
+
+add_test(function () {
+ let tampered = tampered_app_path("missing_entry");
+ tamper(original_app_path("valid_app_1"), tampered, { "manifest.webapp": removeEntry }, []);
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, tampered,
+ check_open_result("missing_entry", Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING));
+});
+
+add_test(function () {
+ let tampered = tampered_app_path("truncated_entry");
+ tamper(original_app_path("valid_app_1"), tampered, { "manifest.webapp": truncateEntry }, []);
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, tampered,
+ check_open_result("truncated_entry", Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY));
+});
+
+add_test(function () {
+ let tampered = tampered_app_path("unsigned_entry");
+ tamper(original_app_path("valid_app_1"), tampered, {},
+ [ { "name": "unsigned.txt", "content": "unsigned content!" } ]);
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, tampered,
+ check_open_result("unsigned_entry", Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY));
+});
+
+add_test(function () {
+ let tampered = tampered_app_path("unsigned_metainf_entry");
+ tamper(original_app_path("valid_app_1"), tampered, {},
+ [ { name: "META-INF/unsigned.txt", content: "unsigned content!" } ]);
+ certdb.openSignedAppFileAsync(
+ Ci.nsIX509CertDB.AppXPCShellRoot, tampered,
+ check_open_result("unsigned_metainf_entry",
+ Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY));
+});
+
+// TODO: tampered MF, tampered SF
+// TODO: too-large MF, too-large RSA, too-large SF
+// TODO: MF and SF that end immediately after the last main header
+// (no CR nor LF)
+// TODO: broken headers to exercise the parser
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/README.md b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/README.md
new file mode 100644
index 000000000..5c6201534
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/README.md
@@ -0,0 +1,18 @@
+This file contains the scripts and binary files needed to regenerate the signed
+files used on the signed apps test.
+
+Prerequisites:
+
+* NSS 3.4 or higher.
+* Python 2.7 (should work with 2.6 also)
+* Bash
+
+Usage:
+
+Run
+
+./create_test_files.sh
+
+The new test files will be created at the ./testApps directory. Just copy the
+contents of this directory to the test directory (dom/apps/tests/signed and
+security/manager/ssl/tests/unit) to use the new files.
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/create_test_files.sh b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/create_test_files.sh
new file mode 100755
index 000000000..e211c3685
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/create_test_files.sh
@@ -0,0 +1,213 @@
+#!/bin/bash
+
+export NSS_DEFAULT_DB_TYPE=sql
+
+export BASE_PATH=`dirname $0`
+export SIGN_SCR_LOC=.
+export APPS_TEST_LOC=../../../../../../../dom/apps/tests/signed
+export TOOLKIT_WEBAPPS_TEST_LOC=../../../../../../../toolkit/webapps/tests/data/
+
+# Creates the entry zip files (unsigned apps) from the source directories
+packageApps() {
+APPS="unsigned_app_1 unsigned_app_origin unsigned_app_origin_toolkit_webapps"
+OLD_PWD=`pwd`
+cd ${BASE_PATH}
+for i in $APPS
+do
+ echo "Creating $i.zip"
+ cd $i && zip -r ../$i.zip . && cd ..
+done
+cd ${OLD_PWD}
+}
+
+
+# Function to create a signing database
+# Parameters:
+# $1: Output directory (where the DB will be created)
+createDb() {
+
+ db=$1
+
+ mkdir -p $db
+
+ # Insecure by design, so... please don't use this for anything serious
+ passwordfile=$db/passwordfile
+
+ echo insecurepassword > $passwordfile
+ certutil -d $db -N -f $passwordfile 2>&1 >/dev/null
+
+}
+
+# Add a CA cert and a signing cert to the database
+# Arguments:
+# $1: DB directory
+# $2: CA CN (don't include the CN=, just the value)
+# $3: Signing Cert CN (don't include the CN=, just the value)
+# $4: CA short name (don't use spaces!)
+# $5: Signing Cert short name (don't use spaces!)
+addCerts() {
+ org="O=Examplla Corporation,L=Mountain View,ST=CA,C=US"
+ ca_subj="CN=${2},${org}"
+ ee_subj="CN=${3},${org}"
+
+ noisefile=/tmp/noise.$$
+ head -c 32 /dev/urandom > $noisefile
+
+ ca_responses=/tmp/caresponses.$$
+ ee_responses=/tmp/earesponses
+
+ echo y > $ca_responses # Is this a CA?
+ echo >> $ca_responses # Accept default path length constraint (no constraint)
+ echo y >> $ca_responses # Is this a critical constraint?
+ echo n > $ee_responses # Is this a CA?
+ echo >> $ee_responses # Accept default path length constraint (no constraint)
+ echo y >> $ee_responses # Is this a critical constraint?
+
+ make_cert="certutil -d $db -f $passwordfile -S -g 2048 -Z SHA256 \
+ -z $noisefile -y 3 -2 --extKeyUsage critical,codeSigning"
+ $make_cert -v 480 -n ${4} -m 1 -s "$ca_subj" \
+ --keyUsage critical,certSigning -t ",,CTu" -x < $ca_responses 2>&1 >/dev/null
+ $make_cert -v 240 -n ${5} -c ${4} -m 2 -s "$ee_subj" \
+ --keyUsage critical,digitalSignature -t ",,," < $ee_responses 2>&1 >/dev/null
+
+ # In case we want to inspect the generated certs
+
+ # Also, we'll need this one later on
+ certutil -d $db -L -n ${4} -r -o $db/${4}.der
+ certutil -d $db -L -n ${5} -r -o $db/${5}.der
+
+ rm -f $noisefile $ee_responses $ca_responses
+}
+
+
+# Signs an app
+# Parameters:
+# $1: Database directory
+# $2: Unsigned ZIP file path
+# $3: Signed ZIP file path
+# $4: Store ID for the signed App
+# $5: Version of the signed App
+# $6: Nickname of the signing certificate
+signApp() {
+
+ db=$1
+
+ # Once again, this is INSECURE. It doesn't matter here but
+ # DON'T use this for anything production related
+ passwordfile=$db/passwordfile
+
+ python ${BASE_PATH}/${SIGN_SCR_LOC}/sign_b2g_app.py -d $db -f $passwordfile \
+ -k ${6} -i ${2} -o ${3} -S ${4} -V ${5}
+}
+
+DB_PATH=${BASE_PATH}/signingDB
+TEST_APP_PATH=${BASE_PATH}/testApps
+
+echo "Warning! The directories ${DB_PATH} and ${TEST_APP_PATH} will be erased!"
+echo "Do you want to proceed anyway?"
+select answer in "Yes" "No"
+do
+ case $answer in
+ Yes) break;;
+ No) exit 1;;
+ esac
+done
+
+rm -rf ${DB_PATH} ${TEST_APP_PATH}
+
+TRUSTED_EE=trusted_ee1
+UNTRUSTED_EE=untrusted_ee1
+TRUSTED_CA=trusted_ca1
+UNTRUSTED_CA=untrusted_ca1
+
+# First, we'll create a new couple of signing DBs
+createDb $DB_PATH
+addCerts $DB_PATH "Valid CA" "Store Cert" trusted_ca1 ${TRUSTED_EE}
+addCerts $DB_PATH "Invalid CA" "Invalid Cert" ${UNTRUSTED_CA} ${UNTRUSTED_EE}
+
+# Then we'll create the unsigned apps
+echo "Creating unsigned apps"
+packageApps
+
+# And then we'll create all the test apps...
+mkdir -p ${TEST_APP_PATH}
+
+# We need:
+# A valid signed file, with two different versions:
+# valid_app_1.zip
+# valid_app_2.zip
+VALID_UID=`uuidgen`
+signApp $DB_PATH ${BASE_PATH}/unsigned_app_1.zip \
+ $TEST_APP_PATH/valid_app_1.zip \
+ $VALID_UID 1 ${TRUSTED_EE}
+signApp $DB_PATH ${BASE_PATH}/unsigned_app_1.zip \
+ $TEST_APP_PATH/valid_app_2.zip \
+ $VALID_UID 2 ${TRUSTED_EE}
+
+
+# A corrupt_package:
+# corrupt_app_1.zip
+# A corrupt package is a package with a entry modified, for example...
+CURDIR=`pwd`
+export TEMP_DIR=$TEST_APP_PATH/aux_unzip_$$
+mkdir -p $TEMP_DIR
+cd $TEMP_DIR
+unzip ../valid_app_1.zip 2>&1 >/dev/null
+echo " - " >> index.html
+zip -r ../corrupt_app_1.zip * 2>&1 >/dev/null
+cd $CURDIR
+rm -rf $TEMP_DIR
+
+# A file signed by a unknown issuer
+# unknown_issuer_app_1.zip
+INVALID_UID=`uuidgen`
+signApp $DB_PATH ${BASE_PATH}/unsigned_app_1.zip \
+ $TEST_APP_PATH/unknown_issuer_app_1.zip \
+ $INVALID_UID 1 ${UNTRUSTED_EE}
+
+# And finally a priviledged signed file that includes the origin on the manifest
+# to avoid that reverting again
+PRIV_UID=`uuidgen`
+signApp $DB_PATH ${BASE_PATH}/unsigned_app_origin.zip \
+ $TEST_APP_PATH/origin_app_1.zip \
+ $PRIV_UID 1 ${TRUSTED_EE}
+
+# A privileged signed app needed for a toolkit/webapps test
+PRIV_TOOLKIT_UID=`uuidgen`
+signApp $DB_PATH ${BASE_PATH}/unsigned_app_origin_toolkit_webapps.zip \
+ $TEST_APP_PATH/custom_origin.zip \
+ $PRIV_TOOLKIT_UID 1 ${TRUSTED_EE}
+
+# Now let's copy the trusted cert to the app directory so we have everything
+# on the same place...
+cp ${DB_PATH}/${TRUSTED_CA}.der ${TEST_APP_PATH}
+
+cat <<EOF
+
+All done. The new test files are in ${TEST_APP_PATH}. You should copy the
+contents of that directory to the dom/apps/tests/signed directory and to
+the security/manager/ssl/tests/unit/test_signed_apps (which should be the
+parent of this directory) to install them.
+
+EOF
+
+echo "Do you wish me to do that for you now?"
+select answer in "Yes" "No"
+do
+ case $answer in
+ Yes) break;;
+ No) echo "Ok, not installing the new files"
+ echo "You should run: "
+ echo cp ${TEST_APP_PATH}/* ${BASE_PATH}/${APPS_TEST_LOC}
+ echo cp ${TEST_APP_PATH}/* ${TEST_APP_PATH}/../unsigned_app_1.zip ${BASE_PATH}/..
+ echo cp ${TEST_APP_PATH}/* ${BASE_PATH}/${TOOLKIT_WEBAPPS_TEST_LOC}
+ echo "to install them"
+ exit 0;;
+ esac
+done
+
+cp ${TEST_APP_PATH}/* ${BASE_PATH}/${APPS_TEST_LOC}
+cp ${TEST_APP_PATH}/* ${TEST_APP_PATH}/../unsigned_app_1.zip ${BASE_PATH}/..
+cp ${TEST_APP_PATH}/* ${BASE_PATH}/${TOOLKIT_WEBAPPS_TEST_LOC}
+
+echo "Done!"
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/nss_ctypes.py b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/nss_ctypes.py
new file mode 100644
index 000000000..35ca92959
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/nss_ctypes.py
@@ -0,0 +1,129 @@
+from ctypes import *
+import os
+import sys
+
+if sys.platform == 'darwin':
+ libprefix = "lib"
+ libsuffix = ".dylib"
+elif os.name == 'posix':
+ libprefix = "lib"
+ libsuffix = ".so"
+else: # assume windows
+ libprefix = ""
+ libsuffix = ".dll"
+
+plc = cdll.LoadLibrary(libprefix + "plc4" + libsuffix)
+nspr = cdll.LoadLibrary(libprefix + "nspr4" + libsuffix)
+nss = cdll.LoadLibrary(libprefix + "nss3" + libsuffix)
+smime = cdll.LoadLibrary(libprefix + "smime3" + libsuffix)
+
+nspr.PR_GetError.argtypes = []
+nspr.PR_GetError.restype = c_int32
+nspr.PR_ErrorToName.argtypes = [c_int32]
+nspr.PR_ErrorToName.restype = c_char_p
+
+def raise_if_not_SECSuccess(rv):
+ SECSuccess = 0
+ if (rv != SECSuccess):
+ raise ValueError(nspr.PR_ErrorToName(nspr.PR_GetError()))
+
+def raise_if_NULL(p):
+ if not p:
+ raise ValueError(nspr.PR_ErrorToName(nspr.PR_GetError()))
+ return p
+
+PRBool = c_int
+SECStatus = c_int
+
+# from secoidt.h
+SEC_OID_SHA1 = 4
+
+# from certt.h
+certUsageObjectSigner = 6
+
+class SECItem(Structure):
+ _fields_ = [("type", c_int),
+ ("data", c_char_p),
+ ("len", c_uint)]
+
+nss.NSS_Init.argtypes = [c_char_p]
+nss.NSS_Init.restype = SECStatus
+def NSS_Init(db_dir):
+ nss.NSS_Init.argtypes = [c_char_p]
+ nss.NSS_Init.restype = SECStatus
+ raise_if_not_SECSuccess(nss.NSS_Init(db_dir))
+
+nss.NSS_Shutdown.argtypes = []
+nss.NSS_Shutdown.restype = SECStatus
+def NSS_Shutdown():
+ raise_if_not_SECSuccess(nss.NSS_Shutdown())
+
+PK11PasswordFunc = CFUNCTYPE(c_char_p, c_void_p, PRBool, c_char_p)
+
+# pass the result of this as the wincx parameter when a wincx is required
+nss.PK11_SetPasswordFunc.argtypes = [PK11PasswordFunc]
+nss.PK11_SetPasswordFunc.restype = None
+
+# Set the return type as *void so Python doesn't touch it
+plc.PL_strdup.argtypes = [c_char_p]
+plc.PL_strdup.restype = c_void_p
+def SetPasswordContext(password):
+ def callback(slot, retry, arg):
+ return plc.PL_strdup(password)
+ wincx = PK11PasswordFunc(callback)
+ nss.PK11_SetPasswordFunc(wincx)
+ return wincx
+
+nss.CERT_GetDefaultCertDB.argtypes = []
+nss.CERT_GetDefaultCertDB.restype = c_void_p
+def CERT_GetDefaultCertDB():
+ return raise_if_NULL(nss.CERT_GetDefaultCertDB())
+
+nss.PK11_FindCertFromNickname.argtypes = [c_char_p, c_void_p]
+nss.PK11_FindCertFromNickname.restype = c_void_p
+def PK11_FindCertFromNickname(nickname, wincx):
+ return raise_if_NULL(nss.PK11_FindCertFromNickname(nickname, wincx))
+
+nss.CERT_DestroyCertificate.argtypes = [c_void_p]
+nss.CERT_DestroyCertificate.restype = None
+def CERT_DestroyCertificate(cert):
+ nss.CERT_DestroyCertificate(cert)
+
+smime.SEC_PKCS7CreateSignedData.argtypes = [c_void_p, c_int, c_void_p,
+ c_int, c_void_p,
+ c_void_p, c_void_p]
+smime.SEC_PKCS7CreateSignedData.restype = c_void_p
+def SEC_PKCS7CreateSignedData(cert, certusage, certdb, digestalg, digest, wincx):
+ item = SECItem(0, c_char_p(digest), len(digest))
+ return raise_if_NULL(smime.SEC_PKCS7CreateSignedData(cert, certusage, certdb,
+ digestalg,
+ pointer(item),
+ None, wincx))
+
+smime.SEC_PKCS7AddSigningTime.argtypes = [c_void_p]
+smime.SEC_PKCS7AddSigningTime.restype = SECStatus
+def SEC_PKCS7AddSigningTime(p7):
+ raise_if_not_SECSuccess(smime.SEC_PKCS7AddSigningTime(p7))
+
+smime.SEC_PKCS7IncludeCertChain.argtypes = [c_void_p, c_void_p]
+smime.SEC_PKCS7IncludeCertChain.restype = SECStatus
+def SEC_PKCS7IncludeCertChain(p7, wincx):
+ raise_if_not_SECSuccess(smime.SEC_PKCS7IncludeCertChain(p7, wincx))
+
+SEC_PKCS7EncoderOutputCallback = CFUNCTYPE(None, c_void_p, c_void_p, c_long)
+smime.SEC_PKCS7Encode.argtypes = [c_void_p, SEC_PKCS7EncoderOutputCallback,
+ c_void_p, c_void_p, c_void_p, c_void_p]
+smime.SEC_PKCS7Encode.restype = SECStatus
+def SEC_PKCS7Encode(p7, bulkkey, wincx):
+ outputChunks = []
+ def callback(chunks, data, len):
+ outputChunks.append(string_at(data, len))
+ callbackWrapper = SEC_PKCS7EncoderOutputCallback(callback)
+ raise_if_not_SECSuccess(smime.SEC_PKCS7Encode(p7, callbackWrapper,
+ None, None, None, wincx))
+ return "".join(outputChunks)
+
+smime.SEC_PKCS7DestroyContentInfo.argtypes = [c_void_p]
+smime.SEC_PKCS7DestroyContentInfo.restype = None
+def SEC_PKCS7DestroyContentInfo(p7):
+ smime.SEC_PKCS7DestroyContentInfo(p7)
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/sign_b2g_app.py b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/sign_b2g_app.py
new file mode 100644
index 000000000..89b385a9b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/sign_b2g_app.py
@@ -0,0 +1,174 @@
+import argparse
+from base64 import b64encode
+from hashlib import sha1
+import sys
+import zipfile
+import ctypes
+
+import nss_ctypes
+
+# Change the limits in JarSignatureVerification.cpp when you change the limits
+# here.
+max_entry_uncompressed_len = 100 * 1024 * 1024
+max_total_uncompressed_len = 500 * 1024 * 1024
+max_entry_count = 100 * 1000
+max_entry_filename_len = 1024
+max_mf_len = max_entry_count * 50
+max_sf_len = 1024
+
+
+
+def nss_load_cert(nss_db_dir, nss_password, cert_nickname):
+ nss_ctypes.NSS_Init(nss_db_dir)
+ try:
+ wincx = nss_ctypes.SetPasswordContext(nss_password)
+ cert = nss_ctypes.PK11_FindCertFromNickname(cert_nickname, wincx)
+ return (wincx, cert)
+ except:
+ nss_ctypes.NSS_Shutdown()
+ raise
+
+def nss_create_detached_signature(cert, dataToSign, wincx):
+ certdb = nss_ctypes.CERT_GetDefaultCertDB()
+ p7 = nss_ctypes.SEC_PKCS7CreateSignedData(cert,
+ nss_ctypes.certUsageObjectSigner,
+ certdb,
+ nss_ctypes.SEC_OID_SHA1,
+ sha1(dataToSign).digest(),
+ wincx )
+ try:
+ nss_ctypes.SEC_PKCS7AddSigningTime(p7)
+ nss_ctypes.SEC_PKCS7IncludeCertChain(p7, wincx)
+ return nss_ctypes.SEC_PKCS7Encode(p7, None, wincx)
+ finally:
+ nss_ctypes.SEC_PKCS7DestroyContentInfo(p7)
+
+# We receive a ids_json string for the toBeSigned app
+def sign_zip(in_zipfile_name, out_zipfile_name, cert, wincx, ids_json):
+ mf_entries = []
+ seen_entries = set()
+
+ total_uncompressed_len = 0
+ entry_count = 0
+ with zipfile.ZipFile(out_zipfile_name, 'w') as out_zip:
+ with zipfile.ZipFile(in_zipfile_name, 'r') as in_zip:
+ for entry_info in in_zip.infolist():
+ name = entry_info.filename
+
+ # Check for reserved and/or insane (potentially malicious) names
+ if name.endswith("/"):
+ pass
+ # Do nothing; we don't copy directory entries since they are just a
+ # waste of space.
+ elif name.lower().startswith("meta-inf/"):
+ # META-INF/* is reserved for our use
+ raise ValueError("META-INF entries are not allowed: %s" % (name))
+ elif len(name) > max_entry_filename_len:
+ raise ValueError("Entry's filename is too long: %s" % (name))
+ # TODO: elif name has invalid characters...
+ elif name in seen_entries:
+ # It is possible for a zipfile to have duplicate entries (with the exact
+ # same filenames). Python's zipfile module accepts them, but our zip
+ # reader in Gecko cannot do anything useful with them, and there's no
+ # sane reason for duplicate entries to exist, so reject them.
+ raise ValueError("Duplicate entry in input file: %s" % (name))
+ else:
+ entry_count += 1
+ if entry_count > max_entry_count:
+ raise ValueError("Too many entries in input archive")
+
+ seen_entries.add(name)
+
+ # Read in the input entry, but be careful to avoid going over the
+ # various limits we have, to minimize the likelihood that we'll run
+ # out of memory. Note that we can't use the length from entry_info
+ # because that might not be accurate if the input zip file is
+ # maliciously crafted to contain misleading metadata.
+ with in_zip.open(name, 'r') as entry_file:
+ contents = entry_file.read(max_entry_uncompressed_len + 1)
+ if len(contents) > max_entry_uncompressed_len:
+ raise ValueError("Entry is too large: %s" % (name))
+ total_uncompressed_len += len(contents)
+ if total_uncompressed_len > max_total_uncompressed_len:
+ raise ValueError("Input archive is too large")
+
+ # Copy the entry, using the same compression as used in the input file
+ out_zip.writestr(entry_info, contents)
+
+ # Add the entry to the manifest we're building
+ mf_entries.append('Name: %s\nSHA1-Digest: %s\n'
+ % (name, b64encode(sha1(contents).digest())))
+ if (ids_json):
+ mf_entries.append('Name: %s\nSHA1-Digest: %s\n'
+ % ("META-INF/ids.json", b64encode(sha1(ids_json).digest())))
+
+ mf_contents = 'Manifest-Version: 1.0\n\n' + '\n'.join(mf_entries)
+ if len(mf_contents) > max_mf_len:
+ raise ValueError("Generated MANIFEST.MF is too large: %d" % (len(mf_contents)))
+
+ sf_contents = ('Signature-Version: 1.0\nSHA1-Digest-Manifest: %s\n'
+ % (b64encode(sha1(mf_contents).digest())))
+ if len(sf_contents) > max_sf_len:
+ raise ValueError("Generated SIGNATURE.SF is too large: %d"
+ % (len(mf_contents)))
+
+ p7 = nss_create_detached_signature(cert, sf_contents, wincx)
+
+ # write the signature, SF, and MF
+ out_zip.writestr("META-INF/A.RSA", p7, zipfile.ZIP_DEFLATED)
+ out_zip.writestr("META-INF/A.SF", sf_contents, zipfile.ZIP_DEFLATED)
+ out_zip.writestr("META-INF/MANIFEST.MF", mf_contents, zipfile.ZIP_DEFLATED)
+ if (ids_json):
+ out_zip.writestr("META-INF/ids.json", ids_json, zipfile.ZIP_DEFLATED)
+
+def main():
+ parser = argparse.ArgumentParser(description='Sign a B2G app.')
+ parser.add_argument('-d', action='store',
+ required=True, help='NSS database directory')
+ parser.add_argument('-f', action='store',
+ type=argparse.FileType('rb'),
+ required=True, help='password file')
+ parser.add_argument('-k', action='store',
+ required=True, help="nickname of signing cert.")
+ parser.add_argument('-i', action='store', type=argparse.FileType('rb'),
+ required=True, help="input JAR file (unsigned)")
+ parser.add_argument('-o', action='store', type=argparse.FileType('wb'),
+ required=True, help="output JAR file (signed)")
+ parser.add_argument('-I', '--ids-file', action='store', type=argparse.FileType('rb'),
+ help="Path to the ids.json file", dest='I')
+ parser.add_argument('-S', '--storeId', action='store',
+ help="Store Id for the package", dest='S')
+ parser.add_argument('-V', '--storeVersion', action='store', type=int,
+ help="Package Version", dest='V')
+ args = parser.parse_args()
+
+ # Sadly nested groups and neccesarily inclusive groups (http://bugs.python.org/issue11588)
+ # are not implemented. Note that this means the automatic help is slighty incorrect
+ if not((not args.I and args.V and args.S) or (args.I and not args.V and not args.S)):
+ raise ValueError("Either -I or -S and -V must be specified")
+
+ if (args.I):
+ ids_contents = args.I.read(max_entry_uncompressed_len+1)
+ else:
+ ids_contents = '''{
+ "id": "%(id)s",
+ "version": %(version)d
+}
+''' % {"id": args.S, "version": args.V}
+ if len(ids_contents) > max_entry_uncompressed_len:
+ raise ValueError("Entry is too large: %s" % (name))
+
+ db_dir = args.d
+ password = args.f.readline().strip()
+ cert_nickname = args.k
+
+ (wincx, cert) = nss_load_cert(db_dir, password, cert_nickname)
+ try:
+ sign_zip(args.i, args.o, cert, wincx, ids_contents)
+ return 0
+ finally:
+ nss_ctypes.CERT_DestroyCertificate(cert)
+ nss_ctypes.NSS_Shutdown()
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/icon-128.png b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/icon-128.png
new file mode 100644
index 000000000..d6fd07a41
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/icon-128.png
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/index.html b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/index.html
new file mode 100644
index 000000000..2acf635e8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/index.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<html lang=en>
+<head><meta charset=utf-8><title>Simple App</title></head>
+<body><p>This is a Simple App.</body>
+</html>
+
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/manifest.webapp b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/manifest.webapp
new file mode 100644
index 000000000..447cd1e71
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_1/manifest.webapp
@@ -0,0 +1,8 @@
+{ "name": "Simple App"
+, "description": "A Simple Open Web App"
+, "launch_path": "tests/dom/apps/tests/signed_app.sjs"
+, "icons": { "128" : "icon-128.png" }
+, "installs_allowed_from": [ "https://marketplace.mozilla.com", "http://mochi.test:8888" ]
+, "version": 1
+, "default_locale": "en-US"
+}
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/icon-128.png b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/icon-128.png
new file mode 100644
index 000000000..d6fd07a41
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/icon-128.png
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/index.html b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/index.html
new file mode 100644
index 000000000..9f2adf57b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/index.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<html lang=en>
+<head><meta charset=utf-8><title>Simple App</title></head>
+<body><p>This is a Simple App.</body>
+</html>
+
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/manifest.webapp b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/manifest.webapp
new file mode 100644
index 000000000..d2393e3c3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin/manifest.webapp
@@ -0,0 +1,10 @@
+{ "name": "Simple App",
+ "description": "A Simple Open Web App",
+ "type": "privileged",
+ "origin": "app://test.origin.privileged.app",
+ "launch_path": "tests/dom/apps/tests/signed_app.sjs",
+ "icons": { "128" : "icon-128.png" },
+ "installs_allowed_from": [ "https://marketplace.mozilla.com", "http://mochi.test:8888" ],
+ "version": 1,
+ "default_locale": "en-US"
+}
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin_toolkit_webapps/index.html b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin_toolkit_webapps/index.html
new file mode 100644
index 000000000..12c6881c2
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin_toolkit_webapps/index.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Test app</title>
+</head>
+<body>
+Test app:
+<iframe src="http://127.0.0.1:8888/chrome/toolkit/webapps/tests/app.sjs?appreq"></iframe>
+</body>
+</html>
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin_toolkit_webapps/manifest.webapp b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin_toolkit_webapps/manifest.webapp
new file mode 100644
index 000000000..55103ca5a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/gentestfiles/unsigned_app_origin_toolkit_webapps/manifest.webapp
@@ -0,0 +1,9 @@
+{
+ "name": "Custom Origin Test",
+ "version": 1,
+ "size": 777,
+ "package_path": "custom_origin.zip",
+ "launch_path": "/index.html",
+ "origin": "app://test.origin.privileged.app",
+ "type": "privileged"
+}
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/privileged-app-test-1.0.zip b/security/manager/ssl/tests/unit/test_signed_apps/privileged-app-test-1.0.zip
new file mode 100644
index 000000000..3a12106c8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/privileged-app-test-1.0.zip
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/test-privileged-app-test-1.0.zip b/security/manager/ssl/tests/unit/test_signed_apps/test-privileged-app-test-1.0.zip
new file mode 100644
index 000000000..ec137ea14
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/test-privileged-app-test-1.0.zip
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/trusted_ca1.der b/security/manager/ssl/tests/unit/test_signed_apps/trusted_ca1.der
new file mode 100644
index 000000000..0200a7f35
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/trusted_ca1.der
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/unknown_issuer_app_1.zip b/security/manager/ssl/tests/unit/test_signed_apps/unknown_issuer_app_1.zip
new file mode 100644
index 000000000..374e45f6f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/unknown_issuer_app_1.zip
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/unsigned_app_1.zip b/security/manager/ssl/tests/unit/test_signed_apps/unsigned_app_1.zip
new file mode 100644
index 000000000..731e050ab
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/unsigned_app_1.zip
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_apps/valid_app_1.zip b/security/manager/ssl/tests/unit/test_signed_apps/valid_app_1.zip
new file mode 100644
index 000000000..74a35a420
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_apps/valid_app_1.zip
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_dir.js b/security/manager/ssl/tests/unit/test_signed_dir.js
new file mode 100644
index 000000000..b07fd2285
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_dir.js
@@ -0,0 +1,201 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that signed extensions extracted/unpacked into a directory work pass
+// verification when non-tampered, and fail verification when tampered via
+// various means.
+
+const { ZipUtils } = Cu.import("resource://gre/modules/ZipUtils.jsm", {});
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+/**
+ * Signed test extension. This is any arbitrary Mozilla signed XPI that
+ * preferably has recently been signed (but note that it actually doesn't
+ * matter, since we ignore expired certificates when checking signing).
+ * @type nsIFile
+ */
+var gSignedXPI =
+ do_get_file("test_signed_dir/lightbeam_for_firefox-1.3.1-fx.xpi", false);
+/**
+ * The directory that the test extension will be extracted to.
+ * @type nsIFile
+ */
+var gTarget = FileUtils.getDir("TmpD", ["test_signed_dir"]);
+gTarget.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+
+/**
+ * Each property below is optional. Defining none of them means "don't tamper".
+ *
+ * @typedef {TamperInstructions}
+ * @type Object
+ * @property {String[][]} copy
+ * Format: [[path,newname], [path2,newname2], ...]
+ * Copy the file located at |path| and name it |newname|.
+ * @property {String[]} delete
+ * List of paths to files to delete.
+ * @property {String[]} corrupt
+ * List of paths to files to corrupt.
+ */
+
+/**
+ * Extracts the signed XPI into a directory, and tampers the files in that
+ * directory if instructed.
+ *
+ * @param {TamperInstructions} tamper
+ * Instructions on whether to tamper any files, and if so, how.
+ * @returns {nsIFile}
+ * The directory where the XPI was extracted to.
+ */
+function prepare(tamper) {
+ ZipUtils.extractFiles(gSignedXPI, gTarget);
+
+ // copy files
+ if (tamper.copy) {
+ tamper.copy.forEach(i => {
+ let f = gTarget.clone();
+ i[0].split("/").forEach(seg => { f.append(seg); });
+ f.copyTo(null, i[1]);
+ });
+ }
+
+ // delete files
+ if (tamper.delete) {
+ tamper.delete.forEach(i => {
+ let f = gTarget.clone();
+ i.split("/").forEach(seg => { f.append(seg); });
+ f.remove(true);
+ });
+ }
+
+ // corrupt files
+ if (tamper.corrupt) {
+ tamper.corrupt.forEach(i => {
+ let f = gTarget.clone();
+ i.split("/").forEach(seg => { f.append(seg); });
+ let s = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY);
+ const str = "Kilroy was here";
+ s.write(str, str.length);
+ s.close();
+ });
+ }
+
+ return gTarget;
+}
+
+function checkResult(expectedRv, dir, resolve) {
+ return function verifySignedDirCallback(rv, aSignerCert) {
+ equal(rv, expectedRv, "Actual and expected return value should match");
+ equal(aSignerCert != null, Components.isSuccessCode(expectedRv),
+ "expecting certificate:");
+ dir.remove(true);
+ resolve();
+ };
+}
+
+function verifyDirAsync(expectedRv, tamper) {
+ let targetDir = prepare(tamper);
+ return new Promise((resolve, reject) => {
+ certdb.verifySignedDirectoryAsync(
+ Ci.nsIX509CertDB.AddonsPublicRoot, targetDir,
+ checkResult(expectedRv, targetDir, resolve));
+ });
+}
+
+//
+// the tests
+//
+add_task(function* testValid() {
+ yield verifyDirAsync(Cr.NS_OK, {} /* no tampering */);
+});
+
+add_task(function* testNoMetaDir() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED,
+ {delete: ["META-INF"]});
+});
+
+add_task(function* testEmptyMetaDir() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED,
+ {delete: ["META-INF/mozilla.rsa",
+ "META-INF/mozilla.sf",
+ "META-INF/manifest.mf"]});
+});
+
+add_task(function* testTwoRSAFiles() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
+ {copy: [["META-INF/mozilla.rsa", "extra.rsa"]]});
+});
+
+add_task(function* testCorruptRSAFile() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
+ {corrupt: ["META-INF/mozilla.rsa"]});
+});
+
+add_task(function* testMissingSFFile() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
+ {delete: ["META-INF/mozilla.sf"]});
+});
+
+add_task(function* testCorruptSFFile() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
+ {corrupt: ["META-INF/mozilla.sf"]});
+});
+
+add_task(function* testExtraInvalidSFFile() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
+ {copy: [["META-INF/mozilla.rsa", "extra.sf"]]});
+});
+
+add_task(function* testExtraValidSFFile() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
+ {copy: [["META-INF/mozilla.sf", "extra.sf"]]});
+});
+
+add_task(function* testMissingManifest() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
+ {delete: ["META-INF/manifest.mf"]});
+});
+
+add_task(function* testCorruptManifest() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID,
+ {corrupt: ["META-INF/manifest.mf"]});
+});
+
+add_task(function* testMissingFile() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING,
+ {delete: ["bootstrap.js"]});
+});
+
+add_task(function* testCorruptFile() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
+ {corrupt: ["bootstrap.js"]});
+});
+
+add_task(function* testExtraFile() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
+ {copy: [["bootstrap.js", "extra"]]});
+});
+
+add_task(function* testMissingFileInDir() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING,
+ {delete: ["lib/ui.js"]});
+});
+
+add_task(function* testCorruptFileInDir() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY,
+ {corrupt: ["lib/ui.js"]});
+});
+
+add_task(function* testExtraFileInDir() {
+ yield verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY,
+ {copy: [["lib/ui.js", "extra"]]});
+});
+
+do_register_cleanup(function() {
+ if (gTarget.exists()) {
+ gTarget.remove(true);
+ }
+});
diff --git a/security/manager/ssl/tests/unit/test_signed_dir/lightbeam_for_firefox-1.3.1-fx.xpi b/security/manager/ssl/tests/unit/test_signed_dir/lightbeam_for_firefox-1.3.1-fx.xpi
new file mode 100644
index 000000000..902b731f3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_dir/lightbeam_for_firefox-1.3.1-fx.xpi
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/README.md b/security/manager/ssl/tests/unit/test_signed_manifest/README.md
new file mode 100644
index 000000000..a442c7052
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/README.md
@@ -0,0 +1,17 @@
+This folder contains the scripts needed to generate signed manifest files
+to verify the Trusted Hosted Apps concept.
+
+Prerequisites:
+
+* NSS 3.4 or higher.
+* Python 2.7 (should work with 2.6 also)
+* Bash
+* OpenSSL
+
+Usage:
+
+Run
+ I) For usage info execute ./create_test_files.sh --help
+
+ II) Upload the signed manifest.webapp and manifest.sig to the
+ application hosting server.
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/create_test_files.sh b/security/manager/ssl/tests/unit/test_signed_manifest/create_test_files.sh
new file mode 100755
index 000000000..cddbe17ec
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/create_test_files.sh
@@ -0,0 +1,181 @@
+#!/bin/bash
+#
+# Mode: shell-script; sh-indentation:2;
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+export BASE_PATH=`dirname $0`
+echo $BASE_PATH
+
+# location of the 'sign_b2g_manifest.py' script
+export SIGN_SCR_PATH=.
+
+DB_PATH=${BASE_PATH}/signingDB
+PASSWORD_FILE=${DB_PATH}/passwordfile
+VALID_MANIFEST_PATH=${BASE_PATH}/testValidSignedManifest
+INVALID_MANIFEST_PATH=${BASE_PATH}/testInvalidSignedManifest
+
+TRUSTED_EE=trusted_ee1
+UNTRUSTED_EE=untrusted_ee1
+TRUSTED_CA=trusted_ca1
+UNTRUSTED_CA=untrusted_ca1
+
+# Print usage info
+usage() {
+ echo
+ echo
+ tput bold
+ echo "NAME"
+ tput sgr0
+ echo " create_test_files.sh - Signing a manifest for Trusted Hosted Apps."
+ echo
+ tput bold
+ echo "SYNOPSIS"
+ tput sgr0
+ echo " create_test_files.sh"
+ echo " create_test_files.sh [--regenerate-test-certs]"
+ echo " create_test_files.sh [--help]"
+ echo
+ tput bold
+ echo "DESCRIPTION"
+ tput sgr0
+ echo " The script signs a manifest for Trusted Hosted Apps if no parameter"
+ echo " is given and if the manifest file and a certificate database directory"
+ echo " is present in the current directory."
+ echo " Two directories ./testValidSignedManifest and ./testInvalidSignedManifest"
+ echo " are generated containing a manifest signature file each, signed with valid"
+ echo " and invalid certificates respectively."
+ echo " If the --regenerate-test-certs parameter is given, a new certificate database"
+ echo " directory is generated before the signing takes place."
+ echo " If the certificate database is not present and the --regenerate-test-certs"
+ echo " parameter is not given the script exits whithout any operations."
+ echo
+ tput bold
+ echo "OPTIONS"
+ echo " --regenerate-test-certs,"
+ tput sgr0
+ echo " Generates a test certificate database and then signs the manifest.webapp"
+ echo " file in the current directory."
+ echo
+ tput bold
+ echo " --help,"
+ tput sgr0
+ echo " Show this usage information."
+ echo
+}
+
+# Function to create a signing database
+# Parameters:
+# $1: Output directory (where the DB will be created)
+# $2: Password file
+createDB() {
+ local db_path=${1}
+ local password_file=${2}
+
+ mkdir -p ${db_path}
+ echo insecurepassword > ${password_file}
+ certutil -d ${db_path} -N -f ${password_file} 2>&1 >/dev/null
+}
+
+# Add a CA cert and a signing cert to the database
+# Arguments:
+# $1: DB directory
+# $2: CA CN (don't include the CN=, just the value)
+# $3: Signing Cert CN (don't include the CN=, just the value)
+# $4: CA short name (don't use spaces!)
+# $5: Signing Cert short name (don't use spaces!)
+# $6: Password file
+addCerts() {
+ local db_path=${1}
+ local password_file=${6}
+
+ org="O=Example Trusted Corporation,L=Mountain View,ST=CA,C=US"
+ ca_subj="CN=${2},${org}"
+ ee_subj="CN=${3},${org}"
+
+ noisefile=/tmp/noise.$$
+ head -c 32 /dev/urandom > ${noisefile}
+
+ ca_responses=/tmp/caresponses.$$
+ ee_responses=/tmp/earesponses
+
+ echo y > ${ca_responses} # Is this a CA?
+ echo >> ${ca_responses} # Accept default path length constraint (no constraint)
+ echo y >> ${ca_responses} # Is this a critical constraint?
+ echo n > ${ee_responses} # Is this a CA?
+ echo >> ${ee_responses} # Accept default path length constraint (no constraint)
+ echo y >> ${ee_responses} # Is this a critical constraint?
+
+ make_cert="certutil -d ${db_path} -f ${password_file} -S -g 2048 -Z SHA256 \
+ -z ${noisefile} -y 3 -2 --extKeyUsage critical,codeSigning"
+ ${make_cert} -v 480 -n ${4} -m 1 -s "${ca_subj}" --keyUsage critical,certSigning \
+ -t ",,CTu" -x < ${ca_responses} 2>&1 >/dev/null
+ ${make_cert} -v 240 -n ${5} -c ${4} -m 2 -s "${ee_subj}" --keyUsage critical,digitalSignature \
+ -t ",,," < ${ee_responses} 2>&1 >/dev/null
+
+ certutil -d ${db_path} -L -n ${4} -r -o ${SIGN_SCR_PATH}/${4}.der
+
+ rm -f ${noisefile} ${ee_responses} ${ca_responses}
+}
+
+# Signs a manifest
+# Parameters:
+# $1: Database directory
+# $2: Unsigned manifest file path
+# $3: Signed manifest file path
+# $4: Nickname of the signing certificate
+# $5: Password file
+signManifest() {
+ local db_path=${1}
+ local password_file=${5}
+
+ python ${BASE_PATH}/${SIGN_SCR_PATH}/sign_b2g_manifest.py -d ${db_path} \
+ -f ${password_file} -k ${4} -i ${2} -o ${3}
+}
+
+# Generate the necessary files to be used for the signing
+generate_files() {
+ # First create a new couple of signing DBs
+ rm -rf ${DB_PATH} ${VALID_MANIFEST_PATH} ${INVALID_MANIFEST_PATH}
+ createDB ${DB_PATH} ${PASSWORD_FILE}
+ addCerts ${DB_PATH} "Trusted Valid CA" "Trusted Corp Cert" ${TRUSTED_CA} ${TRUSTED_EE} ${PASSWORD_FILE}
+ addCerts ${DB_PATH} "Trusted Invalid CA" "Trusted Invalid Cert" ${UNTRUSTED_CA} ${UNTRUSTED_EE} ${PASSWORD_FILE}
+}
+
+#Start of execution
+if [ ${1} ] && [ "${1}" == '--regenerate-test-certs' ]; then
+ generate_files
+elif [ "${1}" == '--help' ]; then
+ usage
+ exit 1
+else
+ if [ -d ${DB_PATH} ]; then
+ rm -rf ${VALID_MANIFEST_PATH} ${INVALID_MANIFEST_PATH}
+ else
+ echo "Error! The directory ${DB_PATH} does not exist!"
+ echo "New certificate database must be created!"
+ usage $0
+ exit 1
+ fi
+fi
+
+# Create all the test manifests
+mkdir -p ${VALID_MANIFEST_PATH}
+mkdir -p ${INVALID_MANIFEST_PATH}
+
+CURDIR=`pwd`
+cd $CURDIR
+
+# Sign a manifest file with a known issuer
+signManifest ${DB_PATH} ${BASE_PATH}/manifest.webapp \
+ ${VALID_MANIFEST_PATH}/manifest.sig \
+ ${TRUSTED_EE} ${PASSWORD_FILE}
+
+# Sign a manifest file with a unknown issuer
+signManifest ${DB_PATH} ${BASE_PATH}/manifest.webapp \
+ ${INVALID_MANIFEST_PATH}/manifest.sig \
+ ${UNTRUSTED_EE} ${PASSWORD_FILE}
+
+echo "Done!"
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/manifest.webapp b/security/manager/ssl/tests/unit/test_signed_manifest/manifest.webapp
new file mode 100644
index 000000000..ad477719b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/manifest.webapp
@@ -0,0 +1,10 @@
+{ "name": "Trusted App Example",
+ "description": "A Manifest for a Trusted Hosted Application",
+ "type": "trusted",
+ "launch_path": "/index.html",
+ "icons": { "128" : "icon-128.png" },
+ "version": 1,
+ "csp" : "script-src https://www.example.com; style-src https://www.example.com",
+ "permissions": { "device-storage:videos":{ "access": "readonly" }, "device-storage:pictures":{ "access": "readwrite" } },
+ "default_locale": "en-US"
+}
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/nss_ctypes.py b/security/manager/ssl/tests/unit/test_signed_manifest/nss_ctypes.py
new file mode 100644
index 000000000..a0c50b1ed
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/nss_ctypes.py
@@ -0,0 +1,136 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from ctypes import *
+import os
+import sys
+
+if sys.platform == 'darwin':
+ libprefix = "lib"
+ libsuffix = ".dylib"
+elif os.name == 'posix':
+ libprefix = "lib"
+ libsuffix = ".so"
+else: # assume windows
+ libprefix = ""
+ libsuffix = ".dll"
+
+plc = cdll.LoadLibrary(libprefix + "plc4" + libsuffix)
+nspr = cdll.LoadLibrary(libprefix + "nspr4" + libsuffix)
+nss = cdll.LoadLibrary(libprefix + "nss3" + libsuffix)
+smime = cdll.LoadLibrary(libprefix + "smime3" + libsuffix)
+
+nspr.PR_GetError.argtypes = []
+nspr.PR_GetError.restype = c_int32
+nspr.PR_ErrorToName.argtypes = [c_int32]
+nspr.PR_ErrorToName.restype = c_char_p
+
+def raise_if_not_SECSuccess(rv):
+ SECSuccess = 0
+ if (rv != SECSuccess):
+ raise ValueError(nspr.PR_ErrorToName(nspr.PR_GetError()))
+
+def raise_if_NULL(p):
+ if not p:
+ raise ValueError(nspr.PR_ErrorToName(nspr.PR_GetError()))
+ return p
+
+PRBool = c_int
+SECStatus = c_int
+
+# from secoidt.h
+SEC_OID_SHA1 = 4
+
+# from certt.h
+certUsageObjectSigner = 6
+
+class SECItem(Structure):
+ _fields_ = [("type", c_int),
+ ("data", c_char_p),
+ ("len", c_uint)]
+
+nss.NSS_Init.argtypes = [c_char_p]
+nss.NSS_Init.restype = SECStatus
+def NSS_Init(db_dir):
+ nss.NSS_Init.argtypes = [c_char_p]
+ nss.NSS_Init.restype = SECStatus
+ raise_if_not_SECSuccess(nss.NSS_Init(db_dir))
+
+nss.NSS_Shutdown.argtypes = []
+nss.NSS_Shutdown.restype = SECStatus
+def NSS_Shutdown():
+ raise_if_not_SECSuccess(nss.NSS_Shutdown())
+
+PK11PasswordFunc = CFUNCTYPE(c_char_p, c_void_p, PRBool, c_char_p)
+
+# pass the result of this as the wincx parameter when a wincx is required
+nss.PK11_SetPasswordFunc.argtypes = [PK11PasswordFunc]
+nss.PK11_SetPasswordFunc.restype = None
+
+# Set the return type as *void so Python doesn't touch it
+plc.PL_strdup.argtypes = [c_char_p]
+plc.PL_strdup.restype = c_void_p
+def SetPasswordContext(password):
+ def callback(slot, retry, arg):
+ return plc.PL_strdup(password)
+ wincx = PK11PasswordFunc(callback)
+ nss.PK11_SetPasswordFunc(wincx)
+ return wincx
+
+nss.CERT_GetDefaultCertDB.argtypes = []
+nss.CERT_GetDefaultCertDB.restype = c_void_p
+def CERT_GetDefaultCertDB():
+ return raise_if_NULL(nss.CERT_GetDefaultCertDB())
+
+nss.PK11_FindCertFromNickname.argtypes = [c_char_p, c_void_p]
+nss.PK11_FindCertFromNickname.restype = c_void_p
+def PK11_FindCertFromNickname(nickname, wincx):
+ return raise_if_NULL(nss.PK11_FindCertFromNickname(nickname, wincx))
+
+nss.CERT_DestroyCertificate.argtypes = [c_void_p]
+nss.CERT_DestroyCertificate.restype = None
+def CERT_DestroyCertificate(cert):
+ nss.CERT_DestroyCertificate(cert)
+
+smime.SEC_PKCS7CreateSignedData.argtypes = [c_void_p, c_int, c_void_p,
+ c_int, c_void_p,
+ c_void_p, c_void_p]
+smime.SEC_PKCS7CreateSignedData.restype = c_void_p
+def SEC_PKCS7CreateSignedData(cert, certusage, certdb, digestalg, digest, wincx):
+ item = SECItem(0, c_char_p(digest), len(digest))
+ return raise_if_NULL(smime.SEC_PKCS7CreateSignedData(cert, certusage, certdb,
+ digestalg,
+ pointer(item),
+ None, wincx))
+
+smime.SEC_PKCS7AddSigningTime.argtypes = [c_void_p]
+smime.SEC_PKCS7AddSigningTime.restype = SECStatus
+def SEC_PKCS7AddSigningTime(p7):
+ raise_if_not_SECSuccess(smime.SEC_PKCS7AddSigningTime(p7))
+
+smime.SEC_PKCS7IncludeCertChain.argtypes = [c_void_p, c_void_p]
+smime.SEC_PKCS7IncludeCertChain.restype = SECStatus
+def SEC_PKCS7IncludeCertChain(p7, wincx):
+ raise_if_not_SECSuccess(smime.SEC_PKCS7IncludeCertChain(p7, wincx))
+
+SEC_PKCS7EncoderOutputCallback = CFUNCTYPE(None, c_void_p, c_void_p, c_long)
+smime.SEC_PKCS7Encode.argtypes = [c_void_p, SEC_PKCS7EncoderOutputCallback,
+ c_void_p, c_void_p, c_void_p, c_void_p]
+smime.SEC_PKCS7Encode.restype = SECStatus
+def SEC_PKCS7Encode(p7, bulkkey, wincx):
+ outputChunks = []
+ def callback(chunks, data, len):
+ outputChunks.append(string_at(data, len))
+ callbackWrapper = SEC_PKCS7EncoderOutputCallback(callback)
+ raise_if_not_SECSuccess(smime.SEC_PKCS7Encode(p7, callbackWrapper,
+ None, None, None, wincx))
+ return "".join(outputChunks)
+
+smime.SEC_PKCS7DestroyContentInfo.argtypes = [c_void_p]
+smime.SEC_PKCS7DestroyContentInfo.restype = None
+def SEC_PKCS7DestroyContentInfo(p7):
+ smime.SEC_PKCS7DestroyContentInfo(p7)
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/sign_b2g_manifest.py b/security/manager/ssl/tests/unit/test_signed_manifest/sign_b2g_manifest.py
new file mode 100644
index 000000000..a7f060481
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/sign_b2g_manifest.py
@@ -0,0 +1,76 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import argparse
+from base64 import b64encode
+from hashlib import sha1
+import sys
+import ctypes
+import nss_ctypes
+
+def nss_create_detached_signature(cert, dataToSign, wincx):
+ certdb = nss_ctypes.CERT_GetDefaultCertDB()
+ p7 = nss_ctypes.SEC_PKCS7CreateSignedData(cert,
+ nss_ctypes.certUsageObjectSigner,
+ certdb,
+ nss_ctypes.SEC_OID_SHA1,
+ sha1(dataToSign).digest(),
+ wincx)
+ try:
+ nss_ctypes.SEC_PKCS7AddSigningTime(p7)
+ nss_ctypes.SEC_PKCS7IncludeCertChain(p7, wincx)
+ return nss_ctypes.SEC_PKCS7Encode(p7, None, wincx)
+ finally:
+ nss_ctypes.SEC_PKCS7DestroyContentInfo(p7)
+
+# Sign a manifest file
+def sign_file(in_file, out_file, cert, wincx):
+ contents = in_file.read()
+ in_file.close()
+
+ # generate base64 encoded string of the sha1 digest of the input file
+ in_file_hash = b64encode(sha1(contents).digest())
+
+ # sign the base64 encoded string with the given certificate
+ in_file_signature = nss_create_detached_signature(cert, in_file_hash, wincx)
+
+ # write the content of the output file
+ out_file.write(in_file_signature)
+ out_file.close()
+
+def main():
+ parser = argparse.ArgumentParser(description='Sign a B2G app manifest.')
+ parser.add_argument('-d', action='store',
+ required=True, help='NSS database directory')
+ parser.add_argument('-f', action='store',
+ type=argparse.FileType('rb'),
+ required=True, help='password file')
+ parser.add_argument('-k', action='store',
+ required=True, help="nickname of signing cert.")
+ parser.add_argument('-i', action='store', type=argparse.FileType('rb'),
+ required=True, help="input manifest file (unsigned)")
+ parser.add_argument('-o', action='store', type=argparse.FileType('wb'),
+ required=True, help="output manifest file (signed)")
+ args = parser.parse_args()
+
+ db_dir = args.d
+ password = args.f.readline().strip()
+ cert_nickname = args.k
+ cert = None
+
+ try:
+ nss_ctypes.NSS_Init(db_dir)
+ wincx = nss_ctypes.SetPasswordContext(password)
+ cert = nss_ctypes.PK11_FindCertFromNickname(cert_nickname, wincx)
+ sign_file(args.i, args.o, cert, wincx)
+ return 0
+ finally:
+ nss_ctypes.CERT_DestroyCertificate(cert)
+ nss_ctypes.NSS_Shutdown()
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/testInvalidSignedManifest/manifest.sig b/security/manager/ssl/tests/unit/test_signed_manifest/testInvalidSignedManifest/manifest.sig
new file mode 100644
index 000000000..d5eee196c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/testInvalidSignedManifest/manifest.sig
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/testValidSignedManifest/manifest.sig b/security/manager/ssl/tests/unit/test_signed_manifest/testValidSignedManifest/manifest.sig
new file mode 100644
index 000000000..996226351
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/testValidSignedManifest/manifest.sig
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_signed_manifest/trusted_ca1.der b/security/manager/ssl/tests/unit/test_signed_manifest/trusted_ca1.der
new file mode 100644
index 000000000..bf05308cc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_signed_manifest/trusted_ca1.der
Binary files differ
diff --git a/security/manager/ssl/tests/unit/test_sss_eviction.js b/security/manager/ssl/tests/unit/test_sss_eviction.js
new file mode 100644
index 000000000..0ac8983f6
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sss_eviction.js
@@ -0,0 +1,85 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to check that a frequently visited site
+// will not be evicted over an infrequently visited site.
+
+var gSSService = null;
+var gProfileDir = null;
+
+function do_state_written(aSubject, aTopic, aData) {
+ if (aData == PRELOAD_STATE_FILE_NAME) {
+ return;
+ }
+
+ equal(aData, SSS_STATE_FILE_NAME);
+
+ let stateFile = gProfileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ ok(stateFile.exists());
+ let stateFileContents = readFile(stateFile);
+ // the last part is removed because it's the empty string after the final \n
+ let lines = stateFileContents.split('\n').slice(0, -1);
+ // We can receive multiple data-storage-written events. In particular, we
+ // may receive one where DataStorage wrote out data before we were done
+ // processing all of our headers. In this case, the data may not be
+ // as we expect. We only care about the final one being correct, however,
+ // so we return and wait for the next event if things aren't as we expect.
+ // There should be 1024 entries.
+ if (lines.length != 1024) {
+ return;
+ }
+
+ let foundLegitSite = false;
+ for (let line of lines) {
+ if (line.startsWith("frequentlyused.example.com:HSTS")) {
+ foundLegitSite = true;
+ break;
+ }
+ }
+
+ ok(foundLegitSite);
+ do_test_finished();
+}
+
+function do_state_read(aSubject, aTopic, aData) {
+ if (aData == PRELOAD_STATE_FILE_NAME) {
+ return;
+ }
+
+ equal(aData, SSS_STATE_FILE_NAME);
+
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "frequentlyused.example.com", 0));
+ let sslStatus = new FakeSSLStatus();
+ for (let i = 0; i < 2000; i++) {
+ let uri = Services.io.newURI("http://bad" + i + ".example.com", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1000", sslStatus, 0);
+ }
+ do_test_pending();
+ Services.obs.addObserver(do_state_written, "data-storage-written", false);
+ do_test_finished();
+}
+
+function run_test() {
+ Services.prefs.setIntPref("test.datastorage.write_timer_ms", 100);
+ gProfileDir = do_get_profile();
+ let stateFile = gProfileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ // Assuming we're working with a clean slate, the file shouldn't exist
+ // until we create it.
+ ok(!stateFile.exists());
+ let outputStream = FileUtils.openFileOutputStream(stateFile);
+ let now = (new Date()).getTime();
+ let line = "frequentlyused.example.com:HSTS\t4\t0\t" + (now + 100000) + ",1,0\n";
+ outputStream.write(line, line.length);
+ outputStream.close();
+ Services.obs.addObserver(do_state_read, "data-storage-ready", false);
+ do_test_pending();
+ gSSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ notEqual(gSSService, null);
+}
diff --git a/security/manager/ssl/tests/unit/test_sss_readstate.js b/security/manager/ssl/tests/unit/test_sss_readstate.js
new file mode 100644
index 000000000..8b7e8cbb5
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sss_readstate.js
@@ -0,0 +1,82 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to create a site security service state file
+// and see that the site security service reads it properly.
+
+function writeLine(aLine, aOutputStream) {
+ aOutputStream.write(aLine, aLine.length);
+}
+
+var gSSService = null;
+
+function checkStateRead(aSubject, aTopic, aData) {
+ if (aData == PRELOAD_STATE_FILE_NAME) {
+ return;
+ }
+
+ equal(aData, SSS_STATE_FILE_NAME);
+
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "expired.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "notexpired.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.includesubdomains.preloaded.test", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "incsubdomain.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.incsubdomain.example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains2.preloaded.test", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.includesubdomains2.preloaded.test", 0));
+
+ // Clearing the data should make everything go back to default.
+ gSSService.clearAll();
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "expired.example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "notexpired.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.includesubdomains.preloaded.test", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "incsubdomain.example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.incsubdomain.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains2.preloaded.test", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.includesubdomains2.preloaded.test", 0));
+ do_test_finished();
+}
+
+function run_test() {
+ let profileDir = do_get_profile();
+ let stateFile = profileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ // Assuming we're working with a clean slate, the file shouldn't exist
+ // until we create it.
+ ok(!stateFile.exists());
+ let outputStream = FileUtils.openFileOutputStream(stateFile);
+ let now = (new Date()).getTime();
+ writeLine("expired.example.com:HSTS\t0\t0\t" + (now - 100000) + ",1,0\n", outputStream);
+ writeLine("notexpired.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
+ // This overrides an entry on the preload list.
+ writeLine("includesubdomains.preloaded.test:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
+ writeLine("incsubdomain.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,1\n", outputStream);
+ // This overrides an entry on the preload list.
+ writeLine("includesubdomains2.preloaded.test:HSTS\t0\t0\t0,2,0\n", outputStream);
+ outputStream.close();
+ Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
+ do_test_pending();
+ gSSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ notEqual(gSSService, null);
+}
diff --git a/security/manager/ssl/tests/unit/test_sss_readstate_child.js b/security/manager/ssl/tests/unit/test_sss_readstate_child.js
new file mode 100644
index 000000000..80f00c31a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sss_readstate_child.js
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to create a site security service state file
+// and see that the site security service reads it properly. We also verify
+// that state changes are reflected in the child process.
+
+function writeLine(aLine, aOutputStream) {
+ aOutputStream.write(aLine, aLine.length);
+}
+
+function start_test_in_child() {
+ run_test_in_child("sss_readstate_child_worker.js");
+ do_test_finished();
+}
+
+function run_test() {
+ let profileDir = do_get_profile();
+ let stateFile = profileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ // Assuming we're working with a clean slate, the file shouldn't exist
+ // until we create it.
+ ok(!stateFile.exists());
+ let outputStream = FileUtils.openFileOutputStream(stateFile);
+ let now = (new Date()).getTime();
+ writeLine("expired.example.com:HSTS\t0\t0\t" + (now - 100000) + ",1,0\n", outputStream);
+ writeLine("notexpired.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
+ // This overrides an entry on the preload list.
+ writeLine("includesubdomains.preloaded.test:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
+ writeLine("incsubdomain.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,1\n", outputStream);
+ // This overrides an entry on the preload list.
+ writeLine("includesubdomains2.preloaded.test:HSTS\t0\t0\t0,2,0\n", outputStream);
+ outputStream.close();
+ Services.obs.addObserver(start_test_in_child, "data-storage-ready", false);
+ do_test_pending();
+ let SSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ notEqual(SSService, null);
+}
diff --git a/security/manager/ssl/tests/unit/test_sss_readstate_empty.js b/security/manager/ssl/tests/unit/test_sss_readstate_empty.js
new file mode 100644
index 000000000..c4605c0af
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sss_readstate_empty.js
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to create an empty site security service state
+// file and see that the site security service doesn't fail when reading it.
+
+var gSSService = null;
+
+function checkStateRead(aSubject, aTopic, aData) {
+ // nonexistent.example.com should never be an HSTS host
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "nonexistent.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ // notexpired.example.com is an HSTS host in a different test - we
+ // want to make sure that test hasn't interfered with this one.
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "notexpired.example.com", 0));
+ do_test_finished();
+}
+
+function run_test() {
+ let profileDir = do_get_profile();
+ let stateFile = profileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ // Assuming we're working with a clean slate, the file shouldn't exist
+ // until we create it.
+ ok(!stateFile.exists());
+ stateFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0x1a4); // 0x1a4 == 0o644
+ ok(stateFile.exists());
+ // Initialize nsISiteSecurityService after do_get_profile() so it
+ // can read the state file.
+ Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
+ do_test_pending();
+ gSSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ notEqual(gSSService, null);
+}
diff --git a/security/manager/ssl/tests/unit/test_sss_readstate_garbage.js b/security/manager/ssl/tests/unit/test_sss_readstate_garbage.js
new file mode 100644
index 000000000..d4165f7f4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sss_readstate_garbage.js
@@ -0,0 +1,56 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to create a mostly bogus site security service
+// state file and see that the site security service handles it properly.
+
+function writeLine(aLine, aOutputStream) {
+ aOutputStream.write(aLine, aLine.length);
+}
+
+var gSSService = null;
+
+function checkStateRead(aSubject, aTopic, aData) {
+ if (aData == PRELOAD_STATE_FILE_NAME) {
+ return;
+ }
+
+ equal(aData, SSS_STATE_FILE_NAME);
+
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example1.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example2.example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example3.example.com", 0));
+ do_test_finished();
+}
+
+function run_test() {
+ let profileDir = do_get_profile();
+ let stateFile = profileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ // Assuming we're working with a clean slate, the file shouldn't exist
+ // until we create it.
+ ok(!stateFile.exists());
+ let outputStream = FileUtils.openFileOutputStream(stateFile);
+ let now = (new Date()).getTime();
+ writeLine("example1.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
+ writeLine("I'm a lumberjack and I'm okay; I work all night and I sleep all day!\n", outputStream);
+ writeLine("This is a totally bogus entry\t\n", outputStream);
+ writeLine("0\t0\t0\t0\t\n", outputStream);
+ writeLine("\t\t\t\t\t\t\t\n", outputStream);
+ writeLine("example.com:HSTS\t\t\t\t\t\t\t\n", outputStream);
+ writeLine("example3.example.com:HSTS\t0\t\t\t\t\t\t\n", outputStream);
+ writeLine("example2.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
+ outputStream.close();
+ Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
+ do_test_pending();
+ gSSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ notEqual(gSSService, null);
+}
diff --git a/security/manager/ssl/tests/unit/test_sss_readstate_huge.js b/security/manager/ssl/tests/unit/test_sss_readstate_huge.js
new file mode 100644
index 000000000..eec93b6f4
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sss_readstate_huge.js
@@ -0,0 +1,60 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to create a site security service state file
+// that is too large and see that the site security service reads it properly
+// (this means discarding all entries after the 1024th).
+
+function writeLine(aLine, aOutputStream) {
+ aOutputStream.write(aLine, aLine.length);
+}
+
+var gSSService = null;
+
+function checkStateRead(aSubject, aTopic, aData) {
+ if (aData == PRELOAD_STATE_FILE_NAME) {
+ return;
+ }
+
+ equal(aData, SSS_STATE_FILE_NAME);
+
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example0.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example423.example.com", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example1023.example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example1024.example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example1025.example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example9000.example.com", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example99999.example.com", 0));
+ do_test_finished();
+}
+
+function run_test() {
+ let profileDir = do_get_profile();
+ let stateFile = profileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ // Assuming we're working with a clean slate, the file shouldn't exist
+ // until we create it.
+ ok(!stateFile.exists());
+ let outputStream = FileUtils.openFileOutputStream(stateFile);
+ let now = (new Date()).getTime();
+ for (let i = 0; i < 10000; i++) {
+ // The 0s will all get squashed down into one 0 when they are read.
+ // This is just to make the file size large (>2MB).
+ writeLine("example" + i + ".example.com:HSTS\t0000000000000000000000000000000000000000000000000\t00000000000000000000000000000000000000\t" + (now + 100000) + ",1,0000000000000000000000000000000000000000000000000000000000000000000000000\n", outputStream);
+ }
+ outputStream.close();
+ Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
+ do_test_pending();
+ gSSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ notEqual(gSSService, null);
+}
diff --git a/security/manager/ssl/tests/unit/test_sss_savestate.js b/security/manager/ssl/tests/unit/test_sss_savestate.js
new file mode 100644
index 000000000..a4d8b5297
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sss_savestate.js
@@ -0,0 +1,128 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// The purpose of this test is to see that the site security service properly
+// writes its state file.
+
+const EXPECTED_ENTRIES = 6;
+const EXPECTED_HSTS_COLUMNS = 3;
+const EXPECTED_HPKP_COLUMNS = 4;
+var gProfileDir = null;
+
+const NON_ISSUED_KEY_HASH = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+
+// For reference, the format of the state file is a list of:
+// <domain name> <expiration time in milliseconds>,<sts status>,<includeSubdomains>
+// separated by newlines ('\n')
+
+function checkStateWritten(aSubject, aTopic, aData) {
+ if (aData == PRELOAD_STATE_FILE_NAME) {
+ return;
+ }
+
+ equal(aData, SSS_STATE_FILE_NAME);
+
+ let stateFile = gProfileDir.clone();
+ stateFile.append(SSS_STATE_FILE_NAME);
+ ok(stateFile.exists());
+ let stateFileContents = readFile(stateFile);
+ // the last line is removed because it's just a trailing newline
+ let lines = stateFileContents.split('\n').slice(0, -1);
+ equal(lines.length, EXPECTED_ENTRIES);
+ let sites = {}; // a map of domain name -> [the entry in the state file]
+ for (let line of lines) {
+ let parts = line.split('\t');
+ let host = parts[0];
+ let score = parts[1];
+ let lastAccessed = parts[2];
+ let entry = parts[3].split(',');
+ let expectedColumns = EXPECTED_HSTS_COLUMNS;
+ if (host.indexOf("HPKP") != -1) {
+ expectedColumns = EXPECTED_HPKP_COLUMNS;
+ }
+ equal(entry.length, expectedColumns);
+ sites[host] = entry;
+ }
+
+ // We can receive multiple data-storage-written events. In particular, we
+ // may receive one where DataStorage wrote out data before we were done
+ // processing all of our headers. In this case, the data may not be
+ // as we expect. We only care about the final one being correct, however,
+ // so we return and wait for the next event if things aren't as we expect.
+ // sites[url][1] corresponds to SecurityPropertySet (if 1) and
+ // SecurityPropertyUnset (if 0)
+ // sites[url][2] corresponds to includeSubdomains
+ if (sites["includesubdomains.preloaded.test:HSTS"][1] != 1) {
+ return;
+ }
+ if (sites["includesubdomains.preloaded.test:HSTS"][2] != 0) {
+ return;
+ }
+ if (sites["a.example.com:HSTS"][1] != 1) {
+ return;
+ }
+ if (sites["a.example.com:HSTS"][2] != 1) {
+ return;
+ }
+ if (sites["b.example.com:HSTS"][1] != 1) {
+ return;
+ }
+ if (sites["b.example.com:HSTS"][2] != 0) {
+ return;
+ }
+ if (sites["c.c.example.com:HSTS"][1] != 1) {
+ return;
+ }
+ if (sites["c.c.example.com:HSTS"][2] != 1) {
+ return;
+ }
+ if (sites["d.example.com:HSTS"][1] != 1) {
+ return;
+ }
+ if (sites["d.example.com:HSTS"][2] != 0) {
+ return;
+ }
+ if (sites["dynamic-pin.example.com:HPKP"][1] != 1) {
+ return;
+ }
+ if (sites["dynamic-pin.example.com:HPKP"][2] != 1) {
+ return;
+ }
+ equal(sites["dynamic-pin.example.com:HPKP"][3], NON_ISSUED_KEY_HASH);
+
+ do_test_finished();
+}
+
+function run_test() {
+ Services.prefs.setIntPref("test.datastorage.write_timer_ms", 100);
+ gProfileDir = do_get_profile();
+ let SSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ // Put an HPKP entry
+ SSService.setKeyPins("dynamic-pin.example.com", true,
+ new Date().getTime() + 1000000, 1,
+ [NON_ISSUED_KEY_HASH]);
+
+ let uris = [ Services.io.newURI("http://includesubdomains.preloaded.test", null, null),
+ Services.io.newURI("http://a.example.com", null, null),
+ Services.io.newURI("http://b.example.com", null, null),
+ Services.io.newURI("http://c.c.example.com", null, null),
+ Services.io.newURI("http://d.example.com", null, null) ];
+
+ for (let i = 0; i < 1000; i++) {
+ let uriIndex = i % uris.length;
+ // vary max-age
+ let maxAge = "max-age=" + (i * 1000);
+ // alternate setting includeSubdomains
+ let includeSubdomains = (i % 2 == 0 ? "; includeSubdomains" : "");
+ let sslStatus = new FakeSSLStatus();
+ SSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS,
+ uris[uriIndex], maxAge + includeSubdomains,
+ sslStatus, 0);
+ }
+
+ do_test_pending();
+ Services.obs.addObserver(checkStateWritten, "data-storage-written", false);
+}
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign.js b/security/manager/ssl/tests/unit/test_startcom_wosign.js
new file mode 100644
index 000000000..4ba89ca73
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign.js
@@ -0,0 +1,43 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests handling of certificates issued by StartCom and WoSign. If such
+// certificates have a notBefore before 21 October 2016, they are handled
+// normally. Otherwise, they are treated as revoked.
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+function loadCertWithTrust(certName, trustString) {
+ addCertFromFile(certdb, "test_startcom_wosign/" + certName + ".pem", trustString);
+}
+
+function certFromFile(certName) {
+ return constructCertFromFile("test_startcom_wosign/" + certName + ".pem");
+}
+
+function checkEndEntity(cert, expectedResult) {
+ // (new Date("2016-11-01")).getTime() / 1000
+ const VALIDATION_TIME = 1477958400;
+ checkCertErrorGenericAtTime(certdb, cert, expectedResult,
+ certificateUsageSSLServer, VALIDATION_TIME);
+}
+
+loadCertWithTrust("ca", "CTu,,");
+// This is not a real StartCom CA - it merely has the same distinguished name as
+// one (namely "/C=IL/O=StartCom Ltd./CN=StartCom Certification Authority G2",
+// encoded with PrintableStrings). By checking for specific DNs, we can enforce
+// the date-based policy in a way that is testable.
+loadCertWithTrust("StartComCA", ",,");
+checkEndEntity(certFromFile("StartCom-before-cutoff"), PRErrorCodeSuccess);
+checkEndEntity(certFromFile("StartCom-after-cutoff"), SEC_ERROR_REVOKED_CERTIFICATE);
+
+// Similarly, this is not a real WoSign CA. It has the same distinguished name
+// as "/C=CN/O=WoSign CA Limited/CN=Certification Authority of WoSign", encoded
+// with PrintableStrings).
+loadCertWithTrust("WoSignCA", ",,");
+checkEndEntity(certFromFile("WoSign-before-cutoff"), PRErrorCodeSuccess);
+checkEndEntity(certFromFile("WoSign-after-cutoff"), SEC_ERROR_REVOKED_CERTIFICATE);
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-after-cutoff.pem b/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-after-cutoff.pem
new file mode 100644
index 000000000..a3914b33f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-after-cutoff.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGzCCAgWgAwIBAgIUQcnJ38esL8x6sizuR5KC5SFcqMUwCwYJKoZIhvcNAQEL
+MFMxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSwwKgYDVQQD
+EyNTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBHMjAiGA8yMDE2MTAy
+MjAwMDAwMFoYDzIwMTcxMDIyMDAwMDAwWjAgMR4wHAYDVQQDDBVTdGFydENvbS1h
+ZnRlci1jdXRvZmYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGo
+RI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9a
+dWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6t
+aRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8n
+FthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kX
+Dqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/py
+UcQx1QOs2hgKNe2NAgMBAAGjGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMAsG
+CSqGSIb3DQEBCwOCAQEAhvpbb5H8Cokd2S8g/tYMutgqnA7UXrYMiIMTC4AwLua3
+FCbqpHVU8oyAuL2uQ+RIPGIRBgVKgqlz1zrvB3HLX1DJ1yiUUbgDcCfGeLTQ1dOj
+ZEHKYgRxmb6OQyMjaHRvXSlPpuKoA2eymj7IaCyRwX3qxVX1vt7UpVEInpwVusNQ
+L2UH4ni0W/GfoO2z8DgMWv2fJAWaFJlVQgalhEq7qZ0B1vSMsx/exwjsqQiTCdGL
+y46y/wo/sUklpQyX7U3/FsYGAEw27LoJ+pf88Stk5VuTu+Ip5KnbWklRlKDxHoo1
+5VriR2NfFVfqtvapGNougn7t2xEuISVtSp2CKVBuUA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-after-cutoff.pem.certspec b/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-after-cutoff.pem.certspec
new file mode 100644
index 000000000..9f0fe22fc
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-after-cutoff.pem.certspec
@@ -0,0 +1,4 @@
+issuer:printableString/C=IL/O=StartCom Ltd./CN=StartCom Certification Authority G2
+subject:StartCom-after-cutoff
+validity:20161022-20171022
+extension:subjectAlternativeName:example.com
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-before-cutoff.pem b/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-before-cutoff.pem
new file mode 100644
index 000000000..a219e745f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-before-cutoff.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAgagAwIBAgIUWZ9YRoup7gVY1EokoIfmnmi93gYwCwYJKoZIhvcNAQEL
+MFMxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSwwKgYDVQQD
+EyNTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBHMjAiGA8yMDE1MTAy
+MjAwMDAwMFoYDzIwMTcxMDIyMDAwMDAwWjAhMR8wHQYDVQQDDBZTdGFydENvbS1i
+ZWZvcmUtY3V0b2ZmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR
+qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv
+WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+
+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv
+JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5
+Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6
+clHEMdUDrNoYCjXtjQIDAQABoxowGDAWBgNVHREEDzANggtleGFtcGxlLmNvbTAL
+BgkqhkiG9w0BAQsDggEBAFhgX9UQSu/Bde3O4EDhIrl413weRbOsy2qU8UrRMrm5
+3im2TGF2/75rlu3vE3dHQaSqPRiZ1HK1FvHt6faohJKGfbN2AFABIpPleh2evQC8
+wXjOcrURnz0MrK5c9v6gNjUq63n9daeIDLby7CTnKPuVGa2kpOWFI8gBGnOj3a96
+oBO9wfi8fVpKRxK+BoCfwUmF4HzlyQy7hMDcHUuf0rlSch6NKVeUpHBP4XlmnITO
+KC7TCIbM2cGSqsSr8rF5AdeCSf2ZukAHQUwO7W/Bs8OIaqurIjwEnM3E/wqUk/MW
+VzySem5LqHnz4yfeOKR9+DQImKZ0pAWn6cIuumMDP2M=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-before-cutoff.pem.certspec b/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-before-cutoff.pem.certspec
new file mode 100644
index 000000000..b7fbd4954
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/StartCom-before-cutoff.pem.certspec
@@ -0,0 +1,4 @@
+issuer:printableString/C=IL/O=StartCom Ltd./CN=StartCom Certification Authority G2
+subject:StartCom-before-cutoff
+validity:20151022-20171022
+extension:subjectAlternativeName:example.com
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/StartComCA.pem b/security/manager/ssl/tests/unit/test_startcom_wosign/StartComCA.pem
new file mode 100644
index 000000000..720c59d4f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/StartComCA.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCzCCAfWgAwIBAgIUP4zQ8t+wfQSkTf7d5CJUa6DCaDEwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMFMxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSwwKgYD
+VQQDEyNTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBHMjCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
+SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYL
+K7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwc
+bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
+JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMd
+MBswCwYDVR0PBAQDAgEGMAwGA1UdEwQFMAMBAf8wCwYJKoZIhvcNAQELA4IBAQBJ
+c1GQxMzouK7DnQ1vgrw5LH92x3navGhO7gJWN2dca1QXnzXG3c/Yh3aqbmNI0fu+
+4PXBEKWP2i+Idgslmxi0O/I9VURHGfEo5JzLEbK6Bj/hU1VIrHj64HZ4F0XcL/K8
+kD8kqLWyuoD/i1mjTp4oGNsprv6M/TsU5nv5FszWvtv0CaGmrjNjOvYEUBo5xies
+ETPbmmPKeVwa1Npk/9uBK8Zyczj0s3rRBaOa3NhzhKuL+6x5sKzEO6uxKgEf1GYB
+KFyugaqLXYsHRTI47gwtRtVHkmriZdxLJJV+8C9OkINUf7fVZNTrdcFncrAQrxDS
+can7HEO19JtMcStdW34i
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/StartComCA.pem.certspec b/security/manager/ssl/tests/unit/test_startcom_wosign/StartComCA.pem.certspec
new file mode 100644
index 000000000..ee5d9fff1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/StartComCA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:printableString/C=IL/O=StartCom Ltd./CN=StartCom Certification Authority G2
+extension:keyUsage:keyCertSign,cRLSign
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-after-cutoff.pem b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-after-cutoff.pem
new file mode 100644
index 000000000..5d7d50527
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-after-cutoff.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGzCCAgWgAwIBAgIUMYT7CkMtLLxN3tKEWzFXFQ6c/gwwCwYJKoZIhvcNAQEL
+MFUxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgG
+A1UEAxMhQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduMCIYDzIwMTYx
+MDIyMDAwMDAwWhgPMjAxNzEwMjIwMDAwMDBaMB4xHDAaBgNVBAMME1dvU2lnbi1h
+ZnRlci1jdXRvZmYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGo
+RI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9a
+dWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6t
+aRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8n
+FthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kX
+Dqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/py
+UcQx1QOs2hgKNe2NAgMBAAGjGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMAsG
+CSqGSIb3DQEBCwOCAQEAjBm9k3WX810z55fcMrbsT6AJk4Fhr+rRLth+KWEpkvN+
+gYZymkVIA390oFyH9VxbEGvSIv6bJfB7yVOtL2q6mj9mn7ybRoWlX1HOH7Cjqp7R
+6qivI4nG5Khn6uQxSxBbu26yhHmGcyq0QrhKEGrLzhoQc/0MOg32xnRRNu/bkFiL
+GNsu6wkRnB82aC4qjyohfkNqnaHES+D5ed+GuSD5QEU/r7Gz0Wd1a+MiOBc71R0W
+WDadFfE7sTuMiidSrxdN4j5sGwSvyudM3NlEHhnyn/jJcOzYpTtVOg5qmcrNRxq5
+ppj7eoIfCz+YJVz86cI96TM7S4OL8LG+UU90+3Kd8w==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-after-cutoff.pem.certspec b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-after-cutoff.pem.certspec
new file mode 100644
index 000000000..2afb5d6ea
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-after-cutoff.pem.certspec
@@ -0,0 +1,4 @@
+issuer:printableString/C=CN/O=WoSign CA Limited/CN=Certification Authority of WoSign
+subject:WoSign-after-cutoff
+validity:20161022-20171022
+extension:subjectAlternativeName:example.com
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-before-cutoff.pem b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-before-cutoff.pem
new file mode 100644
index 000000000..09c661a92
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-before-cutoff.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAgagAwIBAgIUVWn2KHK/AHKe+8z02VsFj3fXqjAwCwYJKoZIhvcNAQEL
+MFUxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgG
+A1UEAxMhQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduMCIYDzIwMTUx
+MDIyMDAwMDAwWhgPMjAxNzEwMjIwMDAwMDBaMB8xHTAbBgNVBAMMFFdvU2lnbi1i
+ZWZvcmUtY3V0b2ZmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR
+qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv
+WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+
+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv
+JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5
+Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6
+clHEMdUDrNoYCjXtjQIDAQABoxowGDAWBgNVHREEDzANggtleGFtcGxlLmNvbTAL
+BgkqhkiG9w0BAQsDggEBALMqCQoOhrBOeIzR7ffMCR/qUNz8LeELms31eF0Ks/Ol
+vMUJ9FBJOVHWq40zXnNBrH3qTVnTgAAZegjepzgggwd52gkkg0aD5WCZZy7TP1ie
+fbcdqC71LWghBZKkl6EFBDcnB4/ssc5MDhFAd3qyH/GHZSwtn2Ekk3vQBudOC/tW
+W/OGS5o+qP3NwtTWXmdD5Q/dmm0wUp9t+4sJ9glwBVDeJfi23QWbR6G2cBBcyzvS
+IZ+F1dOPKrZ23OJufiu4pDLQupC9mpQUWXb5kst+i//52Zsfupe3U/4XjcLbqR+1
+VVhcoBNf/mJs9UMIpaG0tn+j82rw7t8zGd1VMcA/XYM=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-before-cutoff.pem.certspec b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-before-cutoff.pem.certspec
new file mode 100644
index 000000000..224522bf0
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSign-before-cutoff.pem.certspec
@@ -0,0 +1,4 @@
+issuer:printableString/C=CN/O=WoSign CA Limited/CN=Certification Authority of WoSign
+subject:WoSign-before-cutoff
+validity:20151022-20171022
+extension:subjectAlternativeName:example.com
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/WoSignCA.pem b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSignCA.pem
new file mode 100644
index 000000000..30199bb3f
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSignCA.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDTCCAfegAwIBAgIUDxl5OmNq9eGdBbJrOQ/hkQbkVH0wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
+MDBaMFUxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEq
+MCgGA1UEAxMhQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq
+5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SSc
+An7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39
+ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYk
+zBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3u
+JtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQAB
+ox0wGzALBgNVHQ8EBAMCAQYwDAYDVR0TBAUwAwEB/zALBgkqhkiG9w0BAQsDggEB
+AEXCRSFaCDBBttpHRtGnX/tHbazxrHVzK2e5C8wN5piB8sOnwDHfpbRkcqs5Dn11
+7CAaRb993YVk22qzQ+R+r9cbbg2VuuBEYeHgGWNFdy4Oe4FMneHzOarWLiwIKjvS
+ZWf+obcRQpfI1hhXu5NkkZM5VgRwuRziIF6Xe9brQq5oqos/B9Rn7Edu6i8URrHx
+JLmpzTWGpyMYxVjUnvFQUyhFWaDMNE83SvXFY4bJww7O44XdXPpvrGU40oqZPPF4
+gzkYRmBAa/T4ERDQFigoqgZ9AmbFCnRQOBMLUwHT4ShcBO7iMCpxChpEb+nhr0LP
+fPkwoQr8c4keJOSpman2iXA=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/WoSignCA.pem.certspec b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSignCA.pem.certspec
new file mode 100644
index 000000000..db92c5f6d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/WoSignCA.pem.certspec
@@ -0,0 +1,4 @@
+issuer:ca
+subject:printableString/C=CN/O=WoSign CA Limited/CN=Certification Authority of WoSign
+extension:keyUsage:keyCertSign,cRLSign
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/ca.pem b/security/manager/ssl/tests/unit/test_startcom_wosign/ca.pem
new file mode 100644
index 000000000..4e4cb7814
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa+gAwIBAgIUQd13DvR3qDTAkz/7io280SPUCd0wCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTAwMTAxMDAwMDAwWhgPMjA1MDAxMDEwMDAw
+MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
+Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
+7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
+qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
+HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
+uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzALBgNVHQ8EBAMCAQYwDAYDVR0T
+BAUwAwEB/zALBgkqhkiG9w0BAQsDggEBAAEilE//BPKAsXleuiF6ITvBkjgJzlaD
+lGphvhPZNXENmYqkSOAZXAglmX0N4mq/1o3OC4IAhxqOj901y+QRM8zdemGDbpG7
+oqvAgeX5JLMKg5zj1lkdVkuNTfnKzNVJOWLHU4T1LrLuUGkVl7ba3s9RrqRmYtu8
+o4IgFUOXopjAo6Be/xrPzrRE6wTOFkhVaShYZBNNN/yJ4Eni4BnwxQ3uNSs6OQOO
+MpHW1Ibil2Oq7xcOmMj3WbB8uWCp1deM7h7l/u8cyUEMSCAhkYgSCorv/rECjP1k
+K3quGWnX3aN7idc4lOZkROIFyKR2V1No5OyUjmR2QKxf2RUq4XEWP2E=
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/ca.pem.certspec b/security/manager/ssl/tests/unit/test_startcom_wosign/ca.pem.certspec
new file mode 100644
index 000000000..efd24b153
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/ca.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ca
+subject:ca
+validity:20100101-20500101
+extension:keyUsage:keyCertSign,cRLSign
+extension:basicConstraints:cA,
diff --git a/security/manager/ssl/tests/unit/test_startcom_wosign/moz.build b/security/manager/ssl/tests/unit/test_startcom_wosign/moz.build
new file mode 100644
index 000000000..ed3680061
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_startcom_wosign/moz.build
@@ -0,0 +1,19 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'StartCom-after-cutoff.pem',
+# 'StartCom-before-cutoff.pem',
+# 'StartComCA.pem',
+# 'WoSign-after-cutoff.pem',
+# 'WoSign-before-cutoff.pem',
+# 'WoSignCA.pem',
+# 'ca.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
diff --git a/security/manager/ssl/tests/unit/test_sts_fqdn.js b/security/manager/ssl/tests/unit/test_sts_fqdn.js
new file mode 100644
index 000000000..c2c3eb2bd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sts_fqdn.js
@@ -0,0 +1,50 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+"use strict";
+
+function run_test() {
+ let SSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com.", 0));
+ // These cases are only relevant as long as bug 1118522 hasn't been fixed.
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com..", 0));
+
+ let uri = Services.io.newURI("https://example.com", null, null);
+ let sslStatus = new FakeSSLStatus();
+ SSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1000;includeSubdomains", sslStatus, 0);
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com.", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com..", 0));
+
+ ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
+ uri = Services.io.newURI("https://example.com.", null, null);
+ ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
+ uri = Services.io.newURI("https://example.com..", null, null);
+ ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0));
+
+ SSService.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com.", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.com..", 0));
+
+ // Somehow creating this malformed URI succeeds - we need to handle it
+ // gracefully.
+ uri = Services.io.newURI("https://../foo", null, null);
+ equal(uri.host, "..");
+ throws(() => {
+ SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri, 0);
+ }, /NS_ERROR_UNEXPECTED/, "Malformed URI should be rejected");
+}
diff --git a/security/manager/ssl/tests/unit/test_sts_holepunch.js b/security/manager/ssl/tests/unit/test_sts_holepunch.js
new file mode 100644
index 000000000..b7e643148
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sts_holepunch.js
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+"use strict";
+
+// bug 961528: chart.apis.google.com doesn't handle https. Check that
+// it isn't considered HSTS (other example.apis.google.com hosts should be
+// HSTS as long as they're on the preload list, however).
+function run_test() {
+ let SSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "chart.apis.google.com", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "CHART.APIS.GOOGLE.COM", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.chart.apis.google.com", 0));
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "SUB.CHART.APIS.GOOGLE.COM", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "example.apis.google.com", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "EXAMPLE.APIS.GOOGLE.COM", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sub.example.apis.google.com", 0));
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "SUB.EXAMPLE.APIS.GOOGLE.COM", 0));
+ // also check isSecureURI
+ let chartURI = Services.io.newURI("http://chart.apis.google.com", null, null);
+ ok(!SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, chartURI, 0));
+ let otherURI = Services.io.newURI("http://other.apis.google.com", null, null);
+ ok(SSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, otherURI, 0));
+}
diff --git a/security/manager/ssl/tests/unit/test_sts_ipv4_ipv6.js b/security/manager/ssl/tests/unit/test_sts_ipv4_ipv6.js
new file mode 100644
index 000000000..934fa4c3a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sts_ipv4_ipv6.js
@@ -0,0 +1,42 @@
+"use strict";
+
+function check_ip(s, v, ip) {
+ let sslStatus = new FakeSSLStatus();
+ ok(!s.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS, ip, 0));
+
+ let str = "https://";
+ if (v == 6) {
+ str += "[";
+ }
+ str += ip;
+ if (v == 6) {
+ str += "]";
+ }
+ str += "/";
+
+ let uri = Services.io.newURI(str, null, null);
+
+ let parsedMaxAge = {};
+ let parsedIncludeSubdomains = {};
+ s.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1000;includeSubdomains", sslStatus, 0,
+ parsedMaxAge, parsedIncludeSubdomains);
+
+ /* Test that processHeader will ignore headers for an uri, if the uri
+ * contains an IP address not a hostname.
+ * If processHeader indeed ignore the header, then the output parameters will
+ * remain empty, and we shouldn't see the values passed as the header.
+ */
+ notEqual(parsedMaxAge.value, 1000);
+ notEqual(parsedIncludeSubdomains.value, true);
+}
+
+function run_test() {
+ let SSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+
+ check_ip(SSService, 4, "127.0.0.1");
+ check_ip(SSService, 4, "10.0.0.1");
+ check_ip(SSService, 6, "2001:db8::1");
+ check_ip(SSService, 6, "1080::8:800:200C:417A");
+}
diff --git a/security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js b/security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js
new file mode 100644
index 000000000..e83f6f5b9
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js
@@ -0,0 +1,217 @@
+"use strict";
+
+var gSSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+
+function Observer() {}
+Observer.prototype = {
+ observe: function(subject, topic, data) {
+ if (topic == "last-pb-context-exited") {
+ run_next_test();
+ }
+ }
+};
+
+var gObserver = new Observer();
+var sslStatus = new FakeSSLStatus();
+
+function cleanup() {
+ Services.obs.removeObserver(gObserver, "last-pb-context-exited");
+ gSSService.clearAll();
+}
+
+function run_test() {
+ do_register_cleanup(cleanup);
+ Services.obs.addObserver(gObserver, "last-pb-context-exited", false);
+
+ add_test(test_part1);
+ add_test(test_private_browsing1);
+ add_test(test_private_browsing2);
+
+ run_next_test();
+}
+
+function test_part1() {
+ // check that a host not in the list is not identified as an sts host
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "nonexistent.example.com", 0));
+
+ // check that an ancestor domain is not identified as an sts host
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS, "com", 0));
+
+ // check that the pref to toggle using the preload list works
+ Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", false);
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ Services.prefs.setBoolPref("network.stricttransportsecurity.preloadlist", true);
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+
+ // check that a subdomain is an sts host (includeSubdomains is set)
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.includesubdomains.preloaded.test", 0));
+
+ // check that another subdomain is an sts host (includeSubdomains is set)
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "a.b.c.def.includesubdomains.preloaded.test", 0));
+
+ // check that a subdomain is not an sts host (includeSubdomains is not set)
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.noincludesubdomains.preloaded.test", 0));
+
+ // check that a host with a dot on the end won't break anything
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "notsts.nonexistent.example.com.", 0));
+
+ // check that processing a header with max-age: 0 will remove a preloaded
+ // site from the list
+ let uri = Services.io.newURI("http://includesubdomains.preloaded.test", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=0", sslStatus, 0);
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.includesubdomains.preloaded.test", 0));
+ // check that processing another header (with max-age non-zero) will
+ // re-enable a site's sts status
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1000", sslStatus, 0);
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ // but this time include subdomains was not set, so test for that
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.includesubdomains.preloaded.test", 0));
+ gSSService.clearAll();
+
+ // check that processing a header with max-age: 0 from a subdomain of a site
+ // will not remove that (ancestor) site from the list
+ uri = Services.io.newURI("http://subdomain.noincludesubdomains.preloaded.test", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=0", sslStatus, 0);
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "noincludesubdomains.preloaded.test", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.noincludesubdomains.preloaded.test", 0));
+
+ uri = Services.io.newURI("http://subdomain.includesubdomains.preloaded.test", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=0", sslStatus, 0);
+ // we received a header with "max-age=0", so we have "no information"
+ // regarding the sts state of subdomain.includesubdomains.preloaded.test specifically,
+ // but it is actually still an STS host, because of the preloaded
+ // includesubdomains.preloaded.test including subdomains.
+ // Here's a drawing:
+ // |-- includesubdomains.preloaded.test (in preload list, includes subdomains) IS sts host
+ // |-- subdomain.includesubdomains.preloaded.test IS sts host
+ // | `-- another.subdomain.includesubdomains.preloaded.test IS sts host
+ // `-- sibling.includesubdomains.preloaded.test IS sts host
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.includesubdomains.preloaded.test", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sibling.includesubdomains.preloaded.test", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "another.subdomain.includesubdomains.preloaded.test", 0));
+
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1000", sslStatus, 0);
+ // Here's what we have now:
+ // |-- includesubdomains.preloaded.test (in preload list, includes subdomains) IS sts host
+ // |-- subdomain.includesubdomains.preloaded.test (include subdomains is false) IS sts host
+ // | `-- another.subdomain.includesubdomains.preloaded.test IS NOT sts host
+ // `-- sibling.includesubdomains.preloaded.test IS sts host
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.includesubdomains.preloaded.test", 0));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "sibling.includesubdomains.preloaded.test", 0));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "another.subdomain.includesubdomains.preloaded.test", 0));
+
+ // Test that an expired non-private browsing entry results in correctly
+ // identifying a host that is on the preload list as no longer sts.
+ // (This happens when we're in regular browsing mode, we get a header from
+ // a site on the preload list, and that header later expires. We need to
+ // then treat that host as no longer an sts host.)
+ // (sanity check first - this should be in the preload list)
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains2.preloaded.test", 0));
+ uri = Services.io.newURI("http://includesubdomains2.preloaded.test", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1", sslStatus, 0);
+ do_timeout(1250, function() {
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains2.preloaded.test", 0));
+ run_next_test();
+ });
+}
+
+const IS_PRIVATE = Ci.nsISocketProvider.NO_PERMANENT_STORAGE;
+
+function test_private_browsing1() {
+ gSSService.clearAll();
+ // sanity - includesubdomains.preloaded.test is preloaded, includeSubdomains set
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", IS_PRIVATE));
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "a.b.c.subdomain.includesubdomains.preloaded.test", IS_PRIVATE));
+
+ let uri = Services.io.newURI("http://includesubdomains.preloaded.test", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=0", sslStatus, IS_PRIVATE);
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", IS_PRIVATE));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "a.b.subdomain.includesubdomains.preloaded.test", IS_PRIVATE));
+
+ // check adding it back in
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1000", sslStatus, IS_PRIVATE);
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", IS_PRIVATE));
+ // but no includeSubdomains this time
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "b.subdomain.includesubdomains.preloaded.test", IS_PRIVATE));
+
+ // do the hokey-pokey...
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=0", sslStatus, IS_PRIVATE);
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", IS_PRIVATE));
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.includesubdomains.preloaded.test", IS_PRIVATE));
+
+ // Test that an expired private browsing entry results in correctly
+ // identifying a host that is on the preload list as no longer sts.
+ // (This happens when we're in private browsing mode, we get a header from
+ // a site on the preload list, and that header later expires. We need to
+ // then treat that host as no longer an sts host.)
+ // (sanity check first - this should be in the preload list)
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains2.preloaded.test", IS_PRIVATE));
+ uri = Services.io.newURI("http://includesubdomains2.preloaded.test", null, null);
+ gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
+ "max-age=1", sslStatus, IS_PRIVATE);
+ do_timeout(1250, function() {
+ ok(!gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains2.preloaded.test", IS_PRIVATE));
+ // Simulate leaving private browsing mode
+ Services.obs.notifyObservers(null, "last-pb-context-exited", null);
+ });
+}
+
+function test_private_browsing2() {
+ // if this test gets this far, it means there's a private browsing service
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+ // the includesubdomains.preloaded.test entry has includeSubdomains set
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "subdomain.includesubdomains.preloaded.test", 0));
+
+ // Now that we're out of private browsing mode, we need to make sure
+ // we've "forgotten" that we "forgot" this site's sts status.
+ ok(gSSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains2.preloaded.test", 0));
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_sts_preloadlist_selfdestruct.js b/security/manager/ssl/tests/unit/test_sts_preloadlist_selfdestruct.js
new file mode 100644
index 000000000..8b75b52ae
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_sts_preloadlist_selfdestruct.js
@@ -0,0 +1,23 @@
+"use strict";
+
+function run_test() {
+ let SSService = Cc["@mozilla.org/ssservice;1"]
+ .getService(Ci.nsISiteSecurityService);
+
+ // check that a host on the preload list is identified as an sts host
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+
+ // now simulate that it's 19 weeks later than it actually is
+ let offsetSeconds = 19 * 7 * 24 * 60 * 60;
+ Services.prefs.setIntPref("test.currentTimeOffsetSeconds", offsetSeconds);
+
+ // check that the preloaded host is no longer considered sts
+ ok(!SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+
+ // just make sure we can get everything back to normal
+ Services.prefs.clearUserPref("test.currentTimeOffsetSeconds");
+ ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+ "includesubdomains.preloaded.test", 0));
+}
diff --git a/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js b/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js
new file mode 100644
index 000000000..d7ffd17bd
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js
@@ -0,0 +1,133 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* This test is for the TLS error reporting functionality exposed by
+ * SecurityReporter.js in /toolkit/components/securityreporter. The test is
+ * here because we make use of the tlsserver functionality that lives with the
+ * PSM ssl tests.
+ *
+ * The testing here will be augmented by the existing mochitests for the
+ * error reporting functionality in aboutNetError.xhtml and
+ * aboutCertError.xhtml once these make use of this component.
+ */
+
+"use strict";
+const CC = Components.Constructor;
+const Cm = Components.manager;
+
+Cu.import("resource://testing-common/AppInfo.jsm");
+/*global updateAppInfo:false*/ // Imported via AppInfo.jsm.
+updateAppInfo();
+
+// We must get the profile before performing operations on the cert db.
+do_get_profile();
+
+const certdb = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+const reporter = Cc["@mozilla.org/securityreporter;1"]
+ .getService(Ci.nsISecurityReporter);
+
+
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream", "setInputStream");
+
+var server;
+
+// this allows us to create a callback which checks that a report is as
+// expected.
+function getReportCheck(expectReport, expectedError) {
+ return function sendReportWithInfo(transportSecurityInfo) {
+ // register a path handler on the server
+ server.registerPathHandler("/submit/sslreports",
+ function(request, response) {
+ if (expectReport) {
+ let report = JSON.parse(readDataFromRequest(request));
+ do_check_eq(report.errorCode, expectedError);
+ response.setStatusLine(null, 201, "Created");
+ response.write("Created");
+ } else {
+ do_throw("No report should have been received");
+ }
+ });
+
+ reporter.reportTLSError(transportSecurityInfo, "example.com", -1);
+ };
+}
+
+// read the request body from a request
+function readDataFromRequest(aRequest) {
+ if (aRequest.method == "POST" || aRequest.method == "PUT") {
+ if (aRequest.bodyInputStream) {
+ let inputStream = new BinaryInputStream(aRequest.bodyInputStream);
+ let bytes = [];
+ let available;
+
+ while ((available = inputStream.available()) > 0) {
+ Array.prototype.push.apply(bytes, inputStream.readByteArray(available));
+ }
+
+ return String.fromCharCode.apply(null, bytes);
+ }
+ }
+ return null;
+}
+
+function run_test() {
+ // start a report server
+ server = new HttpServer();
+ server.start(-1);
+
+ let port = server.identity.primaryPort;
+
+ // Set the reporting URL to ensure any reports are sent to the test server
+ Services.prefs.setCharPref("security.ssl.errorReporting.url",
+ `http://localhost:${port}/submit/sslreports`);
+ // set strict-mode pinning enforcement so we can cause connection failures.
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
+
+ // start a TLS server
+ add_tls_server_setup("BadCertServer", "bad_certs");
+
+ // Add a user-specified trust anchor.
+ addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u");
+
+
+ // Cause a reportable condition with error reporting disabled. No report
+ // should be sent.
+ Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", false);
+ add_connection_test("expired.example.com",
+ SEC_ERROR_EXPIRED_CERTIFICATE, null,
+ getReportCheck(false));
+
+ // Now enable reporting
+ add_test(function () {
+ Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
+ run_next_test();
+ });
+
+ // test calling the component with no transportSecurityInfo. No report should
+ // be sent even though reporting is enabled.
+ add_test(function() {
+ server.registerPathHandler("/submit/sslreports",
+ function(request, response) {
+ do_throw("No report should be sent");
+ });
+ reporter.reportTLSError(null, "example.com", -1);
+ run_next_test();
+ });
+
+ // Test sending a report with no error. This allows us to check the case
+ // where there is no failed cert chain
+ add_connection_test("good.include-subdomains.pinning.example.com",
+ PRErrorCodeSuccess, null,
+ getReportCheck(true, PRErrorCodeSuccess));
+
+ // Test sending a report where there is an error and a failed cert chain.
+ add_connection_test("expired.example.com",
+ SEC_ERROR_EXPIRED_CERTIFICATE, null,
+ getReportCheck(true, SEC_ERROR_EXPIRED_CERTIFICATE));
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_validity.js b/security/manager/ssl/tests/unit/test_validity.js
new file mode 100644
index 000000000..9158c7a5d
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity.js
@@ -0,0 +1,92 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests that chains containing an end-entity cert with an overly long validity
+// period are rejected.
+
+do_get_profile(); // Must be called before getting nsIX509CertDB
+const certDB = Cc["@mozilla.org/security/x509certdb;1"]
+ .getService(Ci.nsIX509CertDB);
+
+const SERVER_PORT = 8888;
+
+function getOCSPResponder(expectedCertNames) {
+ let expectedPaths = expectedCertNames.slice();
+ return startOCSPResponder(SERVER_PORT, "www.example.com", "test_validity",
+ expectedCertNames, expectedPaths);
+}
+
+function certFromFile(filename) {
+ return constructCertFromFile(`test_validity/${filename}`);
+}
+
+function loadCert(certFilename, trustString) {
+ addCertFromFile(certDB, `test_validity/${certFilename}`, trustString);
+}
+
+/**
+ * Adds a single EV test.
+ *
+ * @param {Array} expectedNamesForOCSP
+ * An array of nicknames of the certs to be responded to.
+ * @param {String} rootCertFileName
+ * The file name of the root cert. Can begin with ".." to reference
+ * certs in folders other than "test_validity/".
+ * @param {Array} intCertFileNames
+ * An array of file names of any intermediate certificates.
+ * @param {String} endEntityCertFileName
+ * The file name of the end entity cert.
+ * @param {Boolean} expectedResult
+ * Whether the chain is expected to validate as EV.
+ */
+function addEVTest(expectedNamesForOCSP, rootCertFileName, intCertFileNames,
+ endEntityCertFileName, expectedResult)
+{
+ add_test(function() {
+ clearOCSPCache();
+ let ocspResponder = getOCSPResponder(expectedNamesForOCSP);
+
+ loadCert(`${rootCertFileName}.pem`, "CTu,CTu,CTu");
+ for (let intCertFileName of intCertFileNames) {
+ loadCert(`${intCertFileName}.pem`, ",,");
+ }
+ checkEVStatus(certDB, certFromFile(`${endEntityCertFileName}.pem`),
+ certificateUsageSSLServer, expectedResult);
+
+ ocspResponder.stop(run_next_test);
+ });
+}
+
+function checkEVChains() {
+ // Chain with an end entity cert with a validity period that is acceptable
+ // for EV.
+ const intFullName = "ev_int_60_months-evroot";
+ let eeFullName = `ev_ee_27_months-${intFullName}`;
+ let expectedNamesForOCSP = gEVExpected
+ ? [ intFullName,
+ eeFullName ]
+ : [ eeFullName ];
+ addEVTest(expectedNamesForOCSP, "../test_ev_certs/evroot", [ intFullName ],
+ eeFullName, gEVExpected);
+
+ // Chain with an end entity cert with a validity period that is too long
+ // for EV.
+ eeFullName = `ev_ee_28_months-${intFullName}`;
+ expectedNamesForOCSP = gEVExpected
+ ? [ intFullName,
+ eeFullName ]
+ : [ eeFullName ];
+ addEVTest(expectedNamesForOCSP, "../test_ev_certs/evroot", [ intFullName ],
+ eeFullName, false);
+}
+
+function run_test() {
+ Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
+ Services.prefs.setIntPref("security.OCSP.enabled", 1);
+
+ checkEVChains();
+
+ run_next_test();
+}
diff --git a/security/manager/ssl/tests/unit/test_validity/ev_ee_27_months-ev_int_60_months-evroot.pem b/security/manager/ssl/tests/unit/test_validity/ev_ee_27_months-ev_int_60_months-evroot.pem
new file mode 100644
index 000000000..6a351f0f8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/ev_ee_27_months-ev_int_60_months-evroot.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDaTCCAlOgAwIBAgIUCfxWL6o44roTydDNAETL0eXxLF4wCwYJKoZIhvcNAQEL
+MCIxIDAeBgNVBAMMF2V2X2ludF82MF9tb250aHMtZXZyb290MCIYDzIwMTUxMTE3
+MDAwMDAwWhgPMjAxODAyMTYwMDAwMDBaMDIxMDAuBgNVBAMMJ2V2X2VlXzI3X21v
+bnRocy1ldl9pbnRfNjBfbW9udGhzLWV2cm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBhjCBgzBgBggrBgEF
+BQcBAQRUMFIwUAYIKwYBBQUHMAGGRGh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4
+OC9ldl9lZV8yN19tb250aHMtZXZfaW50XzYwX21vbnRocy1ldnJvb3QvMB8GA1Ud
+IAQYMBYwFAYSKwYBBAHrSYUahRqFGgGDdAkBMAsGCSqGSIb3DQEBCwOCAQEAIVNL
+5xN2XbNowmdE1AqGcx+fPzou65QRhhus3kLeDKiULIn8fk75rI9+3oqOpeu908iu
+1BQze/EX24DC8k+vkSWRSud1by/AL1ztnTFuFa1UFxKyTBzn9CGHqOK2fcQ2/TZk
+Zewt7yNcsazKGaf+V2K3slnNOjx1Jx7aby8moA74FzoEv6jCHhfbx5l+Ul5izDZH
+EcBi4kOZR6AFP8RhhG8ohqKXv7pxi7tS2OV75cl0sE4XwKp1UbdH7B2ea/aO9ZY8
+Bkq6vgY6Y2kAp8PE2S6cAY9ugEjoplBUq85/1n5FhpBevhMJ/L7oZ+EhooGowRfH
+VofhfUBd6Cn2fsTiMQ==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_validity/ev_ee_27_months-ev_int_60_months-evroot.pem.certspec b/security/manager/ssl/tests/unit/test_validity/ev_ee_27_months-ev_int_60_months-evroot.pem.certspec
new file mode 100644
index 000000000..d2c7fa127
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/ev_ee_27_months-ev_int_60_months-evroot.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ev_int_60_months-evroot
+subject:ev_ee_27_months-ev_int_60_months-evroot
+validity:823
+extension:authorityInformationAccess:http://www.example.com:8888/ev_ee_27_months-ev_int_60_months-evroot/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_validity/ev_ee_28_months-ev_int_60_months-evroot.pem b/security/manager/ssl/tests/unit/test_validity/ev_ee_28_months-ev_int_60_months-evroot.pem
new file mode 100644
index 000000000..28d7bdb90
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/ev_ee_28_months-ev_int_60_months-evroot.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDaTCCAlOgAwIBAgIUVzCbeSKUj0d/ynX8eWoINELWJi8wCwYJKoZIhvcNAQEL
+MCIxIDAeBgNVBAMMF2V2X2ludF82MF9tb250aHMtZXZyb290MCIYDzIwMTUxMTAx
+MDAwMDAwWhgPMjAxODAzMDQwMDAwMDBaMDIxMDAuBgNVBAMMJ2V2X2VlXzI4X21v
+bnRocy1ldl9pbnRfNjBfbW9udGhzLWV2cm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
+qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
+w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
+V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
+MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
+vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaOBhjCBgzBgBggrBgEF
+BQcBAQRUMFIwUAYIKwYBBQUHMAGGRGh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4
+OC9ldl9lZV8yOF9tb250aHMtZXZfaW50XzYwX21vbnRocy1ldnJvb3QvMB8GA1Ud
+IAQYMBYwFAYSKwYBBAHrSYUahRqFGgGDdAkBMAsGCSqGSIb3DQEBCwOCAQEAjqOB
+RSvTVS9M/STcTmevwdW+JZXFkXvMYQ2TZQNsdKL8jTF7V8yUAuWIXt9dfZksRzCH
+J2M2iFBeme2w9732nv8dLiBvfHNHpWAW8YnQka0+SMXgsD7lMuHgXhbesGoGS6f6
+jtO5TsB+D1pXFncehDcxbW+0Ai1yd5sFuFaq2wN6zgsANzwehXp9qCGQ1jVQ2ti5
+ai4raaipKXEo3j3DxlNPdrdeN0RSimP+Mnyfj8LSxnmZQM1hdwRhJekUPQUux4pZ
+qseofBITmHehriREJRZlzxCzccpr2wCcwUYNBDwSJK91xy0SW2gSAQV0OVx/e3tA
+SqIRcRMdskz9NWa/oA==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_validity/ev_ee_28_months-ev_int_60_months-evroot.pem.certspec b/security/manager/ssl/tests/unit/test_validity/ev_ee_28_months-ev_int_60_months-evroot.pem.certspec
new file mode 100644
index 000000000..2dcfb2e29
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/ev_ee_28_months-ev_int_60_months-evroot.pem.certspec
@@ -0,0 +1,5 @@
+issuer:ev_int_60_months-evroot
+subject:ev_ee_28_months-ev_int_60_months-evroot
+validity:854
+extension:authorityInformationAccess:http://www.example.com:8888/ev_ee_28_months-ev_int_60_months-evroot/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.key b/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.key
new file mode 100644
index 000000000..8af23e068
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6iFGoRI4W1kH9
+braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEI
+eqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6
+iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Za
+qn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7
+LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs
+2hgKNe2NAgMBAAECggEBAJ7LzjhhpFTsseD+j4XdQ8kvWCXOLpl4hNDhqUnaosWs
+VZskBFDlrJ/gw+McDu+mUlpl8MIhlABO4atGPd6e6CKHzJPnRqkZKcXmrD2IdT9s
+JbpZeec+XY+yOREaPNq4pLDN9fnKsF8SM6ODNcZLVWBSXn47kq18dQTPHcfLAFeI
+r8vh6Pld90AqFRUw1YCDRoZOs3CqeZVqWHhiy1M3kTB/cNkcltItABppAJuSPGgz
+iMnzbLm16+ZDAgQceNkIIGuHAJy4yrrK09vbJ5L7kRss9NtmA1hb6a4Mo7jmQXqg
+SwbkcOoaO1gcoDpngckxW2KzDmAR8iRyWUbuxXxtlEECgYEA3W4dT//r9o2InE0R
+TNqqnKpjpZN0KGyKXCmnF7umA3VkTVyqZ0xLi8cyY1hkYiDkVQ12CKwn1Vttt0+N
+gSfvj6CQmLaRR94GVXNEfhg9Iv59iFrOtRPZWB3V4HwakPXOCHneExNx7O/JznLp
+xD3BJ9I4GQ3oEXc8pdGTAfSMdCsCgYEA16dz2evDgKdn0v7Ak0rU6LVmckB3Gs3r
+ta15b0eP7E1FmF77yVMpaCicjYkQL63yHzTi3UlA66jAnW0fFtzClyl3TEMnXpJR
+3b5JCeH9O/Hkvt9Go5uLODMo70rjuVuS8gcK8myefFybWH/t3gXo59hspXiG+xZY
+EKd7mEW8MScCgYEAlkcrQaYQwK3hryJmwWAONnE1W6QtS1oOtOnX6zWBQAul3RMs
+2xpekyjHu8C7sBVeoZKXLt+X0SdR2Pz2rlcqMLHqMJqHEt1OMyQdse5FX8CT9byb
+WS11bmYhR08ywHryL7J100B5KzK6JZC7smGu+5WiWO6lN2VTFb6cJNGRmS0CgYAo
+tFCnp1qFZBOyvab3pj49lk+57PUOOCPvbMjo+ibuQT+LnRIFVA8Su+egx2got7pl
+rYPMpND+KiIBFOGzXQPVqFv+Jwa9UPzmz83VcbRspiG47UfWBbvnZbCqSgZlrCU2
+TaIBVAMuEgS4VZ0+NPtbF3yaVv+TUQpaSmKHwVHeLQKBgCgGe5NVgB0u9S36ltit
+tYlnPPjuipxv9yruq+nva+WKT0q/BfeIlH3IUf2qNFQhR6caJGv7BU7naqNGq80m
+ks/J5ExR5vBpxzXgc7oBn2pyFJYckbJoccrqv48GRBigJpDjmo1f8wZ7fNt/ULH1
+NBinA5ZsT8d0v3QCr2xDJH9D
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.key.keyspec b/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.key.keyspec
new file mode 100644
index 000000000..4ad96d515
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.key.keyspec
@@ -0,0 +1 @@
+default
diff --git a/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.pem b/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.pem
new file mode 100644
index 000000000..370f4ff36
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAj2gAwIBAgIUc/8GbZoQxUER+Wpe3STidbOom4UwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE0MDcwNDAwMDAwMFoYDzIwMTkwNzAy
+MDAwMDAwWjAiMSAwHgYDVQQDDBdldl9pbnRfNjBfbW9udGhzLWV2cm9vdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ
+6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUk
+nAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N
+/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAG
+JMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd
+7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEA
+AaOBkTCBjjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjBQBggrBgEFBQcBAQRE
+MEIwQAYIKwYBBQUHMAGGNGh0dHA6Ly93d3cuZXhhbXBsZS5jb206ODg4OC9ldl9p
+bnRfNjBfbW9udGhzLWV2cm9vdC8wHwYDVR0gBBgwFjAUBhIrBgEEAetJhRqFGoUa
+AYN0CQEwCwYJKoZIhvcNAQELA4IBAQBKiGfIv5d53ND76/fYD4UrAQCe4K5Ktj8s
+UkVgozmHi5IE7e2Ikzp5gDAEIirehSQAdGI4DXYArZYG7O90isYiItxD/LDh342Z
+sFkg5Zdm6Cmr0V5EZRcWtfj7ZwdTl3/YdI6Sp00BfeTLabsHQD0/trFcd3BcXXLR
++WcNPwrCktVCtem7mgUPa5GTFgUyoOtcVGC5BBk7MqqLBHX6/R4u8oLcNwQOYZ0v
+Ad/6iQCcJ+siLTuQHWB6zu1uLd9CZQXu3pBU43p3WvvQwCPFSfT4wAOEoqn0a9ny
+YWmq+mXlLH0M28x931Ay5/q3TV93fFHVv5bratytdoUBYpsx3Edy
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.pem.certspec b/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.pem.certspec
new file mode 100644
index 000000000..e169514ff
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/ev_int_60_months-evroot.pem.certspec
@@ -0,0 +1,8 @@
+issuer:evroot
+subject:ev_int_60_months-evroot
+issuerKey:ev
+validity:1825
+extension:basicConstraints:cA,
+extension:keyUsage:cRLSign,keyCertSign
+extension:authorityInformationAccess:http://www.example.com:8888/ev_int_60_months-evroot/
+extension:certificatePolicies:1.3.6.1.4.1.13769.666.666.666.1.500.9.1
diff --git a/security/manager/ssl/tests/unit/test_validity/evroot.key b/security/manager/ssl/tests/unit/test_validity/evroot.key
new file mode 100644
index 000000000..a756a0705
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/evroot.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC1SYlcnQAQjRGh
++Z+HqePRpdtd+uzxiNpXv2QTaI8s5HIs/xCQOMF0Ask6Kkc9vShq7T/c02PPWikU
+dwG92BjXYVv5NWvV08gzaqqMCXE2igbDzURhuT5RQk4XRLsuqtRqqzjOGWghlh+H
+cUoWY2k/CXYc301roSXqzse+Jw04j3ifbN94rjFE7SjEXnkpOGOnoipImAo2pA5y
+1XnJuSXf+MeTNi/9aJenwXVMXpfJZ8Pq3RquiqLMzjSKAWm4Diii1wwalgxvM18t
+oJubZD9av7pJ6Kqpgelg4n2HSAvdVd2UF/oYUJ+7VUzPgaQ5fouoEoo0vfJ4ZcGJ
+5XNPsikFAgMBAAECggEBAJg9VPlNb0x26yPW+T14UjUwz3Ow0WJUxueBdo1F9VaB
+0dAvsr0qrGq8HDiYYJNcUqDY9BSCAQOUd4MUHYZL/zCANjilwBUlcK6dGPPYyhY+
++0dbDd3zLn4W7HVl5rteAlxBxcZuV6A87eVUIh+DBFNHosTEUcPc5Ha3h84MBXJE
+vp4E7xMRjbuz1eCmzIcCnq/Upp7ZsUdZsV452KmITlb1TS+asBPw0V8xipq2svc9
+HsPJ/idK6JQxoQZAvniZsAEcXlCToYNHCGid4QBjTaveYPvWqu+joz3zSh829gwE
+MDa3SNHJ7pjEAxoK/sYO/aCpkL5ST1YU6sT9s0pS+VECgYEA6twssz5f8co3a72V
+vWoXd9LPT6xHVF6S0RpiCbnV5N7UeDRYHBabPIhHQqCeoYdQXBylVBTY0ltJdjLV
+7CqqBSM0MPrUmJJ3en1o4Dj1YaO4lp5gsKJj3vv9pIqbD/OdlbyIsVJnyK3pe1EH
+lI5B5DMknYf32xCdXXRYTYa8wdcCgYEAxZrldqIWRwJI2USlW56b+TKZ2jQexW5V
+jrqCGrzhv1e3nPQR0pBMd0+duh8VGF9gewV0oIIF1uwotmo21jQjLqry/qN1Yauv
+nWRLaNs4yZZMuMluwKxh66ZNBbRGVC9COXb1rN5OzJVTbS31eJVPk/DP2cWPt4ui
+p23VrChNyIMCgYEAwdLvOQYzHFKspkgR+f5CW+somDIvs9tRAyzo1+n8MiQL6SAZ
+zySA/NXjKYNxJxGLKlmhv+BsiD46REfz8DHNmuvQuNNo/Hl0DSzOjq2zJN9/CR6v
+4VZDYdVJILAbBHEjDl5H2T+O0zljxRe8T8ePbYsfnrqFvM7bcDMCZQjbYoUCgYEA
+hSG421aU376ASjFfnvybZSdcVJCs8qNFbWXm5hC/n2R/xnUB1PV3LyMqxwzN75/C
+pt+kFcfEG2r8evnQfDygP37ZPAnwuZ8sMEQ0Mi8QcXCbvBuqTJFXX6apWeB9SZaV
+bZXiK1eTi25HyNUf/t/Jv4iM4NGj5CtlqJvtS5HT5fUCgYEA3El7BrkgyL4LAHe3
+mOl37vdEqQ7Cxdfmy7IkSPrHLagaMxgODYoC6DFGDH/H/TphL3uZMLYbeZ+OkI5j
+LpugQJtqpwsDo7p4dCYmO1vVhD34R27bXRT2qGE+uvW5zVykL1+9KALgjk5J5XCf
+UVFRDKpassHG6z7+kpXRbowlyRY=
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_validity/evroot.key.keyspec b/security/manager/ssl/tests/unit/test_validity/evroot.key.keyspec
new file mode 100644
index 000000000..1a3d76a55
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/evroot.key.keyspec
@@ -0,0 +1 @@
+ev
diff --git a/security/manager/ssl/tests/unit/test_validity/evroot.pem b/security/manager/ssl/tests/unit/test_validity/evroot.pem
new file mode 100644
index 000000000..cd2fd7ed8
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/evroot.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzTCCAbegAwIBAgIUW9j5PS8YoKgynZdYa9i2Kwexnp8wCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MDEwMTAwMDAwMFoYDzIwMzUwMTAx
+MDAwMDAwWjARMQ8wDQYDVQQDDAZldnJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC1SYlcnQAQjRGh+Z+HqePRpdtd+uzxiNpXv2QTaI8s5HIs/xCQ
+OMF0Ask6Kkc9vShq7T/c02PPWikUdwG92BjXYVv5NWvV08gzaqqMCXE2igbDzURh
+uT5RQk4XRLsuqtRqqzjOGWghlh+HcUoWY2k/CXYc301roSXqzse+Jw04j3ifbN94
+rjFE7SjEXnkpOGOnoipImAo2pA5y1XnJuSXf+MeTNi/9aJenwXVMXpfJZ8Pq3Rqu
+iqLMzjSKAWm4Diii1wwalgxvM18toJubZD9av7pJ6Kqpgelg4n2HSAvdVd2UF/oY
+UJ+7VUzPgaQ5fouoEoo0vfJ4ZcGJ5XNPsikFAgMBAAGjHTAbMAwGA1UdEwQFMAMB
+Af8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAO1EZ134zXCiYSMixYSVP
+gAXWdR8zvaeS8UF0Xihle6nBdtkcmhiMgxXecMv7P7xO/U/wz5NAyJ1cvqaxrPbn
+8bekVCCsAAae6mVJIsVeuLtg3f89Qmx6KF6By2NI5R/AX5gxs0V9Tvjp9NfpIWh9
+I0BO0/REmq+CxKWjO6Loq0JA/QRW1jnD3XLitJ9QiCfnLqgUAG8JnkhG/JtpcJC3
+91SluwhVw+8i7caDOgHZGvjBEycyje0iyDLybaVjv2PpyuQx8H6hDzTGd2bNDl22
+fZ0FsOYCH6TJPx7nsCJCQ8/jGsRAGPxbItwSpTQJegKVaJ9s2dOAreJdkQFSIEo+
+3g==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/security/manager/ssl/tests/unit/test_validity/evroot.pem.certspec b/security/manager/ssl/tests/unit/test_validity/evroot.pem.certspec
new file mode 100644
index 000000000..3121f3486
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/evroot.pem.certspec
@@ -0,0 +1,7 @@
+issuer:evroot
+subject:evroot
+subjectKey:ev
+issuerKey:ev
+validity:20150101-20350101
+extension:basicConstraints:cA,
+extension:keyUsage:keyCertSign,cRLSign
diff --git a/security/manager/ssl/tests/unit/test_validity/moz.build b/security/manager/ssl/tests/unit/test_validity/moz.build
new file mode 100644
index 000000000..d2f9bf8d1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_validity/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Temporarily disabled. See bug 1256495.
+#test_certificates = (
+# 'ev_ee_27_months-ev_int_60_months-evroot.pem',
+# 'ev_ee_28_months-ev_int_60_months-evroot.pem',
+# 'ev_int_60_months-evroot.pem',
+# 'evroot.pem',
+#)
+#
+#for test_certificate in test_certificates:
+# GeneratedTestCertificate(test_certificate)
+#
+#test_keys = (
+# 'ev_int_60_months-evroot.key',
+# 'evroot.key',
+#)
+#
+#for test_key in test_keys:
+# GeneratedTestKey(test_key)
diff --git a/security/manager/ssl/tests/unit/test_weak_crypto.js b/security/manager/ssl/tests/unit/test_weak_crypto.js
new file mode 100644
index 000000000..effedf8e3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_weak_crypto.js
@@ -0,0 +1,273 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests the weak crypto override
+
+const TLS_RSA_WITH_RC4_128_MD5 = 0x0004;
+const TLS_RSA_WITH_RC4_128_SHA = 0x0005;
+const TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007;
+const TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011;
+
+// Need profile dir to store the key / cert
+do_get_profile();
+// Ensure PSM is initialized
+Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+
+const certService = Cc["@mozilla.org/security/local-cert-service;1"]
+ .getService(Ci.nsILocalCertService);
+const certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
+ .getService(Ci.nsICertOverrideService);
+const weakCryptoOverride = Cc["@mozilla.org/security/weakcryptooverride;1"]
+ .getService(Ci.nsIWeakCryptoOverride);
+const socketTransportService =
+ Cc["@mozilla.org/network/socket-transport-service;1"]
+ .getService(Ci.nsISocketTransportService);
+
+function getCert() {
+ let deferred = Promise.defer();
+ certService.getOrCreateCert("tls-test", {
+ handleCert: function(c, rv) {
+ if (rv) {
+ deferred.reject(rv);
+ return;
+ }
+ deferred.resolve(c);
+ }
+ });
+ return deferred.promise;
+}
+
+function startServer(cert, rc4only) {
+ let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"]
+ .createInstance(Ci.nsITLSServerSocket);
+ tlsServer.init(-1, true, -1);
+ tlsServer.serverCert = cert;
+
+ let input, output;
+
+ let listener = {
+ onSocketAccepted: function(socket, transport) {
+ do_print("Accept TLS client connection");
+ let connectionInfo = transport.securityInfo
+ .QueryInterface(Ci.nsITLSServerConnectionInfo);
+ connectionInfo.setSecurityObserver(listener);
+ input = transport.openInputStream(0, 0, 0);
+ output = transport.openOutputStream(0, 0, 0);
+ },
+ onHandshakeDone: function(socket, status) {
+ do_print("TLS handshake done");
+
+ equal(status.tlsVersionUsed, Ci.nsITLSClientStatus.TLS_VERSION_1_2,
+ "Using TLS 1.2");
+ let expectedCipher = rc4only ? "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"
+ : "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
+ equal(status.cipherName, expectedCipher,
+ "Using expected cipher");
+ equal(status.keyLength, 128, "Using 128-bit key");
+ equal(status.macLength, rc4only ? 160 : 128, "Using MAC of expected length");
+
+ input.asyncWait({
+ onInputStreamReady: function(streamReadyInput) {
+ NetUtil.asyncCopy(streamReadyInput, output);
+ }
+ }, 0, 0, Services.tm.currentThread);
+ },
+ onStopListening: function() {}
+ };
+
+ tlsServer.setSessionCache(false);
+ tlsServer.setSessionTickets(false);
+ tlsServer.setRequestClientCertificate(Ci.nsITLSServerSocket.REQUEST_NEVER);
+ if (rc4only) {
+ let cipherSuites = [
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_RC4_128_MD5
+ ];
+ tlsServer.setCipherSuites(cipherSuites, cipherSuites.length);
+ }
+
+ tlsServer.asyncListen(listener);
+
+ return tlsServer.port;
+}
+
+function storeCertOverride(port, cert) {
+ let overrideBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED |
+ Ci.nsICertOverrideService.ERROR_MISMATCH;
+ certOverrideService.rememberValidityOverride("127.0.0.1", port, cert,
+ overrideBits, true);
+}
+
+function startClient(port, expectedResult, options = {}) {
+ let transport =
+ socketTransportService.createTransport(["ssl"], 1, "127.0.0.1", port, null);
+ if (options.isPrivate) {
+ transport.connectionFlags |= Ci.nsISocketTransport.NO_PERMANENT_STORAGE;
+ }
+ let input;
+ let output;
+
+ let deferred = Promise.defer();
+
+ let handler = {
+
+ onTransportStatus: function(unused, status) {
+ if (status === Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
+ output.asyncWait(handler, 0, 0, Services.tm.currentThread);
+ }
+ },
+
+ onInputStreamReady: function(streamReadyInput) {
+ try {
+ let data =
+ NetUtil.readInputStreamToString(streamReadyInput,
+ streamReadyInput.available());
+ equal(Cr.NS_OK, expectedResult, "Connection should succeed");
+ equal(data, "HELLO", "Echoed data received");
+ } catch (e) {
+ if (!((e.result == Cr.NS_ERROR_NET_RESET) && options.allowReset) &&
+ (e.result != expectedResult)) {
+ deferred.reject(e);
+ }
+ }
+ streamReadyInput.close();
+ output.close();
+ deferred.resolve();
+ },
+
+ onOutputStreamReady: function(streamReadyOutput) {
+ try {
+ try {
+ streamReadyOutput.write("HELLO", 5);
+ } catch (e) {
+ if (e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK) {
+ streamReadyOutput.asyncWait(handler, 0, 0, Services.tm.currentThread);
+ return;
+ }
+ if (e.result != Cr.NS_OK) {
+ ok((e.result === expectedResult) ||
+ (options.allowReset && (e.result === Cr.NS_ERROR_NET_RESET)),
+ "Actual and expected connection result should match");
+ streamReadyOutput.close();
+ deferred.resolve();
+ return;
+ }
+ }
+ do_print("Output to server written");
+ input = transport.openInputStream(0, 0, 0);
+ input.asyncWait(handler, 0, 0, Services.tm.currentThread);
+ } catch (e) {
+ deferred.reject(e);
+ }
+ }
+
+ };
+
+ transport.setEventSink(handler, Services.tm.currentThread);
+ output = transport.openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED, 0, 0);
+ output.QueryInterface(Ci.nsIAsyncOutputStream);
+
+ return deferred.promise;
+}
+
+function run_test() {
+ Services.prefs.setBoolPref("security.tls.unrestricted_rc4_fallback", false);
+ run_next_test();
+}
+
+// for sanity check
+add_task(function* () {
+ let cert = yield getCert();
+ ok(!!cert, "Got self-signed cert");
+ let port = startServer(cert, false);
+ storeCertOverride(port, cert);
+ yield startClient(port, Cr.NS_OK);
+ yield startClient(port, Cr.NS_OK, {isPrivate: true});
+});
+
+add_task(function* () {
+ let cert = yield getCert();
+ ok(!!cert, "Got self-signed cert");
+ let port = startServer(cert, true);
+ storeCertOverride(port, cert);
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {isPrivate: true});
+
+ weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", true);
+ // private browsing should not affect the permanent storage.
+ equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
+ "");
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
+ // The auto-retry on connection reset is implemented in our HTTP layer.
+ // So we will see the crafted NS_ERROR_NET_RESET when we use
+ // nsISocketTransport directly.
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {isPrivate: true, allowReset: true});
+ // retry manually to simulate the HTTP layer
+ yield startClient(port, Cr.NS_OK, {isPrivate: true});
+
+ weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, true);
+ equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
+ "");
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {isPrivate: true});
+
+ weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false, true);
+ // temporary override should not change the pref.
+ equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
+ "");
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {allowReset: true});
+ yield startClient(port, Cr.NS_OK);
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {isPrivate: true});
+
+ weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, false);
+ equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
+ "");
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {isPrivate: true});
+
+ weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false);
+ // permanent override should change the pref.
+ equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
+ "127.0.0.1");
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {allowReset: true});
+ yield startClient(port, Cr.NS_OK);
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {isPrivate: true});
+
+ weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, false);
+ equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
+ "");
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP));
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {isPrivate: true});
+
+ // add a host to the pref to prepare the next test
+ weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false);
+ yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP),
+ {allowReset: true});
+ yield startClient(port, Cr.NS_OK);
+ equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
+ "127.0.0.1");
+});
+
+add_task(function* () {
+ let cert = yield getCert();
+ ok(!!cert, "Got self-signed cert");
+ let port = startServer(cert, false);
+ storeCertOverride(port, cert);
+ yield startClient(port, Cr.NS_OK);
+ // Successful strong cipher will remove the host from the pref.
+ equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"),
+ "");
+});
diff --git a/security/manager/ssl/tests/unit/test_x509.js b/security/manager/ssl/tests/unit/test_x509.js
new file mode 100644
index 000000000..4c22e28d1
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_x509.js
@@ -0,0 +1,83 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests X509.jsm functionality.
+
+var { X509 } = Cu.import("resource://gre/modules/psm/X509.jsm", {});
+
+function stringToBytes(s) {
+ let b = [];
+ for (let i = 0; i < s.length; i++) {
+ b.push(s.charCodeAt(i));
+ }
+ return b;
+}
+
+function readPEMToBytes(filename) {
+ return stringToBytes(atob(pemToBase64(readFile(do_get_file(filename)))));
+}
+
+function run_test() {
+ let certificate = new X509.Certificate();
+ certificate.parse(readPEMToBytes("bad_certs/default-ee.pem"));
+
+ equal(certificate.tbsCertificate.version, 3,
+ "default-ee.pem should be x509v3");
+
+ // serialNumber
+ deepEqual(certificate.tbsCertificate.serialNumber,
+ [ 0x35, 0x1b, 0xe9, 0x3a, 0x1b, 0x03, 0x1c, 0x46, 0x1b, 0x45,
+ 0xfe, 0x9b, 0xb2, 0x20, 0x0f, 0x6e, 0xf2, 0x9e, 0xd9, 0x50 ],
+ "default-ee.pem should have expected serialNumber");
+
+ deepEqual(certificate.tbsCertificate.signature.algorithm._values,
+ [ 1, 2, 840, 113549, 1, 1, 11 ], // sha256WithRSAEncryption
+ "default-ee.pem should have sha256WithRSAEncryption signature");
+ // TODO: there should actually be an explicit encoded NULL here, but it looks
+ // like pycert doesn't include it.
+ deepEqual(certificate.tbsCertificate.signature.parameters, null,
+ "default-ee.pem should have NULL parameters for signature");
+
+ equal(certificate.tbsCertificate.issuer.rdns.length, 1,
+ "default-ee.pem should have one RDN in issuer");
+ equal(certificate.tbsCertificate.issuer.rdns[0].avas.length, 1,
+ "default-ee.pem should have one AVA in RDN in issuer");
+ deepEqual(certificate.tbsCertificate.issuer.rdns[0].avas[0].value.value,
+ stringToBytes("Test CA"),
+ "default-ee.pem should have issuer 'Test CA'");
+
+ equal(certificate.tbsCertificate.validity.notBefore.time.getTime(),
+ Date.parse("2015-11-28T00:00:00.000Z"),
+ "default-ee.pem should have the correct value for notBefore");
+ equal(certificate.tbsCertificate.validity.notAfter.time.getTime(),
+ Date.parse("2018-02-05T00:00:00.000Z"),
+ "default-ee.pem should have the correct value for notAfter");
+
+ equal(certificate.tbsCertificate.subject.rdns.length, 1,
+ "default-ee.pem should have one RDN in subject");
+ equal(certificate.tbsCertificate.subject.rdns[0].avas.length, 1,
+ "default-ee.pem should have one AVA in RDN in subject");
+ deepEqual(certificate.tbsCertificate.subject.rdns[0].avas[0].value.value,
+ stringToBytes("Test End-entity"),
+ "default-ee.pem should have subject 'Test End-entity'");
+
+ deepEqual(certificate.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm._values,
+ [ 1, 2, 840, 113549, 1, 1, 1 ], // rsaEncryption
+ "default-ee.pem should have a spki algorithm of rsaEncryption");
+
+ equal(certificate.tbsCertificate.extensions.length, 2,
+ "default-ee.pem should have two extensions");
+
+ deepEqual(certificate.signatureAlgorithm.algorithm._values,
+ [ 1, 2, 840, 113549, 1, 1, 11 ], // sha256WithRSAEncryption
+ "default-ee.pem should have sha256WithRSAEncryption signatureAlgorithm");
+ // TODO: there should actually be an explicit encoded NULL here, but it looks
+ // like pycert doesn't include it.
+ deepEqual(certificate.signatureAlgorithm.parameters, null,
+ "default-ee.pem should have NULL parameters for signatureAlgorithm");
+
+ equal(certificate.signatureValue.length, 2048 / 8,
+ "length of signature on default-ee.pem should be 2048 bits");
+}
diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp
new file mode 100644
index 000000000..348dcfc5c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp
@@ -0,0 +1,141 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This is a standalone server that uses various bad certificates.
+// The client is expected to connect, initiate an SSL handshake (with SNI
+// to indicate which "server" to connect to), and verify the certificate.
+// If all is good, the client then sends one encrypted byte and receives that
+// same byte back.
+// This server also has the ability to "call back" another process waiting on
+// it. That is, when the server is all set up and ready to receive connections,
+// it will connect to a specified port and issue a simple HTTP request.
+
+#include <stdio.h>
+
+#include "TLSServer.h"
+
+using namespace mozilla;
+using namespace mozilla::test;
+
+struct BadCertHost
+{
+ const char *mHostName;
+ const char *mCertName;
+};
+
+// Hostname, cert nickname pairs.
+const BadCertHost sBadCertHosts[] =
+{
+ { "expired.example.com", "expired-ee" },
+ { "notyetvalid.example.com", "notYetValid" },
+ { "before-epoch.example.com", "beforeEpoch" },
+ { "selfsigned.example.com", "selfsigned" },
+ { "unknownissuer.example.com", "unknownissuer" },
+ { "mismatch.example.com", "mismatch" },
+ { "mismatch-CN.example.com", "mismatchCN" },
+ { "expiredissuer.example.com", "expiredissuer" },
+ { "notyetvalidissuer.example.com", "notYetValidIssuer" },
+ { "before-epoch-issuer.example.com", "beforeEpochIssuer" },
+ { "md5signature.example.com", "md5signature" },
+ { "untrusted.example.com", "default-ee" },
+ { "untrustedissuer.example.com", "untrustedissuer" },
+ { "mismatch-expired.example.com", "mismatch-expired" },
+ { "mismatch-notYetValid.example.com", "mismatch-notYetValid" },
+ { "mismatch-untrusted.example.com", "mismatch-untrusted" },
+ { "untrusted-expired.example.com", "untrusted-expired" },
+ { "md5signature-expired.example.com", "md5signature-expired" },
+ { "mismatch-untrusted-expired.example.com", "mismatch-untrusted-expired" },
+ { "inadequatekeyusage.example.com", "inadequatekeyusage-ee" },
+ { "selfsigned-inadequateEKU.example.com", "selfsigned-inadequateEKU" },
+ { "self-signed-end-entity-with-cA-true.example.com", "self-signed-EE-with-cA-true" },
+ { "ca-used-as-end-entity.example.com", "ca-used-as-end-entity" },
+ { "ca-used-as-end-entity-name-mismatch.example.com", "ca-used-as-end-entity" },
+ // All of include-subdomains.pinning.example.com is pinned to End Entity
+ // Test Cert with nick default-ee. Any other nick will only
+ // pass pinning when security.cert_pinning.enforcement.level != strict and
+ // otherCA is added as a user-specified trust anchor. See StaticHPKPins.h.
+ { "include-subdomains.pinning.example.com", "default-ee" },
+ { "good.include-subdomains.pinning.example.com", "default-ee" },
+ { "bad.include-subdomains.pinning.example.com", "other-issuer-ee" },
+ { "bad.include-subdomains.pinning.example.com.", "other-issuer-ee" },
+ { "bad.include-subdomains.pinning.example.com..", "other-issuer-ee" },
+ { "exclude-subdomains.pinning.example.com", "default-ee" },
+ { "sub.exclude-subdomains.pinning.example.com", "other-issuer-ee" },
+ { "test-mode.pinning.example.com", "other-issuer-ee" },
+ { "unknownissuer.include-subdomains.pinning.example.com", "unknownissuer" },
+ { "unknownissuer.test-mode.pinning.example.com", "unknownissuer" },
+ { "nsCertTypeNotCritical.example.com", "nsCertTypeNotCritical" },
+ { "nsCertTypeCriticalWithExtKeyUsage.example.com", "nsCertTypeCriticalWithExtKeyUsage" },
+ { "nsCertTypeCritical.example.com", "nsCertTypeCritical" },
+ { "end-entity-issued-by-v1-cert.example.com", "eeIssuedByV1Cert" },
+ { "end-entity-issued-by-non-CA.example.com", "eeIssuedByNonCA" },
+ { "inadequate-key-size-ee.example.com", "inadequateKeySizeEE" },
+ { "badSubjectAltNames.example.com", "badSubjectAltNames" },
+ { "ipAddressAsDNSNameInSAN.example.com", "ipAddressAsDNSNameInSAN" },
+ { "noValidNames.example.com", "noValidNames" },
+ { "bug413909.xn--hxajbheg2az3al.xn--jxalpdlp", "idn-certificate" },
+ { "emptyissuername.example.com", "emptyIssuerName" },
+ { "ev-test.example.com", "ev-test" },
+ { nullptr, nullptr }
+};
+
+int32_t
+DoSNISocketConfigBySubjectCN(PRFileDesc* aFd, const SECItem* aSrvNameArr,
+ uint32_t aSrvNameArrSize)
+{
+ for (uint32_t i = 0; i < aSrvNameArrSize; i++) {
+ UniquePORTString name(
+ static_cast<char*>(PORT_ZAlloc(aSrvNameArr[i].len + 1)));
+ if (name) {
+ PORT_Memcpy(name.get(), aSrvNameArr[i].data, aSrvNameArr[i].len);
+ if (ConfigSecureServerWithNamedCert(aFd, name.get(), nullptr, nullptr)
+ == SECSuccess) {
+ return 0;
+ }
+ }
+ }
+
+ return SSL_SNI_SEND_ALERT;
+}
+
+int32_t
+DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
+ uint32_t aSrvNameArrSize, void* aArg)
+{
+ const BadCertHost* host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize,
+ sBadCertHosts);
+ if (!host) {
+ // No static cert <-> hostname mapping found. This happens when we use a
+ // collection of certificates in a given directory and build a cert DB at
+ // runtime, rather than using an NSS cert DB populated at build time.
+ // (This will be the default in the future.)
+ // For all given server names, check if the runtime-built cert DB contains
+ // a certificate with a matching subject CN.
+ return DoSNISocketConfigBySubjectCN(aFd, aSrvNameArr, aSrvNameArrSize);
+ }
+
+ if (gDebugLevel >= DEBUG_VERBOSE) {
+ fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName);
+ }
+
+ UniqueCERTCertificate cert;
+ SSLKEAType certKEA;
+ if (SECSuccess != ConfigSecureServerWithNamedCert(aFd, host->mCertName,
+ &cert, &certKEA)) {
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <NSS DB directory>\n", argv[0]);
+ return 1;
+ }
+
+ return StartServer(argv[1], DoSNISocketConfig, nullptr);
+}
diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp
new file mode 100644
index 000000000..775f1f06e
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 tw=80 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* This simple program takes a database directory, and one or more tuples like
+ * <typeOfResponse> <CertNick> <ExtraCertNick> <outPutFilename>
+ * to generate (one or more) ocsp responses.
+ */
+
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+#include "mozilla/ArrayUtils.h"
+
+#include "base64.h"
+#include "cert.h"
+#include "nspr.h"
+#include "nss.h"
+#include "plarenas.h"
+#include "prerror.h"
+#include "ssl.h"
+#include "secerr.h"
+
+#include "OCSPCommon.h"
+#include "ScopedNSSTypes.h"
+#include "TLSServer.h"
+
+using namespace mozilla;
+using namespace mozilla::test;
+
+struct OCSPResponseName
+{
+ const char *mTypeString;
+ const OCSPResponseType mORT;
+};
+
+const static OCSPResponseName kOCSPResponseNameList[] = {
+ { "good", ORTGood }, // the certificate is good
+ { "good-delegated", ORTDelegatedIncluded}, // the certificate is good, using
+ // a delegated signer
+ { "revoked", ORTRevoked}, // the certificate has been revoked
+ { "unknown", ORTUnknown}, // the responder doesn't know if the
+ // cert is good
+ { "goodotherca", ORTGoodOtherCA}, // the wrong CA has signed the
+ // response
+ { "expiredresponse", ORTExpired}, // the signature on the response has
+ // expired
+ { "oldvalidperiod", ORTExpiredFreshCA}, // fresh signature, but old validity
+ // period
+ { "empty", ORTEmpty}, // an empty stapled response
+
+ { "malformed", ORTMalformed}, // the response from the responder
+ // was malformed
+ { "serverr", ORTSrverr}, // the response indicates there was a
+ // server error
+ { "trylater", ORTTryLater}, // the responder replied with
+ // "try again later"
+ { "resp-unsigned", ORTNeedsSig}, // the response needs a signature
+ { "unauthorized", ORTUnauthorized}, // the responder does not know about
+ // the cert
+ { "bad-signature", ORTBadSignature}, // the response has a bad signature
+ { "longvalidityalmostold", ORTLongValidityAlmostExpired}, // the response is
+ // still valid, but the generation
+ // is almost a year old
+ { "ancientstillvalid", ORTAncientAlmostExpired}, // The response is still
+ // valid but the generation is almost
+ // two years old
+};
+
+bool
+StringToOCSPResponseType(const char* respText,
+ /*out*/ OCSPResponseType* OCSPType)
+{
+ if (!OCSPType) {
+ return false;
+ }
+ for (uint32_t i = 0; i < mozilla::ArrayLength(kOCSPResponseNameList); i++) {
+ if (strcmp(respText, kOCSPResponseNameList[i].mTypeString) == 0) {
+ *OCSPType = kOCSPResponseNameList[i].mORT;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+WriteResponse(const char* filename, const SECItem* item)
+{
+ if (!filename || !item || !item->data) {
+ PR_fprintf(PR_STDERR, "invalid parameters to WriteResponse");
+ return false;
+ }
+
+ UniquePRFileDesc outFile(PR_Open(filename,
+ PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
+ 0644));
+ if (!outFile) {
+ PrintPRError("cannot open file for writing");
+ return false;
+ }
+ int32_t rv = PR_Write(outFile.get(), item->data, item->len);
+ if (rv < 0 || (uint32_t) rv != item->len) {
+ PrintPRError("File write failure");
+ return false;
+ }
+
+ return true;
+}
+
+int
+main(int argc, char* argv[])
+{
+
+ if (argc < 6 || (argc - 6) % 4 != 0) {
+ PR_fprintf(PR_STDERR, "usage: %s <NSS DB directory> <responsetype> "
+ "<cert_nick> <extranick> <outfilename> [<resptype> "
+ "<cert_nick> <extranick> <outfilename>]* \n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ SECStatus rv = InitializeNSS(argv[1]);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed to initialize NSS\n");
+ exit(EXIT_FAILURE);
+ }
+ UniquePLArenaPool arena(PORT_NewArena(256 * argc));
+ if (!arena) {
+ PrintPRError("PORT_NewArena failed");
+ exit(EXIT_FAILURE);
+ }
+
+ for (int i = 2; i + 3 < argc; i += 4) {
+ const char* ocspTypeText = argv[i];
+ const char* certNick = argv[i + 1];
+ const char* extraCertname = argv[i + 2];
+ const char* filename = argv[i + 3];
+
+ OCSPResponseType ORT;
+ if (!StringToOCSPResponseType(ocspTypeText, &ORT)) {
+ PR_fprintf(PR_STDERR, "Cannot generate OCSP response of type %s\n",
+ ocspTypeText);
+ exit(EXIT_FAILURE);
+ }
+
+ UniqueCERTCertificate cert(PK11_FindCertFromNickname(certNick, nullptr));
+ if (!cert) {
+ PrintPRError("PK11_FindCertFromNickname failed");
+ PR_fprintf(PR_STDERR, "Failed to find certificate with nick '%s'\n",
+ certNick);
+ exit(EXIT_FAILURE);
+ }
+
+ SECItemArray* response = GetOCSPResponseForType(ORT, cert, arena,
+ extraCertname);
+ if (!response) {
+ PR_fprintf(PR_STDERR, "Failed to generate OCSP response of type %s "
+ "for %s\n", ocspTypeText, certNick);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!WriteResponse(filename, &response->items[0])) {
+ PR_fprintf(PR_STDERR, "Failed to write file %s\n", filename);
+ exit(EXIT_FAILURE);
+ }
+ }
+ return 0;
+}
diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp
new file mode 100644
index 000000000..6bf33a143
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp
@@ -0,0 +1,129 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This is a standalone server that delivers various stapled OCSP responses.
+// The client is expected to connect, initiate an SSL handshake (with SNI
+// to indicate which "server" to connect to), and verify the OCSP response.
+// If all is good, the client then sends one encrypted byte and receives that
+// same byte back.
+// This server also has the ability to "call back" another process waiting on
+// it. That is, when the server is all set up and ready to receive connections,
+// it will connect to a specified port and issue a simple HTTP request.
+
+#include <stdio.h>
+
+#include "OCSPCommon.h"
+#include "TLSServer.h"
+
+using namespace mozilla;
+using namespace mozilla::test;
+
+const OCSPHost sOCSPHosts[] =
+{
+ { "ocsp-stapling-good.example.com", ORTGood, nullptr, nullptr },
+ { "ocsp-stapling-revoked.example.com", ORTRevoked, nullptr, nullptr },
+ { "ocsp-stapling-revoked-old.example.com", ORTRevokedOld, nullptr, nullptr },
+ { "ocsp-stapling-unknown.example.com", ORTUnknown, nullptr, nullptr },
+ { "ocsp-stapling-unknown-old.example.com", ORTUnknownOld, nullptr, nullptr },
+ { "ocsp-stapling-good-other.example.com", ORTGoodOtherCert, "ocspOtherEndEntity", nullptr },
+ { "ocsp-stapling-good-other-ca.example.com", ORTGoodOtherCA, "other-test-ca", nullptr },
+ { "ocsp-stapling-expired.example.com", ORTExpired, nullptr, nullptr },
+ { "ocsp-stapling-expired-fresh-ca.example.com", ORTExpiredFreshCA, nullptr, nullptr },
+ { "ocsp-stapling-none.example.com", ORTNone, nullptr, nullptr },
+ { "ocsp-stapling-empty.example.com", ORTEmpty, nullptr, nullptr },
+ { "ocsp-stapling-malformed.example.com", ORTMalformed, nullptr, nullptr },
+ { "ocsp-stapling-srverr.example.com", ORTSrverr, nullptr, nullptr },
+ { "ocsp-stapling-trylater.example.com", ORTTryLater, nullptr, nullptr },
+ { "ocsp-stapling-needssig.example.com", ORTNeedsSig, nullptr, nullptr },
+ { "ocsp-stapling-unauthorized.example.com", ORTUnauthorized, nullptr, nullptr },
+ { "ocsp-stapling-with-intermediate.example.com", ORTGood, nullptr, "ocspEEWithIntermediate" },
+ { "ocsp-stapling-bad-signature.example.com", ORTBadSignature, nullptr, nullptr },
+ { "ocsp-stapling-skip-responseBytes.example.com", ORTSkipResponseBytes, nullptr, nullptr },
+ { "ocsp-stapling-critical-extension.example.com", ORTCriticalExtension, nullptr, nullptr },
+ { "ocsp-stapling-noncritical-extension.example.com", ORTNoncriticalExtension, nullptr, nullptr },
+ { "ocsp-stapling-empty-extensions.example.com", ORTEmptyExtensions, nullptr, nullptr },
+ { "ocsp-stapling-delegated-included.example.com", ORTDelegatedIncluded, "delegatedSigner", nullptr },
+ { "ocsp-stapling-delegated-included-last.example.com", ORTDelegatedIncludedLast, "delegatedSigner", nullptr },
+ { "ocsp-stapling-delegated-missing.example.com", ORTDelegatedMissing, "delegatedSigner", nullptr },
+ { "ocsp-stapling-delegated-missing-multiple.example.com", ORTDelegatedMissingMultiple, "delegatedSigner", nullptr },
+ { "ocsp-stapling-delegated-no-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerNoExtKeyUsage", nullptr },
+ { "ocsp-stapling-delegated-from-intermediate.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerFromIntermediate", nullptr },
+ { "ocsp-stapling-delegated-keyUsage-crlSigning.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerKeyUsageCrlSigning", nullptr },
+ { "ocsp-stapling-delegated-wrong-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerWrongExtKeyUsage", nullptr },
+ { "ocsp-stapling-ancient-valid.example.com", ORTAncientAlmostExpired, nullptr, nullptr },
+ { "keysize-ocsp-delegated.example.com", ORTDelegatedIncluded, "rsa-1016-keysizeDelegatedSigner", nullptr },
+ { "revoked-ca-cert-used-as-end-entity.example.com", ORTRevoked, "ca-used-as-end-entity", nullptr },
+ { "ocsp-stapling-must-staple.example.com", ORTGood, nullptr, "must-staple-ee" },
+ { "ocsp-stapling-must-staple-revoked.example.com", ORTRevoked, nullptr, "must-staple-ee" },
+ { "ocsp-stapling-must-staple-missing.example.com", ORTNone, nullptr, "must-staple-ee" },
+ { "ocsp-stapling-must-staple-empty.example.com", ORTEmpty, nullptr, "must-staple-ee" },
+ { "ocsp-stapling-must-staple-ee-with-must-staple-int.example.com", ORTGood, nullptr, "must-staple-ee-with-must-staple-int" },
+ { "ocsp-stapling-plain-ee-with-must-staple-int.example.com", ORTGood, nullptr, "must-staple-missing-ee" },
+ { "multi-tls-feature-good.example.com", ORTNone, nullptr, "multi-tls-feature-good-ee" },
+ { "multi-tls-feature-bad.example.com", ORTNone, nullptr, "multi-tls-feature-bad-ee" },
+ { nullptr, ORTNull, nullptr, nullptr }
+};
+
+int32_t
+DoSNISocketConfig(PRFileDesc *aFd, const SECItem *aSrvNameArr,
+ uint32_t aSrvNameArrSize, void *aArg)
+{
+ const OCSPHost *host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize,
+ sOCSPHosts);
+ if (!host) {
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ if (gDebugLevel >= DEBUG_VERBOSE) {
+ fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName);
+ }
+
+ const char *certNickname = host->mServerCertName ? host->mServerCertName
+ : DEFAULT_CERT_NICKNAME;
+
+ UniqueCERTCertificate cert;
+ SSLKEAType certKEA;
+ if (SECSuccess != ConfigSecureServerWithNamedCert(aFd, certNickname,
+ &cert, &certKEA)) {
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ // If the OCSP response type is "none", don't staple a response.
+ if (host->mORT == ORTNone) {
+ return 0;
+ }
+
+ UniquePLArenaPool arena(PORT_NewArena(1024));
+ if (!arena) {
+ PrintPRError("PORT_NewArena failed");
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ // response is contained by the arena - freeing the arena will free it
+ SECItemArray *response = GetOCSPResponseForType(host->mORT, cert, arena,
+ host->mAdditionalCertName);
+ if (!response) {
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ // SSL_SetStapledOCSPResponses makes a deep copy of response
+ SECStatus st = SSL_SetStapledOCSPResponses(aFd, response, certKEA);
+ if (st != SECSuccess) {
+ PrintPRError("SSL_SetStapledOCSPResponses failed");
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <NSS DB directory>\n", argv[0]);
+ return 1;
+ }
+
+ return StartServer(argv[1], DoSNISocketConfig, nullptr);
+}
diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/moz.build b/security/manager/ssl/tests/unit/tlsserver/cmd/moz.build
new file mode 100644
index 000000000..6fdd0c35b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/moz.build
@@ -0,0 +1,25 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+GeckoSimplePrograms([
+ 'BadCertServer',
+ 'GenerateOCSPResponse',
+ 'OCSPStaplingServer',
+], linkage=None)
+
+LOCAL_INCLUDES += [
+ '../lib',
+]
+
+USE_LIBS += [
+ 'mozillapkix',
+ 'nspr',
+ 'nss',
+ 'pkixtestutil',
+ 'tlsserver',
+]
+
+CXXFLAGS += CONFIG['TK_CFLAGS']
diff --git a/security/manager/ssl/tests/unit/tlsserver/default-ee.der b/security/manager/ssl/tests/unit/tlsserver/default-ee.der
new file mode 100644
index 000000000..3a9b8fa9b
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/default-ee.der
@@ -0,0 +1,3 @@
+This is now an unused file. It exists to ease the coordination between gecko
+development trees and the automation infrastructure that runs periodic updates.
+See bug 1203312 and bug 1205406.
diff --git a/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.cpp b/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.cpp
new file mode 100644
index 000000000..5c99edade
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.cpp
@@ -0,0 +1,215 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "OCSPCommon.h"
+
+#include <stdio.h>
+
+#include "pkixtestutil.h"
+#include "TLSServer.h"
+#include "secder.h"
+#include "secerr.h"
+
+namespace mozilla { namespace pkix { namespace test {
+
+// Ownership of privateKey is transfered.
+TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
+ const SECKEYPublicKey& publicKey,
+ SECKEYPrivateKey* privateKey);
+
+} } } // namespace mozilla::pkix::test
+
+using namespace mozilla;
+using namespace mozilla::pkix;
+using namespace mozilla::pkix::test;
+using namespace mozilla::test;
+
+static TestKeyPair*
+CreateTestKeyPairFromCert(const UniqueCERTCertificate& cert)
+{
+ UniqueSECKEYPrivateKey privateKey(PK11_FindKeyByAnyCert(cert.get(), nullptr));
+ if (!privateKey) {
+ return nullptr;
+ }
+ UniqueSECKEYPublicKey publicKey(CERT_ExtractPublicKey(cert.get()));
+ if (!publicKey) {
+ return nullptr;
+ }
+ return CreateTestKeyPair(RSA_PKCS1(), *publicKey.get(), privateKey.release());
+}
+
+SECItemArray*
+GetOCSPResponseForType(OCSPResponseType aORT, const UniqueCERTCertificate& aCert,
+ const UniquePLArenaPool& aArena,
+ const char* aAdditionalCertName)
+{
+ MOZ_ASSERT(aArena);
+ MOZ_ASSERT(aCert);
+ // Note: |aAdditionalCertName| may or may not need to be non-null depending
+ // on the |aORT| value given.
+
+ if (aORT == ORTNone) {
+ if (gDebugLevel >= DEBUG_WARNINGS) {
+ fprintf(stderr, "GetOCSPResponseForType called with type ORTNone, "
+ "which makes no sense.\n");
+ }
+ return nullptr;
+ }
+
+ if (aORT == ORTEmpty) {
+ SECItemArray* arr = SECITEM_AllocArray(aArena.get(), nullptr, 1);
+ arr->items[0].data = nullptr;
+ arr->items[0].len = 0;
+ return arr;
+ }
+
+ time_t now = time(nullptr);
+ time_t oldNow = now - (8 * Time::ONE_DAY_IN_SECONDS);
+
+ mozilla::UniqueCERTCertificate cert(CERT_DupCertificate(aCert.get()));
+
+ if (aORT == ORTGoodOtherCert) {
+ cert.reset(PK11_FindCertFromNickname(aAdditionalCertName, nullptr));
+ if (!cert) {
+ PrintPRError("PK11_FindCertFromNickname failed");
+ return nullptr;
+ }
+ }
+ // XXX CERT_FindCertIssuer uses the old, deprecated path-building logic
+ mozilla::UniqueCERTCertificate
+ issuerCert(CERT_FindCertIssuer(aCert.get(), PR_Now(), certUsageSSLCA));
+ if (!issuerCert) {
+ PrintPRError("CERT_FindCertIssuer failed");
+ return nullptr;
+ }
+ Input issuer;
+ if (issuer.Init(cert->derIssuer.data, cert->derIssuer.len) != Success) {
+ return nullptr;
+ }
+ Input issuerPublicKey;
+ if (issuerPublicKey.Init(issuerCert->derPublicKey.data,
+ issuerCert->derPublicKey.len) != Success) {
+ return nullptr;
+ }
+ Input serialNumber;
+ if (serialNumber.Init(cert->serialNumber.data,
+ cert->serialNumber.len) != Success) {
+ return nullptr;
+ }
+ CertID certID(issuer, issuerPublicKey, serialNumber);
+ OCSPResponseContext context(certID, now);
+
+ mozilla::UniqueCERTCertificate signerCert;
+ if (aORT == ORTGoodOtherCA || aORT == ORTDelegatedIncluded ||
+ aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissing ||
+ aORT == ORTDelegatedMissingMultiple) {
+ signerCert.reset(PK11_FindCertFromNickname(aAdditionalCertName, nullptr));
+ if (!signerCert) {
+ PrintPRError("PK11_FindCertFromNickname failed");
+ return nullptr;
+ }
+ }
+
+ ByteString certs[5];
+
+ if (aORT == ORTDelegatedIncluded) {
+ certs[0].assign(signerCert->derCert.data, signerCert->derCert.len);
+ context.certs = certs;
+ }
+ if (aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissingMultiple) {
+ certs[0].assign(issuerCert->derCert.data, issuerCert->derCert.len);
+ certs[1].assign(cert->derCert.data, cert->derCert.len);
+ certs[2].assign(issuerCert->derCert.data, issuerCert->derCert.len);
+ if (aORT != ORTDelegatedMissingMultiple) {
+ certs[3].assign(signerCert->derCert.data, signerCert->derCert.len);
+ }
+ context.certs = certs;
+ }
+
+ switch (aORT) {
+ case ORTMalformed:
+ context.responseStatus = 1;
+ break;
+ case ORTSrverr:
+ context.responseStatus = 2;
+ break;
+ case ORTTryLater:
+ context.responseStatus = 3;
+ break;
+ case ORTNeedsSig:
+ context.responseStatus = 5;
+ break;
+ case ORTUnauthorized:
+ context.responseStatus = 6;
+ break;
+ default:
+ // context.responseStatus is 0 in all other cases, and it has
+ // already been initialized in the constructor.
+ break;
+ }
+ if (aORT == ORTSkipResponseBytes) {
+ context.skipResponseBytes = true;
+ }
+ if (aORT == ORTExpired || aORT == ORTExpiredFreshCA ||
+ aORT == ORTRevokedOld || aORT == ORTUnknownOld) {
+ context.thisUpdate = oldNow;
+ context.nextUpdate = oldNow + Time::ONE_DAY_IN_SECONDS;
+ }
+ if (aORT == ORTLongValidityAlmostExpired) {
+ context.thisUpdate = now - (320 * Time::ONE_DAY_IN_SECONDS);
+ }
+ if (aORT == ORTAncientAlmostExpired) {
+ context.thisUpdate = now - (640 * Time::ONE_DAY_IN_SECONDS);
+ }
+ if (aORT == ORTRevoked || aORT == ORTRevokedOld) {
+ context.certStatus = 1;
+ }
+ if (aORT == ORTUnknown || aORT == ORTUnknownOld) {
+ context.certStatus = 2;
+ }
+ if (aORT == ORTBadSignature) {
+ context.badSignature = true;
+ }
+ OCSPResponseExtension extension;
+ if (aORT == ORTCriticalExtension || aORT == ORTNoncriticalExtension) {
+ // python DottedOIDToCode.py --tlv some-Mozilla-OID 1.3.6.1.4.1.13769.666.666.666.1.500.9.2
+ static const uint8_t tlv_some_Mozilla_OID[] = {
+ 0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85,
+ 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x02
+ };
+
+ extension.id.assign(tlv_some_Mozilla_OID, sizeof(tlv_some_Mozilla_OID));
+ extension.critical = (aORT == ORTCriticalExtension);
+ extension.value.push_back(0x05); // tag: NULL
+ extension.value.push_back(0x00); // length: 0
+ extension.next = nullptr;
+ context.responseExtensions = &extension;
+ }
+ if (aORT == ORTEmptyExtensions) {
+ context.includeEmptyExtensions = true;
+ }
+
+ if (!signerCert) {
+ signerCert.reset(CERT_DupCertificate(issuerCert.get()));
+ }
+ context.signerKeyPair.reset(CreateTestKeyPairFromCert(signerCert));
+ if (!context.signerKeyPair) {
+ PrintPRError("PK11_FindKeyByAnyCert failed");
+ return nullptr;
+ }
+
+ ByteString response(CreateEncodedOCSPResponse(context));
+ if (ENCODING_FAILED(response)) {
+ PrintPRError("CreateEncodedOCSPResponse failed");
+ return nullptr;
+ }
+
+ SECItem item = {
+ siBuffer,
+ const_cast<uint8_t*>(response.data()),
+ static_cast<unsigned int>(response.length())
+ };
+ SECItemArray arr = { &item, 1 };
+ return SECITEM_DupArray(aArena.get(), &arr);
+}
diff --git a/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.h b/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.h
new file mode 100644
index 000000000..5a88d6e52
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.h
@@ -0,0 +1,61 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Implements generating OCSP responses of various types. Used by the
+// programs in tlsserver/cmd.
+
+#ifndef OCSPCommon_h
+#define OCSPCommon_h
+
+#include "ScopedNSSTypes.h"
+#include "certt.h"
+#include "seccomon.h"
+
+enum OCSPResponseType
+{
+ ORTNull = 0,
+ ORTGood, // the certificate is good
+ ORTRevoked, // the certificate has been revoked
+ ORTRevokedOld, // same, but the response is old
+ ORTUnknown, // the responder doesn't know if the cert is good
+ ORTUnknownOld, // same, but the response is old
+ ORTGoodOtherCert, // the response references a different certificate
+ ORTGoodOtherCA, // the wrong CA has signed the response
+ ORTExpired, // the signature on the response has expired
+ ORTExpiredFreshCA, // fresh signature, but old validity period
+ ORTNone, // no stapled response
+ ORTEmpty, // an empty stapled response
+ ORTMalformed, // the response from the responder was malformed
+ ORTSrverr, // the response indicates there was a server error
+ ORTTryLater, // the responder replied with "try again later"
+ ORTNeedsSig, // the response needs a signature
+ ORTUnauthorized, // the responder is not authorized for this certificate
+ ORTBadSignature, // the response has a signature that does not verify
+ ORTSkipResponseBytes, // the response does not include responseBytes
+ ORTCriticalExtension, // the response includes a critical extension
+ ORTNoncriticalExtension, // the response includes an extension that is not critical
+ ORTEmptyExtensions, // the response includes a SEQUENCE OF Extension that is empty
+ ORTDelegatedIncluded, // the response is signed by an included delegated responder
+ ORTDelegatedIncludedLast, // same, but multiple other certificates are included
+ ORTDelegatedMissing, // the response is signed by a not included delegated responder
+ ORTDelegatedMissingMultiple, // same, but multiple other certificates are included
+ ORTLongValidityAlmostExpired, // a good response, but that was generated a almost a year ago
+ ORTAncientAlmostExpired, // a good response, with a validity of almost two years almost expiring
+};
+
+struct OCSPHost
+{
+ const char *mHostName;
+ OCSPResponseType mORT;
+ const char *mAdditionalCertName; // useful for ORTGoodOtherCert, etc.
+ const char *mServerCertName;
+};
+
+SECItemArray*
+GetOCSPResponseForType(OCSPResponseType aORT,
+ const mozilla::UniqueCERTCertificate& aCert,
+ const mozilla::UniquePLArenaPool& aArena,
+ const char* aAdditionalCertName);
+
+#endif // OCSPCommon_h
diff --git a/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp
new file mode 100644
index 000000000..fcf6aa951
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp
@@ -0,0 +1,600 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TLSServer.h"
+
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+#include "base64.h"
+#include "mozilla/Move.h"
+#include "mozilla/Sprintf.h"
+#include "nspr.h"
+#include "nss.h"
+#include "plarenas.h"
+#include "prenv.h"
+#include "prerror.h"
+#include "prnetdb.h"
+#include "prtime.h"
+#include "ssl.h"
+
+namespace mozilla { namespace test {
+
+static const uint16_t LISTEN_PORT = 8443;
+
+DebugLevel gDebugLevel = DEBUG_ERRORS;
+uint16_t gCallbackPort = 0;
+
+const char DEFAULT_CERT_NICKNAME[] = "default-ee";
+
+struct Connection
+{
+ PRFileDesc *mSocket;
+ char mByte;
+
+ explicit Connection(PRFileDesc *aSocket);
+ ~Connection();
+};
+
+Connection::Connection(PRFileDesc *aSocket)
+: mSocket(aSocket)
+, mByte(0)
+{}
+
+Connection::~Connection()
+{
+ if (mSocket) {
+ PR_Close(mSocket);
+ }
+}
+
+void
+PrintPRError(const char *aPrefix)
+{
+ const char *err = PR_ErrorToName(PR_GetError());
+ if (err) {
+ if (gDebugLevel >= DEBUG_ERRORS) {
+ fprintf(stderr, "%s: %s\n", aPrefix, err);
+ }
+ } else {
+ if (gDebugLevel >= DEBUG_ERRORS) {
+ fprintf(stderr, "%s\n", aPrefix);
+ }
+ }
+}
+
+template <size_t N>
+SECStatus
+ReadFileToBuffer(const char* basePath, const char* filename, char (&buf)[N])
+{
+ static_assert(N > 0, "input buffer too small for ReadFileToBuffer");
+ if (snprintf(buf, N - 1, "%s/%s", basePath, filename) == 0) {
+ PrintPRError("snprintf failed");
+ return SECFailure;
+ }
+ UniquePRFileDesc fd(PR_OpenFile(buf, PR_RDONLY, 0));
+ if (!fd) {
+ PrintPRError("PR_Open failed");
+ return SECFailure;
+ }
+ int32_t fileSize = PR_Available(fd.get());
+ if (fileSize < 0) {
+ PrintPRError("PR_Available failed");
+ return SECFailure;
+ }
+ if (static_cast<size_t>(fileSize) > N - 1) {
+ PR_fprintf(PR_STDERR, "file too large - not reading\n");
+ return SECFailure;
+ }
+ int32_t bytesRead = PR_Read(fd.get(), buf, fileSize);
+ if (bytesRead != fileSize) {
+ PrintPRError("PR_Read failed");
+ return SECFailure;
+ }
+ buf[bytesRead] = 0;
+ return SECSuccess;
+}
+
+SECStatus
+AddKeyFromFile(const char* basePath, const char* filename)
+{
+ const char* PRIVATE_KEY_HEADER = "-----BEGIN PRIVATE KEY-----";
+ const char* PRIVATE_KEY_FOOTER = "-----END PRIVATE KEY-----";
+
+ char buf[16384] = { 0 };
+ SECStatus rv = ReadFileToBuffer(basePath, filename, buf);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ if (strncmp(buf, PRIVATE_KEY_HEADER, strlen(PRIVATE_KEY_HEADER)) != 0) {
+ PR_fprintf(PR_STDERR, "invalid key - not importing\n");
+ return SECFailure;
+ }
+ const char* bufPtr = buf + strlen(PRIVATE_KEY_HEADER);
+ size_t bufLen = strlen(buf);
+ char base64[16384] = { 0 };
+ char* base64Ptr = base64;
+ while (bufPtr < buf + bufLen) {
+ if (strncmp(bufPtr, PRIVATE_KEY_FOOTER, strlen(PRIVATE_KEY_FOOTER)) == 0) {
+ break;
+ }
+ if (*bufPtr != '\r' && *bufPtr != '\n') {
+ *base64Ptr = *bufPtr;
+ base64Ptr++;
+ }
+ bufPtr++;
+ }
+
+ unsigned int binLength;
+ UniquePORTString bin(
+ BitwiseCast<char*, unsigned char*>(ATOB_AsciiToData(base64, &binLength)));
+ if (!bin || binLength == 0) {
+ PrintPRError("ATOB_AsciiToData failed");
+ return SECFailure;
+ }
+ UniqueSECItem secitem(::SECITEM_AllocItem(nullptr, nullptr, binLength));
+ if (!secitem) {
+ PrintPRError("SECITEM_AllocItem failed");
+ return SECFailure;
+ }
+ PORT_Memcpy(secitem->data, bin.get(), binLength);
+ UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
+ if (!slot) {
+ PrintPRError("PK11_GetInternalKeySlot failed");
+ return SECFailure;
+ }
+ if (PK11_NeedUserInit(slot.get())) {
+ if (PK11_InitPin(slot.get(), nullptr, nullptr) != SECSuccess) {
+ PrintPRError("PK11_InitPin failed");
+ return SECFailure;
+ }
+ }
+ SECKEYPrivateKey* privateKey;
+ if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(), secitem.get(),
+ nullptr, nullptr, true, false,
+ KU_ALL, &privateKey, nullptr)
+ != SECSuccess) {
+ PrintPRError("PK11_ImportDERPrivateKeyInfoAndReturnKey failed");
+ return SECFailure;
+ }
+ SECKEY_DestroyPrivateKey(privateKey);
+ return SECSuccess;
+}
+
+SECStatus
+DecodeCertCallback(void* arg, SECItem** certs, int numcerts)
+{
+ if (numcerts != 1) {
+ PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
+ return SECFailure;
+ }
+
+ SECItem* certDEROut = static_cast<SECItem*>(arg);
+ return SECITEM_CopyItem(nullptr, certDEROut, *certs);
+}
+
+SECStatus
+AddCertificateFromFile(const char* basePath, const char* filename)
+{
+ char buf[16384] = { 0 };
+ SECStatus rv = ReadFileToBuffer(basePath, filename, buf);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ ScopedAutoSECItem certDER;
+ rv = CERT_DecodeCertPackage(buf, strlen(buf), DecodeCertCallback, &certDER);
+ if (rv != SECSuccess) {
+ PrintPRError("CERT_DecodeCertPackage failed");
+ return rv;
+ }
+ UniqueCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
+ &certDER, nullptr, false,
+ true));
+ if (!cert) {
+ PrintPRError("CERT_NewTempCertificate failed");
+ return SECFailure;
+ }
+ UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
+ if (!slot) {
+ PrintPRError("PK11_GetInternalKeySlot failed");
+ return SECFailure;
+ }
+ // The nickname is the filename without '.pem'.
+ std::string nickname(filename, strlen(filename) - 4);
+ rv = PK11_ImportCert(slot.get(), cert.get(), CK_INVALID_HANDLE,
+ nickname.c_str(), false);
+ if (rv != SECSuccess) {
+ PrintPRError("PK11_ImportCert failed");
+ return rv;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+LoadCertificatesAndKeys(const char* basePath)
+{
+ // The NSS cert DB path could have been specified as "sql:path". Trim off
+ // the leading "sql:" if so.
+ if (strncmp(basePath, "sql:", 4) == 0) {
+ basePath = basePath + 4;
+ }
+
+ UniquePRDir fdDir(PR_OpenDir(basePath));
+ if (!fdDir) {
+ PrintPRError("PR_OpenDir failed");
+ return SECFailure;
+ }
+ // On the B2G ICS emulator, operations taken in AddCertificateFromFile
+ // appear to interact poorly with readdir (more specifically, something is
+ // causing readdir to never return null - it indefinitely loops through every
+ // file in the directory, which causes timeouts). Rather than waste more time
+ // chasing this down, loading certificates and keys happens in two phases:
+ // filename collection and then loading. (This is probably a good
+ // idea anyway because readdir isn't reentrant. Something could change later
+ // such that it gets called as a result of calling AddCertificateFromFile or
+ // AddKeyFromFile.)
+ std::vector<std::string> certificates;
+ std::vector<std::string> keys;
+ for (PRDirEntry* dirEntry = PR_ReadDir(fdDir.get(), PR_SKIP_BOTH); dirEntry;
+ dirEntry = PR_ReadDir(fdDir.get(), PR_SKIP_BOTH)) {
+ size_t nameLength = strlen(dirEntry->name);
+ if (nameLength > 4) {
+ if (strncmp(dirEntry->name + nameLength - 4, ".pem", 4) == 0) {
+ certificates.push_back(dirEntry->name);
+ } else if (strncmp(dirEntry->name + nameLength - 4, ".key", 4) == 0) {
+ keys.push_back(dirEntry->name);
+ }
+ }
+ }
+ SECStatus rv;
+ for (std::string& certificate : certificates) {
+ rv = AddCertificateFromFile(basePath, certificate.c_str());
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ for (std::string& key : keys) {
+ rv = AddKeyFromFile(basePath, key.c_str());
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ return SECSuccess;
+}
+
+SECStatus
+InitializeNSS(const char* nssCertDBDir)
+{
+ // Try initializing an existing DB.
+ if (NSS_Init(nssCertDBDir) == SECSuccess) {
+ return SECSuccess;
+ }
+
+ // Create a new DB if there is none...
+ SECStatus rv = NSS_Initialize(nssCertDBDir, nullptr, nullptr, nullptr, 0);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ // ...and load all certificates into it.
+ return LoadCertificatesAndKeys(nssCertDBDir);
+}
+
+nsresult
+SendAll(PRFileDesc *aSocket, const char *aData, size_t aDataLen)
+{
+ if (gDebugLevel >= DEBUG_VERBOSE) {
+ fprintf(stderr, "sending '%s'\n", aData);
+ }
+
+ while (aDataLen > 0) {
+ int32_t bytesSent = PR_Send(aSocket, aData, aDataLen, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesSent == -1) {
+ PrintPRError("PR_Send failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ aDataLen -= bytesSent;
+ aData += bytesSent;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+ReplyToRequest(Connection *aConn)
+{
+ // For debugging purposes, SendAll can print out what it's sending.
+ // So, any strings we give to it to send need to be null-terminated.
+ char buf[2] = { aConn->mByte, 0 };
+ return SendAll(aConn->mSocket, buf, 1);
+}
+
+nsresult
+SetupTLS(Connection *aConn, PRFileDesc *aModelSocket)
+{
+ PRFileDesc *sslSocket = SSL_ImportFD(aModelSocket, aConn->mSocket);
+ if (!sslSocket) {
+ PrintPRError("SSL_ImportFD failed");
+ return NS_ERROR_FAILURE;
+ }
+ aConn->mSocket = sslSocket;
+
+ SSL_OptionSet(sslSocket, SSL_SECURITY, true);
+ SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, false);
+ SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_SERVER, true);
+
+ SSL_ResetHandshake(sslSocket, /* asServer */ 1);
+
+ return NS_OK;
+}
+
+nsresult
+ReadRequest(Connection *aConn)
+{
+ int32_t bytesRead = PR_Recv(aConn->mSocket, &aConn->mByte, 1, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesRead < 0) {
+ PrintPRError("PR_Recv failed");
+ return NS_ERROR_FAILURE;
+ } else if (bytesRead == 0) {
+ PR_SetError(PR_IO_ERROR, 0);
+ PrintPRError("PR_Recv EOF in ReadRequest");
+ return NS_ERROR_FAILURE;
+ } else {
+ if (gDebugLevel >= DEBUG_VERBOSE) {
+ fprintf(stderr, "read '0x%hhx'\n", aConn->mByte);
+ }
+ }
+ return NS_OK;
+}
+
+void
+HandleConnection(PRFileDesc* aSocket, const UniquePRFileDesc& aModelSocket)
+{
+ Connection conn(aSocket);
+ nsresult rv = SetupTLS(&conn, aModelSocket.get());
+ if (NS_FAILED(rv)) {
+ PR_SetError(PR_INVALID_STATE_ERROR, 0);
+ PrintPRError("PR_Recv failed");
+ exit(1);
+ }
+
+ // TODO: On tests that are expected to fail (e.g. due to a revoked
+ // certificate), the client will close the connection wtihout sending us the
+ // request byte. In those cases, we should keep going. But, in the cases
+ // where the connection is supposed to suceed, we should verify that we
+ // successfully receive the request and send the response.
+ rv = ReadRequest(&conn);
+ if (NS_SUCCEEDED(rv)) {
+ rv = ReplyToRequest(&conn);
+ }
+}
+
+// returns 0 on success, non-zero on error
+int
+DoCallback()
+{
+ UniquePRFileDesc socket(PR_NewTCPSocket());
+ if (!socket) {
+ PrintPRError("PR_NewTCPSocket failed");
+ return 1;
+ }
+
+ PRNetAddr addr;
+ PR_InitializeNetAddr(PR_IpAddrLoopback, gCallbackPort, &addr);
+ if (PR_Connect(socket.get(), &addr, PR_INTERVAL_NO_TIMEOUT) != PR_SUCCESS) {
+ PrintPRError("PR_Connect failed");
+ return 1;
+ }
+
+ const char *request = "GET / HTTP/1.0\r\n\r\n";
+ SendAll(socket.get(), request, strlen(request));
+ char buf[4096];
+ memset(buf, 0, sizeof(buf));
+ int32_t bytesRead = PR_Recv(socket.get(), buf, sizeof(buf) - 1, 0,
+ PR_INTERVAL_NO_TIMEOUT);
+ if (bytesRead < 0) {
+ PrintPRError("PR_Recv failed 1");
+ return 1;
+ }
+ if (bytesRead == 0) {
+ fprintf(stderr, "PR_Recv eof 1\n");
+ return 1;
+ }
+ fprintf(stderr, "%s\n", buf);
+ return 0;
+}
+
+SECStatus
+ConfigSecureServerWithNamedCert(PRFileDesc* fd, const char* certName,
+ /*optional*/ UniqueCERTCertificate* certOut,
+ /*optional*/ SSLKEAType* keaOut)
+{
+ UniqueCERTCertificate cert(PK11_FindCertFromNickname(certName, nullptr));
+ if (!cert) {
+ PrintPRError("PK11_FindCertFromNickname failed");
+ return SECFailure;
+ }
+ // If an intermediate certificate issued the server certificate (rather than
+ // directly by a trust anchor), we want to send it along in the handshake so
+ // we don't encounter unknown issuer errors when that's not what we're
+ // testing.
+ UniqueCERTCertificateList certList;
+ UniqueCERTCertificate issuerCert(
+ CERT_FindCertByName(CERT_GetDefaultCertDB(), &cert->derIssuer));
+ // If we can't find the issuer cert, continue without it.
+ if (issuerCert) {
+ // Sadly, CERTCertificateList does not have a CERT_NewCertificateList
+ // utility function, so we must create it ourselves. This consists
+ // of creating an arena, allocating space for the CERTCertificateList,
+ // and then transferring ownership of the arena to that list.
+ UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+ if (!arena) {
+ PrintPRError("PORT_NewArena failed");
+ return SECFailure;
+ }
+ certList.reset(static_cast<CERTCertificateList*>(
+ PORT_ArenaAlloc(arena.get(), sizeof(CERTCertificateList))));
+ if (!certList) {
+ PrintPRError("PORT_ArenaAlloc failed");
+ return SECFailure;
+ }
+ certList->arena = arena.release();
+ // We also have to manually copy the certificates we care about to the
+ // list, because there aren't any utility functions for that either.
+ certList->certs = static_cast<SECItem*>(
+ PORT_ArenaAlloc(certList->arena, 2 * sizeof(SECItem)));
+ if (SECITEM_CopyItem(certList->arena, certList->certs, &cert->derCert)
+ != SECSuccess) {
+ PrintPRError("SECITEM_CopyItem failed");
+ return SECFailure;
+ }
+ if (SECITEM_CopyItem(certList->arena, certList->certs + 1,
+ &issuerCert->derCert) != SECSuccess) {
+ PrintPRError("SECITEM_CopyItem failed");
+ return SECFailure;
+ }
+ certList->len = 2;
+ }
+
+ UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
+ if (!slot) {
+ PrintPRError("PK11_GetInternalKeySlot failed");
+ return SECFailure;
+ }
+ UniqueSECKEYPrivateKey key(
+ PK11_FindKeyByDERCert(slot.get(), cert.get(), nullptr));
+ if (!key) {
+ PrintPRError("PK11_FindKeyByDERCert failed");
+ return SECFailure;
+ }
+
+ SSLKEAType certKEA = NSS_FindCertKEAType(cert.get());
+
+ if (SSL_ConfigSecureServerWithCertChain(fd, cert.get(), certList.get(),
+ key.get(), certKEA) != SECSuccess) {
+ PrintPRError("SSL_ConfigSecureServer failed");
+ return SECFailure;
+ }
+
+ if (certOut) {
+ *certOut = Move(cert);
+ }
+
+ if (keaOut) {
+ *keaOut = certKEA;
+ }
+
+ SSL_OptionSet(fd, SSL_NO_CACHE, false);
+ SSL_OptionSet(fd, SSL_ENABLE_SESSION_TICKETS, true);
+
+ return SECSuccess;
+}
+
+int
+StartServer(const char *nssCertDBDir, SSLSNISocketConfig sniSocketConfig,
+ void *sniSocketConfigArg)
+{
+ const char *debugLevel = PR_GetEnv("MOZ_TLS_SERVER_DEBUG_LEVEL");
+ if (debugLevel) {
+ int level = atoi(debugLevel);
+ switch (level) {
+ case DEBUG_ERRORS: gDebugLevel = DEBUG_ERRORS; break;
+ case DEBUG_WARNINGS: gDebugLevel = DEBUG_WARNINGS; break;
+ case DEBUG_VERBOSE: gDebugLevel = DEBUG_VERBOSE; break;
+ default:
+ PrintPRError("invalid MOZ_TLS_SERVER_DEBUG_LEVEL");
+ return 1;
+ }
+ }
+
+ const char *callbackPort = PR_GetEnv("MOZ_TLS_SERVER_CALLBACK_PORT");
+ if (callbackPort) {
+ gCallbackPort = atoi(callbackPort);
+ }
+
+ if (InitializeNSS(nssCertDBDir) != SECSuccess) {
+ PR_fprintf(PR_STDERR, "InitializeNSS failed");
+ return 1;
+ }
+
+ if (NSS_SetDomesticPolicy() != SECSuccess) {
+ PrintPRError("NSS_SetDomesticPolicy failed");
+ return 1;
+ }
+
+ if (SSL_ConfigServerSessionIDCache(0, 0, 0, nullptr) != SECSuccess) {
+ PrintPRError("SSL_ConfigServerSessionIDCache failed");
+ return 1;
+ }
+
+ UniquePRFileDesc serverSocket(PR_NewTCPSocket());
+ if (!serverSocket) {
+ PrintPRError("PR_NewTCPSocket failed");
+ return 1;
+ }
+
+ PRSocketOptionData socketOption;
+ socketOption.option = PR_SockOpt_Reuseaddr;
+ socketOption.value.reuse_addr = true;
+ PR_SetSocketOption(serverSocket.get(), &socketOption);
+
+ PRNetAddr serverAddr;
+ PR_InitializeNetAddr(PR_IpAddrLoopback, LISTEN_PORT, &serverAddr);
+ if (PR_Bind(serverSocket.get(), &serverAddr) != PR_SUCCESS) {
+ PrintPRError("PR_Bind failed");
+ return 1;
+ }
+
+ if (PR_Listen(serverSocket.get(), 1) != PR_SUCCESS) {
+ PrintPRError("PR_Listen failed");
+ return 1;
+ }
+
+ UniquePRFileDesc rawModelSocket(PR_NewTCPSocket());
+ if (!rawModelSocket) {
+ PrintPRError("PR_NewTCPSocket failed for rawModelSocket");
+ return 1;
+ }
+
+ UniquePRFileDesc modelSocket(SSL_ImportFD(nullptr, rawModelSocket.release()));
+ if (!modelSocket) {
+ PrintPRError("SSL_ImportFD of rawModelSocket failed");
+ return 1;
+ }
+
+ if (SSL_SNISocketConfigHook(modelSocket.get(), sniSocketConfig,
+ sniSocketConfigArg) != SECSuccess) {
+ PrintPRError("SSL_SNISocketConfigHook failed");
+ return 1;
+ }
+
+ // We have to configure the server with a certificate, but it's not one
+ // we're actually going to end up using. In the SNI callback, we pick
+ // the right certificate for the connection.
+ if (ConfigSecureServerWithNamedCert(modelSocket.get(), DEFAULT_CERT_NICKNAME,
+ nullptr, nullptr) != SECSuccess) {
+ return 1;
+ }
+
+ if (gCallbackPort != 0) {
+ if (DoCallback()) {
+ return 1;
+ }
+ }
+
+ while (true) {
+ PRNetAddr clientAddr;
+ PRFileDesc* clientSocket = PR_Accept(serverSocket.get(), &clientAddr,
+ PR_INTERVAL_NO_TIMEOUT);
+ HandleConnection(clientSocket, modelSocket);
+ }
+
+ return 0;
+}
+
+} } // namespace mozilla::test
diff --git a/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.h b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.h
new file mode 100644
index 000000000..f1dc1569a
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.h
@@ -0,0 +1,89 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TLSServer_h
+#define TLSServer_h
+
+// This is a standalone server for testing SSL features of Gecko.
+// The client is expected to connect and initiate an SSL handshake (with SNI
+// to indicate which "server" to connect to). If all is good, the client then
+// sends one encrypted byte and receives that same byte back.
+// This server also has the ability to "call back" another process waiting on
+// it. That is, when the server is all set up and ready to receive connections,
+// it will connect to a specified port and issue a simple HTTP request.
+
+#include <stdint.h>
+
+#include "ScopedNSSTypes.h"
+#include "mozilla/Casting.h"
+#include "prio.h"
+#include "secerr.h"
+#include "ssl.h"
+
+namespace mozilla {
+
+MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePRDir, PRDir, PR_CloseDir);
+
+} // namespace mozilla
+
+namespace mozilla { namespace test {
+
+enum DebugLevel
+{
+ DEBUG_ERRORS = 1,
+ DEBUG_WARNINGS = 2,
+ DEBUG_VERBOSE = 3
+};
+
+extern DebugLevel gDebugLevel;
+
+void PrintPRError(const char *aPrefix);
+
+// The default certificate is trusted for localhost and *.example.com
+extern const char DEFAULT_CERT_NICKNAME[];
+
+// Pass DEFAULT_CERT_NICKNAME as certName unless you need a specific
+// certificate.
+SECStatus
+ConfigSecureServerWithNamedCert(PRFileDesc* fd, const char* certName,
+ /*optional*/ UniqueCERTCertificate* cert,
+ /*optional*/ SSLKEAType* kea);
+
+SECStatus
+InitializeNSS(const char* nssCertDBDir);
+
+int
+StartServer(const char *nssCertDBDir, SSLSNISocketConfig sniSocketConfig,
+ void *sniSocketConfigArg);
+
+template <typename Host>
+inline const Host *
+GetHostForSNI(const SECItem *aSrvNameArr, uint32_t aSrvNameArrSize,
+ const Host *hosts)
+{
+ for (uint32_t i = 0; i < aSrvNameArrSize; i++) {
+ for (const Host *host = hosts; host->mHostName; ++host) {
+ SECItem hostName;
+ hostName.data = BitwiseCast<unsigned char*, const char*>(host->mHostName);
+ hostName.len = strlen(host->mHostName);
+ if (SECITEM_ItemsAreEqual(&hostName, &aSrvNameArr[i])) {
+ if (gDebugLevel >= DEBUG_VERBOSE) {
+ fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName);
+ }
+ return host;
+ }
+ }
+ }
+
+ if (gDebugLevel >= DEBUG_VERBOSE) {
+ fprintf(stderr, "could not find host info from SNI\n");
+ }
+
+ PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+ return nullptr;
+}
+
+} } // namespace mozilla::test
+
+#endif // TLSServer_h
diff --git a/security/manager/ssl/tests/unit/tlsserver/lib/moz.build b/security/manager/ssl/tests/unit/tlsserver/lib/moz.build
new file mode 100644
index 000000000..5b28e4a55
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+ 'OCSPCommon.cpp',
+ 'TLSServer.cpp',
+]
+
+LOCAL_INCLUDES += [
+ '../../../../../../pkix/include',
+ '../../../../../../pkix/test/lib',
+]
+
+Library('tlsserver')
diff --git a/security/manager/ssl/tests/unit/tlsserver/moz.build b/security/manager/ssl/tests/unit/tlsserver/moz.build
new file mode 100644
index 000000000..96fb65d06
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# lib must be first, because cmd depends on its output
+DIRS += ['lib', 'cmd']
diff --git a/security/manager/ssl/tests/unit/xpcshell-smartcards.ini b/security/manager/ssl/tests/unit/xpcshell-smartcards.ini
new file mode 100644
index 000000000..df099b746
--- /dev/null
+++ b/security/manager/ssl/tests/unit/xpcshell-smartcards.ini
@@ -0,0 +1,14 @@
+[DEFAULT]
+head = head_psm.js
+tail =
+tags = psm
+skip-if = toolkit == 'android'
+support-files =
+
+[test_pkcs11_insert_remove.js]
+[test_pkcs11_module.js]
+[test_pkcs11_no_events_after_removal.js]
+[test_pkcs11_safe_mode.js]
+[test_pkcs11_slot.js]
+[test_pkcs11_token.js]
+[test_pkcs11_tokenDB.js]
diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini
new file mode 100644
index 000000000..b2f3de420
--- /dev/null
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -0,0 +1,149 @@
+[DEFAULT]
+head = head_psm.js
+tail =
+tags = psm
+support-files =
+ bad_certs/**
+ ocsp_certs/**
+ test_baseline_requirements/**
+ test_cert_eku/**
+ test_cert_embedded_null/**
+ test_cert_isBuiltInRoot_reload/**
+ test_cert_keyUsage/**
+ test_cert_sha1/**
+ test_cert_signatures/**
+ test_cert_trust/**
+ test_cert_version/**
+ test_certDB_import/**
+ test_certviewer_invalid_oids/**
+ test_content_signing/**
+ test_ev_certs/**
+ test_getchain/**
+ test_intermediate_basic_usage_constraints/**
+ test_keysize/**
+ test_keysize_ev/**
+ test_name_constraints/**
+ test_ocsp_fetch_method/**
+ test_ocsp_url/**
+ test_onecrl/**
+ test_pinning_dynamic/**
+ test_signed_apps/**
+ test_signed_dir/**
+ test_startcom_wosign/**
+ test_validity/**
+ tlsserver/**
+
+[test_add_preexisting_cert.js]
+[test_baseline_requirements_subject_common_name.js]
+[test_cert_blocklist.js]
+tags = addons psm
+[test_cert_chains.js]
+run-sequentially = hardcoded ports
+[test_cert_dbKey.js]
+[test_cert_eku.js]
+[test_cert_embedded_null.js]
+[test_cert_keyUsage.js]
+[test_cert_isBuiltInRoot.js]
+[test_cert_isBuiltInRoot_reload.js]
+[test_cert_overrides.js]
+run-sequentially = hardcoded ports
+[test_cert_override_bits_mismatches.js]
+run-sequentially = hardcoded ports
+[test_cert_sha1.js]
+[test_cert_signatures.js]
+[test_cert_trust.js]
+[test_cert_version.js]
+[test_certDB_import.js]
+[test_certDB_import_pkcs12.js]
+[test_certviewer_invalid_oids.js]
+skip-if = toolkit == 'android'
+[test_constructX509FromBase64.js]
+[test_content_signing.js]
+[test_datasignatureverifier.js]
+[test_der.js]
+[test_enterprise_roots.js]
+skip-if = os != 'win' # tests a Windows-specific feature
+[test_ev_certs.js]
+run-sequentially = hardcoded ports
+[test_forget_about_site_security_headers.js]
+skip-if = toolkit == 'android'
+[test_getchain.js]
+[test_hash_algorithms.js]
+[test_hash_algorithms_wrap.js]
+# bug 1124289 - run_test_in_child violates the sandbox on android
+skip-if = toolkit == 'android'
+[test_hmac.js]
+[test_intermediate_basic_usage_constraints.js]
+[test_js_cert_override_service.js]
+run-sequentially = hardcoded ports
+[test_keysize.js]
+[test_keysize_ev.js]
+run-sequentially = hardcoded ports
+[test_local_cert.js]
+[test_logoutAndTeardown.js]
+run-sequentially = hardcoded ports
+[test_name_constraints.js]
+[test_nsCertType.js]
+run-sequentially = hardcoded ports
+[test_nsIX509Cert_utf8.js]
+[test_nsIX509CertValidity.js]
+[test_nss_shutdown.js]
+[test_ocsp_caching.js]
+run-sequentially = hardcoded ports
+[test_ocsp_enabled_pref.js]
+run-sequentially = hardcoded ports
+[test_ocsp_fetch_method.js]
+run-sequentially = hardcoded ports
+[test_ocsp_must_staple.js]
+run-sequentially = hardcoded ports
+[test_ocsp_no_hsts_upgrade.js]
+run-sequentially = hardcoded ports
+[test_ocsp_required.js]
+run-sequentially = hardcoded ports
+[test_ocsp_stapling.js]
+run-sequentially = hardcoded ports
+[test_ocsp_stapling_expired.js]
+run-sequentially = hardcoded ports
+[test_ocsp_stapling_with_intermediate.js]
+run-sequentially = hardcoded ports
+[test_ocsp_timeout.js]
+run-sequentially = hardcoded ports
+[test_ocsp_url.js]
+run-sequentially = hardcoded ports
+[test_password_prompt.js]
+[test_pinning.js]
+run-sequentially = hardcoded ports
+# This test can take longer than 300 seconds on B2G emulator debug builds, so
+# give it enough time to finish. See bug 1081128.
+requesttimeoutfactor = 2
+[test_pinning_dynamic.js]
+[test_pinning_header_parsing.js]
+[test_sdr.js]
+[test_session_resumption.js]
+run-sequentially = hardcoded ports
+[test_signed_apps.js]
+[test_signed_apps-marketplace.js]
+[test_signed_dir.js]
+tags = addons psm
+[test_sss_eviction.js]
+[test_sss_readstate.js]
+[test_sss_readstate_child.js]
+support-files = sss_readstate_child_worker.js
+# bug 1124289 - run_test_in_child violates the sandbox on android
+skip-if = toolkit == 'android'
+[test_sss_readstate_empty.js]
+[test_sss_readstate_garbage.js]
+[test_sss_readstate_huge.js]
+[test_sss_savestate.js]
+[test_startcom_wosign.js]
+[test_sts_fqdn.js]
+[test_sts_holepunch.js]
+[test_sts_ipv4_ipv6.js]
+[test_sts_preloadlist_perwindowpb.js]
+[test_sts_preloadlist_selfdestruct.js]
+[test_validity.js]
+run-sequentially = hardcoded ports
+[test_x509.js]
+
+# The TLS error reporting functionality lives in /toolkit but needs tlsserver
+[test_toolkit_securityreporter.js]