summaryrefslogtreecommitdiffstats
path: root/security/nss/lib
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-12-15 01:42:53 +0100
committerwolfbeast <mcwerewolf@gmail.com>2018-12-15 01:42:53 +0100
commit74cabf7948b2597f5b6a67d6910c844fd1a88ff6 (patch)
treedb1f30ada487c3831ea8e4e98b2d39edc9e88eea /security/nss/lib
parent09ef48bd005a7f9e97a3fe797a079fcf2b5e58d3 (diff)
downloadUXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.tar
UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.tar.gz
UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.tar.lz
UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.tar.xz
UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.zip
Update NSS to 3.41
Diffstat (limited to 'security/nss/lib')
-rw-r--r--security/nss/lib/base/error.c29
-rw-r--r--security/nss/lib/certdb/cert.h2
-rw-r--r--security/nss/lib/certdb/certdb.c77
-rw-r--r--security/nss/lib/certdb/certi.h3
-rw-r--r--security/nss/lib/certdb/certt.h6
-rw-r--r--security/nss/lib/certhigh/certreq.c2
-rw-r--r--security/nss/lib/certhigh/certvfy.c64
-rw-r--r--security/nss/lib/certhigh/ocsp.h2
-rw-r--r--security/nss/lib/ckfw/builtins/certdata.txt2476
-rw-r--r--security/nss/lib/ckfw/builtins/nssckbi.h4
-rw-r--r--security/nss/lib/ckfw/ckfw.h4
-rw-r--r--security/nss/lib/ckfw/session.c4
-rw-r--r--security/nss/lib/cryptohi/cryptohi.h2
-rw-r--r--security/nss/lib/cryptohi/key.h6
-rw-r--r--security/nss/lib/cryptohi/keyi.h17
-rw-r--r--security/nss/lib/cryptohi/keyt.h4
-rw-r--r--security/nss/lib/cryptohi/seckey.c104
-rw-r--r--security/nss/lib/cryptohi/secsign.c11
-rw-r--r--security/nss/lib/cryptohi/secvfy.c52
-rw-r--r--security/nss/lib/freebl/ctr.c21
-rw-r--r--security/nss/lib/freebl/freebl.gyp35
-rw-r--r--security/nss/lib/freebl/freebl_base.gypi7
-rw-r--r--security/nss/lib/freebl/mpi/mpi.c61
-rw-r--r--security/nss/lib/freebl/mpi/mpi.h3
-rw-r--r--security/nss/lib/freebl/mpi/mpi_arm.c38
-rw-r--r--security/nss/lib/freebl/rsapkcs.c68
-rw-r--r--security/nss/lib/jar/jarint.h2
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c16
-rw-r--r--security/nss/lib/mozpkix/.clang-format4
-rw-r--r--security/nss/lib/mozpkix/exports.gyp47
-rw-r--r--security/nss/lib/mozpkix/include/pkix-test/pkixtestnss.h48
-rw-r--r--security/nss/lib/mozpkix/include/pkix-test/pkixtestutil.h406
-rw-r--r--security/nss/lib/mozpkix/include/pkix/Input.h310
-rw-r--r--security/nss/lib/mozpkix/include/pkix/Result.h219
-rw-r--r--security/nss/lib/mozpkix/include/pkix/Time.h137
-rw-r--r--security/nss/lib/mozpkix/include/pkix/pkix.h160
-rw-r--r--security/nss/lib/mozpkix/include/pkix/pkixcheck.h65
-rw-r--r--security/nss/lib/mozpkix/include/pkix/pkixder.h520
-rw-r--r--security/nss/lib/mozpkix/include/pkix/pkixnss.h106
-rw-r--r--security/nss/lib/mozpkix/include/pkix/pkixtypes.h400
-rw-r--r--security/nss/lib/mozpkix/include/pkix/pkixutil.h265
-rw-r--r--security/nss/lib/mozpkix/lib/pkixbuild.cpp418
-rw-r--r--security/nss/lib/mozpkix/lib/pkixcert.cpp323
-rw-r--r--security/nss/lib/mozpkix/lib/pkixcheck.cpp1100
-rw-r--r--security/nss/lib/mozpkix/lib/pkixder.cpp611
-rw-r--r--security/nss/lib/mozpkix/lib/pkixnames.cpp2050
-rw-r--r--security/nss/lib/mozpkix/lib/pkixnss.cpp236
-rw-r--r--security/nss/lib/mozpkix/lib/pkixocsp.cpp1012
-rw-r--r--security/nss/lib/mozpkix/lib/pkixresult.cpp46
-rw-r--r--security/nss/lib/mozpkix/lib/pkixtime.cpp78
-rw-r--r--security/nss/lib/mozpkix/lib/pkixverify.cpp106
-rw-r--r--security/nss/lib/mozpkix/mozpkix.gyp60
-rw-r--r--security/nss/lib/mozpkix/test-lib/pkixtestalg.cpp211
-rw-r--r--security/nss/lib/mozpkix/test-lib/pkixtestnss.cpp364
-rw-r--r--security/nss/lib/mozpkix/test-lib/pkixtestutil.cpp1155
-rw-r--r--security/nss/lib/mozpkix/tools/DottedOIDToCode.py216
-rw-r--r--security/nss/lib/nss/nss.def6
-rw-r--r--security/nss/lib/nss/nss.h4
-rw-r--r--security/nss/lib/nss/nssinit.c52
-rw-r--r--security/nss/lib/pk11wrap/pk11akey.c20
-rw-r--r--security/nss/lib/pk11wrap/pk11cert.c4
-rw-r--r--security/nss/lib/pk11wrap/pk11kea.c2
-rw-r--r--security/nss/lib/pk11wrap/pk11obj.c2
-rw-r--r--security/nss/lib/pk11wrap/pk11pars.c285
-rw-r--r--security/nss/lib/pk11wrap/pk11pbe.c2
-rw-r--r--security/nss/lib/pk11wrap/pk11pk12.c2
-rw-r--r--security/nss/lib/pk11wrap/pk11priv.h2
-rw-r--r--security/nss/lib/pk11wrap/pk11pub.h2
-rw-r--r--security/nss/lib/pk11wrap/pk11slot.c86
-rw-r--r--security/nss/lib/pk11wrap/secmodi.h2
-rw-r--r--security/nss/lib/pkcs12/p12.h2
-rw-r--r--security/nss/lib/pkcs12/p12t.h2
-rw-r--r--security/nss/lib/pkcs12/pkcs12t.h2
-rw-r--r--security/nss/lib/pkcs7/p7decode.c2
-rw-r--r--security/nss/lib/pkcs7/secmime.c2
-rw-r--r--security/nss/lib/pkcs7/secpkcs7.h2
-rw-r--r--security/nss/lib/smime/cms.h2
-rw-r--r--security/nss/lib/smime/cmsasn1.c2
-rw-r--r--security/nss/lib/smime/cmsdecode.c2
-rw-r--r--security/nss/lib/smime/cmsdigest.c2
-rw-r--r--security/nss/lib/smime/cmsencdata.c2
-rw-r--r--security/nss/lib/smime/cmsencode.c2
-rw-r--r--security/nss/lib/smime/cmsenvdata.c2
-rw-r--r--security/nss/lib/smime/cmspubkey.c2
-rw-r--r--security/nss/lib/smime/cmsrecinfo.c2
-rw-r--r--security/nss/lib/smime/cmsreclist.c2
-rw-r--r--security/nss/lib/smime/cmssiginfo.c2
-rw-r--r--security/nss/lib/smime/cmsutil.c2
-rw-r--r--security/nss/lib/smime/smimemessage.c2
-rw-r--r--security/nss/lib/smime/smimeutil.c2
-rw-r--r--security/nss/lib/softoken/pkcs11c.c2
-rw-r--r--security/nss/lib/softoken/softkver.h4
-rw-r--r--security/nss/lib/ssl/SSLerrs.h12
-rw-r--r--security/nss/lib/ssl/authcert.c2
-rw-r--r--security/nss/lib/ssl/cmpcert.c31
-rw-r--r--security/nss/lib/ssl/config.mk4
-rw-r--r--security/nss/lib/ssl/dtls13con.c10
-rw-r--r--security/nss/lib/ssl/dtls13con.h2
-rw-r--r--security/nss/lib/ssl/dtlscon.c22
-rw-r--r--security/nss/lib/ssl/dtlscon.h2
-rw-r--r--security/nss/lib/ssl/manifest.mn2
-rw-r--r--security/nss/lib/ssl/ssl.gyp6
-rw-r--r--security/nss/lib/ssl/ssl.h19
-rw-r--r--security/nss/lib/ssl/ssl3con.c1004
-rw-r--r--security/nss/lib/ssl/ssl3ecc.c7
-rw-r--r--security/nss/lib/ssl/ssl3ext.c13
-rw-r--r--security/nss/lib/ssl/ssl3ext.h10
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.c91
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.h4
-rw-r--r--security/nss/lib/ssl/ssl3gthr.c16
-rw-r--r--security/nss/lib/ssl/ssl3prot.h15
-rw-r--r--security/nss/lib/ssl/sslcert.c2
-rw-r--r--security/nss/lib/ssl/sslerr.h4
-rw-r--r--security/nss/lib/ssl/sslexp.h60
-rw-r--r--security/nss/lib/ssl/sslimpl.h48
-rw-r--r--security/nss/lib/ssl/sslnonce.c48
-rw-r--r--security/nss/lib/ssl/sslsecur.c44
-rw-r--r--security/nss/lib/ssl/sslsock.c97
-rw-r--r--security/nss/lib/ssl/sslspec.c2
-rw-r--r--security/nss/lib/ssl/sslt.h11
-rw-r--r--security/nss/lib/ssl/tls13con.c290
-rw-r--r--security/nss/lib/ssl/tls13con.h36
-rw-r--r--security/nss/lib/ssl/tls13esni.c844
-rw-r--r--security/nss/lib/ssl/tls13esni.h51
-rw-r--r--security/nss/lib/ssl/tls13exthandle.c375
-rw-r--r--security/nss/lib/ssl/tls13exthandle.h9
-rw-r--r--security/nss/lib/util/nssutil.def6
-rw-r--r--security/nss/lib/util/nssutil.h4
-rw-r--r--security/nss/lib/util/pkcs11p.h5
-rw-r--r--security/nss/lib/util/pkcs11u.h5
-rw-r--r--security/nss/lib/util/pkcs11uri.c2
-rw-r--r--security/nss/lib/util/pkcs1sig.c67
-rw-r--r--security/nss/lib/util/secder.h3
-rw-r--r--security/nss/lib/util/secitem.c4
-rw-r--r--security/nss/lib/util/secitem.h2
-rw-r--r--security/nss/lib/util/secoid.c26
-rw-r--r--security/nss/lib/util/secoidt.h5
-rw-r--r--security/nss/lib/util/secport.c3
-rw-r--r--security/nss/lib/util/utilpars.c86
-rw-r--r--security/nss/lib/util/utilpars.h1
140 files changed, 15450 insertions, 2272 deletions
diff --git a/security/nss/lib/base/error.c b/security/nss/lib/base/error.c
index 95a76cf79..2ef032933 100644
--- a/security/nss/lib/base/error.c
+++ b/security/nss/lib/base/error.c
@@ -15,6 +15,10 @@
#include <limits.h> /* for UINT_MAX */
#include <string.h> /* for memmove */
+#if defined(__MINGW32__)
+#include <windows.h>
+#endif
+
#define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */
/*
@@ -65,7 +69,32 @@ static const PRCallOnceType error_call_again;
static PRStatus
error_once_function(void)
{
+
+/*
+ * This #ifdef function is redundant. It performs the same thing as the
+ * else case.
+ *
+ * However, the MinGW version looks up the function from nss3's export
+ * table, and on MinGW _that_ behaves differently than passing a
+ * function pointer in a different module because MinGW has
+ * -mnop-fun-dllimport specified, which generates function thunks for
+ * cross-module calls. And when a module (like nssckbi) gets unloaded,
+ * and you try to call into that thunk (which is now missing) you'll
+ * crash. So we do this bit of ugly to avoid that crash. Fortunately
+ * this is the only place we've had to do this.
+ */
+#if defined(__MINGW32__)
+ HMODULE nss3 = GetModuleHandleW(L"nss3");
+ if (nss3) {
+ FARPROC freePtr = GetProcAddress(nss3, "PR_Free");
+ if (freePtr) {
+ return PR_NewThreadPrivateIndex(&error_stack_index, freePtr);
+ }
+ }
+ return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
+#else
return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free);
+#endif
}
/*
diff --git a/security/nss/lib/certdb/cert.h b/security/nss/lib/certdb/cert.h
index c76a5a9b0..333ba4c9d 100644
--- a/security/nss/lib/certdb/cert.h
+++ b/security/nss/lib/certdb/cert.h
@@ -18,7 +18,7 @@
#include "seccomon.h"
#include "secdert.h"
#include "secoidt.h"
-#include "keyt.h"
+#include "keythi.h"
#include "certt.h"
SEC_BEGIN_PROTOS
diff --git a/security/nss/lib/certdb/certdb.c b/security/nss/lib/certdb/certdb.c
index 1a676a720..85b5f2917 100644
--- a/security/nss/lib/certdb/certdb.c
+++ b/security/nss/lib/certdb/certdb.c
@@ -446,6 +446,74 @@ cert_GetCertType(CERTCertificate *cert)
return SECSuccess;
}
+PRBool
+cert_EKUAllowsIPsecIKE(CERTCertificate *cert, PRBool *isCritical)
+{
+ SECStatus rv;
+ SECItem encodedExtKeyUsage;
+ CERTOidSequence *extKeyUsage = NULL;
+ PRBool result = PR_FALSE;
+
+ rv = CERT_GetExtenCriticality(cert->extensions,
+ SEC_OID_X509_EXT_KEY_USAGE,
+ isCritical);
+ if (rv != SECSuccess) {
+ *isCritical = PR_FALSE;
+ }
+
+ encodedExtKeyUsage.data = NULL;
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE,
+ &encodedExtKeyUsage);
+ if (rv != SECSuccess) {
+ /* EKU not present, allowed. */
+ result = PR_TRUE;
+ goto done;
+ }
+
+ extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
+ if (!extKeyUsage) {
+ /* failure */
+ goto done;
+ }
+
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_X509_ANY_EXT_KEY_USAGE) ==
+ SECSuccess) {
+ result = PR_TRUE;
+ goto done;
+ }
+
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_IKE) ==
+ SECSuccess) {
+ result = PR_TRUE;
+ goto done;
+ }
+
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_IPSEC_IKE_END) ==
+ SECSuccess) {
+ result = PR_TRUE;
+ goto done;
+ }
+
+ if (findOIDinOIDSeqByTagNum(extKeyUsage,
+ SEC_OID_IPSEC_IKE_INTERMEDIATE) ==
+ SECSuccess) {
+ result = PR_TRUE;
+ goto done;
+ }
+
+done:
+ if (encodedExtKeyUsage.data != NULL) {
+ PORT_Free(encodedExtKeyUsage.data);
+ }
+ if (extKeyUsage != NULL) {
+ CERT_DestroyOidSequence(extKeyUsage);
+ }
+ return result;
+}
+
PRUint32
cert_ComputeCertType(CERTCertificate *cert)
{
@@ -1083,6 +1151,10 @@ CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage, PRBool ca,
requiredKeyUsage = KU_KEY_CERT_SIGN;
requiredCertType = NS_CERT_TYPE_SSL_CA;
break;
+ case certUsageIPsec:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_SSL_CA;
+ break;
case certUsageSSLCA:
requiredKeyUsage = KU_KEY_CERT_SIGN;
requiredCertType = NS_CERT_TYPE_SSL_CA;
@@ -1125,6 +1197,11 @@ CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage, PRBool ca,
requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
requiredCertType = NS_CERT_TYPE_SSL_SERVER;
break;
+ case certUsageIPsec:
+ /* RFC 4945 Section 5.1.3.2 */
+ requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
+ requiredCertType = 0;
+ break;
case certUsageSSLServerWithStepUp:
requiredKeyUsage =
KU_KEY_AGREEMENT_OR_ENCIPHERMENT | KU_NS_GOVT_APPROVED;
diff --git a/security/nss/lib/certdb/certi.h b/security/nss/lib/certdb/certi.h
index 456f2fc4e..2a8ae2758 100644
--- a/security/nss/lib/certdb/certi.h
+++ b/security/nss/lib/certdb/certi.h
@@ -294,6 +294,9 @@ extern SECStatus cert_GetCertType(CERTCertificate* cert);
*/
extern PRUint32 cert_ComputeCertType(CERTCertificate* cert);
+extern PRBool cert_EKUAllowsIPsecIKE(CERTCertificate* cert,
+ PRBool* isCritical);
+
void cert_AddToVerifyLog(CERTVerifyLog* log, CERTCertificate* cert,
long errorCode, unsigned int depth, void* arg);
diff --git a/security/nss/lib/certdb/certt.h b/security/nss/lib/certdb/certt.h
index 797f9f585..9cac70ca6 100644
--- a/security/nss/lib/certdb/certt.h
+++ b/security/nss/lib/certdb/certt.h
@@ -447,7 +447,8 @@ typedef enum SECCertUsageEnum {
certUsageVerifyCA = 8,
certUsageProtectedObjectSigner = 9,
certUsageStatusResponder = 10,
- certUsageAnyCA = 11
+ certUsageAnyCA = 11,
+ certUsageIPsec = 12
} SECCertUsage;
typedef PRInt64 SECCertificateUsage;
@@ -465,8 +466,9 @@ typedef PRInt64 SECCertificateUsage;
#define certificateUsageProtectedObjectSigner (0x0200)
#define certificateUsageStatusResponder (0x0400)
#define certificateUsageAnyCA (0x0800)
+#define certificateUsageIPsec (0x1000)
-#define certificateUsageHighest certificateUsageAnyCA
+#define certificateUsageHighest certificateUsageIPsec
/*
* Does the cert belong to the user, a peer, or a CA.
diff --git a/security/nss/lib/certhigh/certreq.c b/security/nss/lib/certhigh/certreq.c
index 4087bc978..2ab4f1ab7 100644
--- a/security/nss/lib/certhigh/certreq.c
+++ b/security/nss/lib/certhigh/certreq.c
@@ -5,7 +5,7 @@
#include "cert.h"
#include "certt.h"
#include "secder.h"
-#include "key.h"
+#include "keyhi.h"
#include "secitem.h"
#include "secasn1.h"
#include "secerr.h"
diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c
index ccd38e660..3a94a4150 100644
--- a/security/nss/lib/certhigh/certvfy.c
+++ b/security/nss/lib/certhigh/certvfy.c
@@ -25,7 +25,7 @@
#include "pkim.h"
#include "pki3hack.h"
#include "base.h"
-#include "keyhi.h"
+#include "keyi.h"
/*
* Check the validity times of a certificate
@@ -73,12 +73,38 @@ checkKeyParams(const SECAlgorithmID *sigAlgorithm, const SECKEYPublicKey *key)
return SECFailure;
}
return SECSuccess;
+
+ case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: {
+ PORTCheapArenaPool tmpArena;
+ SECOidTag hashAlg;
+ SECOidTag maskHashAlg;
+
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
+ rv = sec_DecodeRSAPSSParams(&tmpArena.arena,
+ &sigAlgorithm->parameters,
+ &hashAlg, &maskHashAlg, NULL);
+ PORT_DestroyCheapArena(&tmpArena);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (NSS_GetAlgorithmPolicy(hashAlg, &policyFlags) == SECSuccess &&
+ !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
+ PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ return SECFailure;
+ }
+ if (NSS_GetAlgorithmPolicy(maskHashAlg, &policyFlags) == SECSuccess &&
+ !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
+ PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ return SECFailure;
+ }
+ }
+ /* fall through to RSA key checking */
case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
- case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
if (key->keyType != rsaKey && key->keyType != rsaPssKey) {
@@ -289,6 +315,10 @@ CERT_TrustFlagsForCACertUsage(SECCertUsage usage,
requiredFlags = CERTDB_TRUSTED_CA;
trustType = trustSSL;
break;
+ case certUsageIPsec:
+ requiredFlags = CERTDB_TRUSTED_CA;
+ trustType = trustSSL;
+ break;
case certUsageSSLServerWithStepUp:
requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA;
trustType = trustSSL;
@@ -579,6 +609,7 @@ cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert,
switch (certUsage) {
case certUsageSSLClient:
case certUsageSSLServer:
+ case certUsageIPsec:
case certUsageSSLCA:
case certUsageSSLServerWithStepUp:
case certUsageEmailSigner:
@@ -645,7 +676,8 @@ cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert,
CERTGeneralName *subjectNameList;
int subjectNameListLen;
int i;
- PRBool getSubjectCN = (!count && certUsage == certUsageSSLServer);
+ PRBool getSubjectCN = (!count &&
+ (certUsage == certUsageSSLServer || certUsage == certUsageIPsec));
subjectNameList =
CERT_GetConstrainedCertificateNames(subjectCert, arena,
getSubjectCN);
@@ -986,6 +1018,7 @@ CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
switch (certUsage) {
case certUsageSSLClient:
case certUsageSSLServer:
+ case certUsageIPsec:
case certUsageSSLCA:
case certUsageSSLServerWithStepUp:
case certUsageEmailSigner:
@@ -1171,6 +1204,7 @@ cert_CheckLeafTrust(CERTCertificate *cert, SECCertUsage certUsage,
switch (certUsage) {
case certUsageSSLClient:
case certUsageSSLServer:
+ case certUsageIPsec:
flags = trust.sslFlags;
/* is the cert directly trusted or not trusted ? */
@@ -1347,7 +1381,8 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
/* make sure that the cert is valid at time t */
allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) ||
- (requiredUsages & certificateUsageSSLServerWithStepUp));
+ (requiredUsages & certificateUsageSSLServerWithStepUp) ||
+ (requiredUsages & certificateUsageIPsec));
validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
if (validity != secCertTimeValid) {
valid = SECFailure;
@@ -1360,6 +1395,7 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
for (i = 1; i <= certificateUsageHighest &&
(SECSuccess == valid || returnedUsages || log);) {
+ PRBool typeAndEKUAllowed = PR_TRUE;
PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
NEXT_USAGE();
@@ -1376,6 +1412,7 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
case certUsageEmailRecipient:
case certUsageObjectSigner:
case certUsageStatusResponder:
+ case certUsageIPsec:
rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
&requiredKeyUsage,
&requiredCertType);
@@ -1408,7 +1445,19 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
LOG_ERROR(log, cert, 0, requiredKeyUsage);
INVALID_USAGE();
}
- if (!(certType & requiredCertType)) {
+ if (certUsage != certUsageIPsec) {
+ if (!(certType & requiredCertType)) {
+ typeAndEKUAllowed = PR_FALSE;
+ }
+ } else {
+ PRBool isCritical;
+ PRBool allowed = cert_EKUAllowsIPsecIKE(cert, &isCritical);
+ /* If the extension isn't critical, we allow any EKU value. */
+ if (isCritical && !allowed) {
+ typeAndEKUAllowed = PR_FALSE;
+ }
+ }
+ if (!typeAndEKUAllowed) {
if (PR_TRUE == requiredUsage) {
PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
}
@@ -1508,7 +1557,8 @@ cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert,
/* make sure that the cert is valid at time t */
allowOverride = (PRBool)((certUsage == certUsageSSLServer) ||
- (certUsage == certUsageSSLServerWithStepUp));
+ (certUsage == certUsageSSLServerWithStepUp) ||
+ (certUsage == certUsageIPsec));
validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
if (validity != secCertTimeValid) {
LOG_ERROR_OR_EXIT(log, cert, 0, validity);
@@ -1521,6 +1571,7 @@ cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert,
case certUsageSSLClient:
case certUsageSSLServer:
case certUsageSSLServerWithStepUp:
+ case certUsageIPsec:
case certUsageSSLCA:
case certUsageEmailSigner:
case certUsageEmailRecipient:
@@ -1633,6 +1684,7 @@ CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
* certUsageSSLClient
* certUsageSSLServer
* certUsageSSLServerWithStepUp
+ * certUsageIPsec
* certUsageEmailSigner
* certUsageEmailRecipient
* certUsageObjectSigner
diff --git a/security/nss/lib/certhigh/ocsp.h b/security/nss/lib/certhigh/ocsp.h
index ac9dd6465..1b94aec2e 100644
--- a/security/nss/lib/certhigh/ocsp.h
+++ b/security/nss/lib/certhigh/ocsp.h
@@ -12,7 +12,7 @@
#include "plarena.h"
#include "seccomon.h"
#include "secoidt.h"
-#include "keyt.h"
+#include "keythi.h"
#include "certt.h"
#include "ocspt.h"
diff --git a/security/nss/lib/ckfw/builtins/certdata.txt b/security/nss/lib/ckfw/builtins/certdata.txt
index d291f28a5..182dda65e 100644
--- a/security/nss/lib/ckfw/builtins/certdata.txt
+++ b/security/nss/lib/ckfw/builtins/certdata.txt
@@ -2145,146 +2145,6 @@ CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
-# Certificate "Visa eCommerce Root"
-#
-# Issuer: CN=Visa eCommerce Root,OU=Visa International Service Association,O=VISA,C=US
-# Serial Number:13:86:35:4d:1d:3f:06:f2:c1:f9:65:05:d5:90:1c:62
-# Subject: CN=Visa eCommerce Root,OU=Visa International Service Association,O=VISA,C=US
-# Not Valid Before: Wed Jun 26 02:18:36 2002
-# Not Valid After : Fri Jun 24 00:16:12 2022
-# Fingerprint (MD5): FC:11:B8:D8:08:93:30:00:6D:23:F9:7E:EB:52:1E:02
-# Fingerprint (SHA1): 70:17:9B:86:8C:00:A4:FA:60:91:52:22:3F:9F:3E:32:BD:E0:05:62
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "Visa eCommerce Root"
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\153\061\013\060\011\006\003\125\004\006\023\002\125\123\061
-\015\060\013\006\003\125\004\012\023\004\126\111\123\101\061\057
-\060\055\006\003\125\004\013\023\046\126\151\163\141\040\111\156
-\164\145\162\156\141\164\151\157\156\141\154\040\123\145\162\166
-\151\143\145\040\101\163\163\157\143\151\141\164\151\157\156\061
-\034\060\032\006\003\125\004\003\023\023\126\151\163\141\040\145
-\103\157\155\155\145\162\143\145\040\122\157\157\164
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\153\061\013\060\011\006\003\125\004\006\023\002\125\123\061
-\015\060\013\006\003\125\004\012\023\004\126\111\123\101\061\057
-\060\055\006\003\125\004\013\023\046\126\151\163\141\040\111\156
-\164\145\162\156\141\164\151\157\156\141\154\040\123\145\162\166
-\151\143\145\040\101\163\163\157\143\151\141\164\151\157\156\061
-\034\060\032\006\003\125\004\003\023\023\126\151\163\141\040\145
-\103\157\155\155\145\162\143\145\040\122\157\157\164
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\020\023\206\065\115\035\077\006\362\301\371\145\005\325\220
-\034\142
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\003\242\060\202\002\212\240\003\002\001\002\002\020\023
-\206\065\115\035\077\006\362\301\371\145\005\325\220\034\142\060
-\015\006\011\052\206\110\206\367\015\001\001\005\005\000\060\153
-\061\013\060\011\006\003\125\004\006\023\002\125\123\061\015\060
-\013\006\003\125\004\012\023\004\126\111\123\101\061\057\060\055
-\006\003\125\004\013\023\046\126\151\163\141\040\111\156\164\145
-\162\156\141\164\151\157\156\141\154\040\123\145\162\166\151\143
-\145\040\101\163\163\157\143\151\141\164\151\157\156\061\034\060
-\032\006\003\125\004\003\023\023\126\151\163\141\040\145\103\157
-\155\155\145\162\143\145\040\122\157\157\164\060\036\027\015\060
-\062\060\066\062\066\060\062\061\070\063\066\132\027\015\062\062
-\060\066\062\064\060\060\061\066\061\062\132\060\153\061\013\060
-\011\006\003\125\004\006\023\002\125\123\061\015\060\013\006\003
-\125\004\012\023\004\126\111\123\101\061\057\060\055\006\003\125
-\004\013\023\046\126\151\163\141\040\111\156\164\145\162\156\141
-\164\151\157\156\141\154\040\123\145\162\166\151\143\145\040\101
-\163\163\157\143\151\141\164\151\157\156\061\034\060\032\006\003
-\125\004\003\023\023\126\151\163\141\040\145\103\157\155\155\145
-\162\143\145\040\122\157\157\164\060\202\001\042\060\015\006\011
-\052\206\110\206\367\015\001\001\001\005\000\003\202\001\017\000
-\060\202\001\012\002\202\001\001\000\257\127\336\126\036\156\241
-\332\140\261\224\047\313\027\333\007\077\200\205\117\310\234\266
-\320\364\157\117\317\231\330\341\333\302\110\134\072\254\071\063
-\307\037\152\213\046\075\053\065\365\110\261\221\301\002\116\004
-\226\221\173\260\063\360\261\024\116\021\157\265\100\257\033\105
-\245\112\357\176\266\254\362\240\037\130\077\022\106\140\074\215
-\241\340\175\317\127\076\063\036\373\107\361\252\025\227\007\125
-\146\245\265\055\056\330\200\131\262\247\015\267\106\354\041\143
-\377\065\253\245\002\317\052\364\114\376\173\365\224\135\204\115
-\250\362\140\217\333\016\045\074\237\163\161\317\224\337\112\352
-\333\337\162\070\214\363\226\275\361\027\274\322\272\073\105\132
-\306\247\366\306\027\213\001\235\374\031\250\052\203\026\270\072
-\110\376\116\076\240\253\006\031\351\123\363\200\023\007\355\055
-\277\077\012\074\125\040\071\054\054\000\151\164\225\112\274\040
-\262\251\171\345\030\211\221\250\334\034\115\357\273\176\067\013
-\135\376\071\245\210\122\214\000\154\354\030\174\101\275\366\213
-\165\167\272\140\235\204\347\376\055\002\003\001\000\001\243\102
-\060\100\060\017\006\003\125\035\023\001\001\377\004\005\060\003
-\001\001\377\060\016\006\003\125\035\017\001\001\377\004\004\003
-\002\001\006\060\035\006\003\125\035\016\004\026\004\024\025\070
-\203\017\077\054\077\160\063\036\315\106\376\007\214\040\340\327
-\303\267\060\015\006\011\052\206\110\206\367\015\001\001\005\005
-\000\003\202\001\001\000\137\361\101\175\174\134\010\271\053\340
-\325\222\107\372\147\134\245\023\303\003\041\233\053\114\211\106
-\317\131\115\311\376\245\100\266\143\315\335\161\050\225\147\021
-\314\044\254\323\104\154\161\256\001\040\153\003\242\217\030\267
-\051\072\175\345\026\140\123\170\074\300\257\025\203\367\217\122
-\063\044\275\144\223\227\356\213\367\333\030\250\155\161\263\367
-\054\027\320\164\045\151\367\376\153\074\224\276\115\113\101\214
-\116\342\163\320\343\220\042\163\103\315\363\357\352\163\316\105
-\212\260\246\111\377\114\175\235\161\210\304\166\035\220\133\035
-\356\375\314\367\356\375\140\245\261\172\026\161\321\026\320\174
-\022\074\154\151\227\333\256\137\071\232\160\057\005\074\031\106
-\004\231\040\066\320\140\156\141\006\273\026\102\214\160\367\060
-\373\340\333\146\243\000\001\275\346\054\332\221\137\240\106\213
-\115\152\234\075\075\335\005\106\376\166\277\240\012\074\344\000
-\346\047\267\377\204\055\336\272\042\047\226\020\161\353\042\355
-\337\337\063\234\317\343\255\256\216\324\216\346\117\121\257\026
-\222\340\134\366\007\017
-END
-CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
-
-# Trust for Certificate "Visa eCommerce Root"
-# Issuer: CN=Visa eCommerce Root,OU=Visa International Service Association,O=VISA,C=US
-# Serial Number:13:86:35:4d:1d:3f:06:f2:c1:f9:65:05:d5:90:1c:62
-# Subject: CN=Visa eCommerce Root,OU=Visa International Service Association,O=VISA,C=US
-# Not Valid Before: Wed Jun 26 02:18:36 2002
-# Not Valid After : Fri Jun 24 00:16:12 2022
-# Fingerprint (MD5): FC:11:B8:D8:08:93:30:00:6D:23:F9:7E:EB:52:1E:02
-# Fingerprint (SHA1): 70:17:9B:86:8C:00:A4:FA:60:91:52:22:3F:9F:3E:32:BD:E0:05:62
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "Visa eCommerce Root"
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\160\027\233\206\214\000\244\372\140\221\122\042\077\237\076\062
-\275\340\005\142
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\374\021\270\330\010\223\060\000\155\043\371\176\353\122\036\002
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\153\061\013\060\011\006\003\125\004\006\023\002\125\123\061
-\015\060\013\006\003\125\004\012\023\004\126\111\123\101\061\057
-\060\055\006\003\125\004\013\023\046\126\151\163\141\040\111\156
-\164\145\162\156\141\164\151\157\156\141\154\040\123\145\162\166
-\151\143\145\040\101\163\163\157\143\151\141\164\151\157\156\061
-\034\060\032\006\003\125\004\003\023\023\126\151\163\141\040\145
-\103\157\155\155\145\162\143\145\040\122\157\157\164
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\020\023\206\065\115\035\077\006\362\301\371\145\005\325\220
-\034\142
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
# Certificate "Certum Root CA"
#
# Issuer: CN=Certum CA,O=Unizeto Sp. z o.o.,C=PL
@@ -7054,193 +6914,6 @@ CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
-# Certificate "AC Raiz Certicamara S.A."
-#
-# Issuer: CN=AC Ra..z Certic..mara S.A.,O=Sociedad Cameral de Certificaci..n Digital - Certic..mara S.A.,C=CO
-# Serial Number:07:7e:52:93:7b:e0:15:e3:57:f0:69:8c:cb:ec:0c
-# Subject: CN=AC Ra..z Certic..mara S.A.,O=Sociedad Cameral de Certificaci..n Digital - Certic..mara S.A.,C=CO
-# Not Valid Before: Mon Nov 27 20:46:29 2006
-# Not Valid After : Tue Apr 02 21:42:02 2030
-# Fingerprint (MD5): 93:2A:3E:F6:FD:23:69:0D:71:20:D4:2B:47:99:2B:A6
-# Fingerprint (SHA1): CB:A1:C5:F8:B0:E3:5E:B8:B9:45:12:D3:F9:34:A2:E9:06:10:D3:36
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "AC Ra\xC3\xADz Certic\xC3\xA1mara S.A."
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\173\061\013\060\011\006\003\125\004\006\023\002\103\117\061
-\107\060\105\006\003\125\004\012\014\076\123\157\143\151\145\144
-\141\144\040\103\141\155\145\162\141\154\040\144\145\040\103\145
-\162\164\151\146\151\143\141\143\151\303\263\156\040\104\151\147
-\151\164\141\154\040\055\040\103\145\162\164\151\143\303\241\155
-\141\162\141\040\123\056\101\056\061\043\060\041\006\003\125\004
-\003\014\032\101\103\040\122\141\303\255\172\040\103\145\162\164
-\151\143\303\241\155\141\162\141\040\123\056\101\056
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\173\061\013\060\011\006\003\125\004\006\023\002\103\117\061
-\107\060\105\006\003\125\004\012\014\076\123\157\143\151\145\144
-\141\144\040\103\141\155\145\162\141\154\040\144\145\040\103\145
-\162\164\151\146\151\143\141\143\151\303\263\156\040\104\151\147
-\151\164\141\154\040\055\040\103\145\162\164\151\143\303\241\155
-\141\162\141\040\123\056\101\056\061\043\060\041\006\003\125\004
-\003\014\032\101\103\040\122\141\303\255\172\040\103\145\162\164
-\151\143\303\241\155\141\162\141\040\123\056\101\056
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\017\007\176\122\223\173\340\025\343\127\360\151\214\313\354
-\014
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\006\146\060\202\004\116\240\003\002\001\002\002\017\007
-\176\122\223\173\340\025\343\127\360\151\214\313\354\014\060\015
-\006\011\052\206\110\206\367\015\001\001\005\005\000\060\173\061
-\013\060\011\006\003\125\004\006\023\002\103\117\061\107\060\105
-\006\003\125\004\012\014\076\123\157\143\151\145\144\141\144\040
-\103\141\155\145\162\141\154\040\144\145\040\103\145\162\164\151
-\146\151\143\141\143\151\303\263\156\040\104\151\147\151\164\141
-\154\040\055\040\103\145\162\164\151\143\303\241\155\141\162\141
-\040\123\056\101\056\061\043\060\041\006\003\125\004\003\014\032
-\101\103\040\122\141\303\255\172\040\103\145\162\164\151\143\303
-\241\155\141\162\141\040\123\056\101\056\060\036\027\015\060\066
-\061\061\062\067\062\060\064\066\062\071\132\027\015\063\060\060
-\064\060\062\062\061\064\062\060\062\132\060\173\061\013\060\011
-\006\003\125\004\006\023\002\103\117\061\107\060\105\006\003\125
-\004\012\014\076\123\157\143\151\145\144\141\144\040\103\141\155
-\145\162\141\154\040\144\145\040\103\145\162\164\151\146\151\143
-\141\143\151\303\263\156\040\104\151\147\151\164\141\154\040\055
-\040\103\145\162\164\151\143\303\241\155\141\162\141\040\123\056
-\101\056\061\043\060\041\006\003\125\004\003\014\032\101\103\040
-\122\141\303\255\172\040\103\145\162\164\151\143\303\241\155\141
-\162\141\040\123\056\101\056\060\202\002\042\060\015\006\011\052
-\206\110\206\367\015\001\001\001\005\000\003\202\002\017\000\060
-\202\002\012\002\202\002\001\000\253\153\211\243\123\314\110\043
-\010\373\303\317\121\226\010\056\270\010\172\155\074\220\027\206
-\251\351\355\056\023\064\107\262\320\160\334\311\074\320\215\312
-\356\113\027\253\320\205\260\247\043\004\313\250\242\374\345\165
-\333\100\312\142\211\217\120\236\001\075\046\133\030\204\034\313
-\174\067\267\175\354\323\177\163\031\260\152\262\330\210\212\055
-\105\164\250\367\263\270\300\324\332\315\042\211\164\115\132\025
-\071\163\030\164\117\265\353\231\247\301\036\210\264\302\223\220
-\143\227\363\247\247\022\262\011\042\007\063\331\221\315\016\234
-\037\016\040\307\356\273\063\215\217\302\322\130\247\137\375\145
-\067\342\210\302\330\217\206\165\136\371\055\247\207\063\362\170
-\067\057\213\274\035\206\067\071\261\224\362\330\274\112\234\203
-\030\132\006\374\363\324\324\272\214\025\011\045\360\371\266\215
-\004\176\027\022\063\153\127\110\114\117\333\046\036\353\314\220
-\347\213\371\150\174\160\017\243\052\320\072\070\337\067\227\342
-\133\336\200\141\323\200\330\221\203\102\132\114\004\211\150\021
-\074\254\137\150\200\101\314\140\102\316\015\132\052\014\017\233
-\060\300\246\360\206\333\253\111\327\227\155\110\213\371\003\300
-\122\147\233\022\367\302\362\056\230\145\102\331\326\232\343\320
-\031\061\014\255\207\325\127\002\172\060\350\206\046\373\217\043
-\212\124\207\344\277\074\356\353\303\165\110\137\036\071\157\201
-\142\154\305\055\304\027\124\031\267\067\215\234\067\221\310\366
-\013\325\352\143\157\203\254\070\302\363\077\336\232\373\341\043
-\141\360\310\046\313\066\310\241\363\060\217\244\243\242\241\335
-\123\263\336\360\232\062\037\203\221\171\060\301\251\037\123\233
-\123\242\025\123\077\335\235\263\020\073\110\175\211\017\374\355
-\003\365\373\045\144\165\016\027\031\015\217\000\026\147\171\172
-\100\374\055\131\007\331\220\372\232\255\075\334\200\212\346\134
-\065\242\147\114\021\153\261\370\200\144\000\055\157\042\141\305
-\254\113\046\345\132\020\202\233\244\203\173\064\367\236\211\221
-\040\227\216\267\102\307\146\303\320\351\244\326\365\040\215\304
-\303\225\254\104\012\235\133\163\074\046\075\057\112\276\247\311
-\247\020\036\373\237\120\151\363\002\003\001\000\001\243\201\346
-\060\201\343\060\017\006\003\125\035\023\001\001\377\004\005\060
-\003\001\001\377\060\016\006\003\125\035\017\001\001\377\004\004
-\003\002\001\006\060\035\006\003\125\035\016\004\026\004\024\321
-\011\320\351\327\316\171\164\124\371\072\060\263\364\155\054\003
-\003\033\150\060\201\240\006\003\125\035\040\004\201\230\060\201
-\225\060\201\222\006\004\125\035\040\000\060\201\211\060\053\006
-\010\053\006\001\005\005\007\002\001\026\037\150\164\164\160\072
-\057\057\167\167\167\056\143\145\162\164\151\143\141\155\141\162
-\141\056\143\157\155\057\144\160\143\057\060\132\006\010\053\006
-\001\005\005\007\002\002\060\116\032\114\114\151\155\151\164\141
-\143\151\157\156\145\163\040\144\145\040\147\141\162\141\156\164
-\355\141\163\040\144\145\040\145\163\164\145\040\143\145\162\164
-\151\146\151\143\141\144\157\040\163\145\040\160\165\145\144\145
-\156\040\145\156\143\157\156\164\162\141\162\040\145\156\040\154
-\141\040\104\120\103\056\060\015\006\011\052\206\110\206\367\015
-\001\001\005\005\000\003\202\002\001\000\134\224\265\270\105\221
-\115\216\141\037\003\050\017\123\174\346\244\131\251\263\212\172
-\305\260\377\010\174\054\243\161\034\041\023\147\241\225\022\100
-\065\203\203\217\164\333\063\134\360\111\166\012\201\122\335\111
-\324\232\062\063\357\233\247\313\165\345\172\313\227\022\220\134
-\272\173\305\233\337\273\071\043\310\377\230\316\012\115\042\001
-\110\007\176\212\300\325\040\102\224\104\357\277\167\242\211\147
-\110\033\100\003\005\241\211\354\317\142\343\075\045\166\146\277
-\046\267\273\042\276\157\377\071\127\164\272\172\311\001\225\301
-\225\121\350\253\054\370\261\206\040\351\077\313\065\133\322\027
-\351\052\376\203\023\027\100\356\210\142\145\133\325\073\140\351
-\173\074\270\311\325\177\066\002\045\252\150\302\061\025\267\060
-\145\353\177\035\110\171\261\317\071\342\102\200\026\323\365\223
-\043\374\114\227\311\132\067\154\174\042\330\112\315\322\216\066
-\203\071\221\220\020\310\361\311\065\176\077\270\323\201\306\040
-\144\032\266\120\302\041\244\170\334\320\057\073\144\223\164\360
-\226\220\361\357\373\011\132\064\100\226\360\066\022\301\243\164
-\214\223\176\101\336\167\213\354\206\331\322\017\077\055\321\314
-\100\242\211\146\110\036\040\263\234\043\131\163\251\104\163\274
-\044\171\220\126\067\263\306\051\176\243\017\361\051\071\357\176
-\134\050\062\160\065\254\332\270\310\165\146\374\233\114\071\107
-\216\033\157\233\115\002\124\042\063\357\141\272\236\051\204\357
-\116\113\063\107\166\227\152\313\176\137\375\025\246\236\102\103
-\133\146\132\212\210\015\367\026\271\077\121\145\053\146\152\213
-\321\070\122\242\326\106\021\372\374\232\034\164\236\217\227\013
-\002\117\144\306\365\150\323\113\055\377\244\067\036\213\077\277
-\104\276\141\106\241\204\075\010\047\114\201\040\167\211\010\352
-\147\100\136\154\010\121\137\064\132\214\226\150\315\327\367\211
-\302\034\323\062\000\257\122\313\323\140\133\052\072\107\176\153
-\060\063\241\142\051\177\112\271\341\055\347\024\043\016\016\030
-\107\341\171\374\025\125\320\261\374\045\161\143\165\063\034\043
-\053\257\134\331\355\107\167\140\016\073\017\036\322\300\334\144
-\005\211\374\170\326\134\054\046\103\251
-END
-CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
-
-# Trust for Certificate "AC Raiz Certicamara S.A."
-# Issuer: CN=AC Ra..z Certic..mara S.A.,O=Sociedad Cameral de Certificaci..n Digital - Certic..mara S.A.,C=CO
-# Serial Number:07:7e:52:93:7b:e0:15:e3:57:f0:69:8c:cb:ec:0c
-# Subject: CN=AC Ra..z Certic..mara S.A.,O=Sociedad Cameral de Certificaci..n Digital - Certic..mara S.A.,C=CO
-# Not Valid Before: Mon Nov 27 20:46:29 2006
-# Not Valid After : Tue Apr 02 21:42:02 2030
-# Fingerprint (MD5): 93:2A:3E:F6:FD:23:69:0D:71:20:D4:2B:47:99:2B:A6
-# Fingerprint (SHA1): CB:A1:C5:F8:B0:E3:5E:B8:B9:45:12:D3:F9:34:A2:E9:06:10:D3:36
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "AC Ra\xC3\xADz Certic\xC3\xA1mara S.A."
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\313\241\305\370\260\343\136\270\271\105\022\323\371\064\242\351
-\006\020\323\066
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\223\052\076\366\375\043\151\015\161\040\324\053\107\231\053\246
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\173\061\013\060\011\006\003\125\004\006\023\002\103\117\061
-\107\060\105\006\003\125\004\012\014\076\123\157\143\151\145\144
-\141\144\040\103\141\155\145\162\141\154\040\144\145\040\103\145
-\162\164\151\146\151\143\141\143\151\303\263\156\040\104\151\147
-\151\164\141\154\040\055\040\103\145\162\164\151\143\303\241\155
-\141\162\141\040\123\056\101\056\061\043\060\041\006\003\125\004
-\003\014\032\101\103\040\122\141\303\255\172\040\103\145\162\164
-\151\143\303\241\155\141\162\141\040\123\056\101\056
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\017\007\176\122\223\173\340\025\343\127\360\151\214\313\354
-\014
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
# Certificate "Deutsche Telekom Root CA 2"
#
# Issuer: CN=Deutsche Telekom Root CA 2,OU=T-TeleSec Trust Center,O=Deutsche Telekom AG,C=DE
@@ -7382,136 +7055,6 @@ CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
-# Certificate "ComSign CA"
-#
-# Issuer: C=IL,O=ComSign,CN=ComSign CA
-# Serial Number:14:13:96:83:14:55:8c:ea:7b:63:e5:fc:34:87:77:44
-# Subject: C=IL,O=ComSign,CN=ComSign CA
-# Not Valid Before: Wed Mar 24 11:32:18 2004
-# Not Valid After : Mon Mar 19 15:02:18 2029
-# Fingerprint (MD5): CD:F4:39:F3:B5:18:50:D7:3E:A4:C5:91:A0:3E:21:4B
-# Fingerprint (SHA1): E1:A4:5B:14:1A:21:DA:1A:79:F4:1A:42:A9:61:D6:69:CD:06:34:C1
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "ComSign CA"
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\064\061\023\060\021\006\003\125\004\003\023\012\103\157\155
-\123\151\147\156\040\103\101\061\020\060\016\006\003\125\004\012
-\023\007\103\157\155\123\151\147\156\061\013\060\011\006\003\125
-\004\006\023\002\111\114
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\064\061\023\060\021\006\003\125\004\003\023\012\103\157\155
-\123\151\147\156\040\103\101\061\020\060\016\006\003\125\004\012
-\023\007\103\157\155\123\151\147\156\061\013\060\011\006\003\125
-\004\006\023\002\111\114
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\020\024\023\226\203\024\125\214\352\173\143\345\374\064\207
-\167\104
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\003\223\060\202\002\173\240\003\002\001\002\002\020\024
-\023\226\203\024\125\214\352\173\143\345\374\064\207\167\104\060
-\015\006\011\052\206\110\206\367\015\001\001\005\005\000\060\064
-\061\023\060\021\006\003\125\004\003\023\012\103\157\155\123\151
-\147\156\040\103\101\061\020\060\016\006\003\125\004\012\023\007
-\103\157\155\123\151\147\156\061\013\060\011\006\003\125\004\006
-\023\002\111\114\060\036\027\015\060\064\060\063\062\064\061\061
-\063\062\061\070\132\027\015\062\071\060\063\061\071\061\065\060
-\062\061\070\132\060\064\061\023\060\021\006\003\125\004\003\023
-\012\103\157\155\123\151\147\156\040\103\101\061\020\060\016\006
-\003\125\004\012\023\007\103\157\155\123\151\147\156\061\013\060
-\011\006\003\125\004\006\023\002\111\114\060\202\001\042\060\015
-\006\011\052\206\110\206\367\015\001\001\001\005\000\003\202\001
-\017\000\060\202\001\012\002\202\001\001\000\360\344\124\151\053
-\323\307\217\152\104\344\176\130\047\370\013\320\344\224\022\212
-\361\033\070\070\057\037\061\234\006\324\054\247\336\013\052\256
-\032\240\343\236\152\277\237\074\307\156\242\371\213\144\154\072
-\255\205\125\121\124\245\070\125\270\253\203\004\362\077\144\066
-\367\300\215\103\103\152\146\321\367\027\052\325\357\066\372\060
-\020\102\327\123\315\371\372\063\163\114\263\351\204\040\212\326
-\101\047\065\344\070\372\224\233\270\172\344\171\037\063\373\033
-\330\041\011\050\174\115\030\151\136\144\212\172\031\223\312\176
-\354\363\162\347\067\007\130\131\050\254\102\371\305\377\315\077
-\347\245\372\070\261\320\014\307\331\122\032\123\326\201\314\102
-\172\065\133\355\113\072\172\366\265\216\314\377\017\174\344\140
-\066\207\057\255\360\241\045\175\377\322\113\021\210\160\124\246
-\101\250\147\123\122\102\136\344\064\236\344\276\243\354\252\142
-\135\335\303\114\246\202\101\344\063\013\254\311\063\017\144\202
-\127\052\375\014\255\066\341\014\256\113\305\357\073\231\331\043
-\263\133\135\264\127\354\164\160\014\052\117\002\003\001\000\001
-\243\201\240\060\201\235\060\014\006\003\125\035\023\004\005\060
-\003\001\001\377\060\075\006\003\125\035\037\004\066\060\064\060
-\062\240\060\240\056\206\054\150\164\164\160\072\057\057\146\145
-\144\151\162\056\143\157\155\163\151\147\156\056\143\157\056\151
-\154\057\143\162\154\057\103\157\155\123\151\147\156\103\101\056
-\143\162\154\060\016\006\003\125\035\017\001\001\377\004\004\003
-\002\001\206\060\037\006\003\125\035\043\004\030\060\026\200\024
-\113\001\233\076\126\032\145\066\166\313\173\227\252\222\005\356
-\062\347\050\061\060\035\006\003\125\035\016\004\026\004\024\113
-\001\233\076\126\032\145\066\166\313\173\227\252\222\005\356\062
-\347\050\061\060\015\006\011\052\206\110\206\367\015\001\001\005
-\005\000\003\202\001\001\000\320\331\245\176\376\051\140\105\235
-\176\203\317\156\274\107\156\365\032\236\124\166\102\161\264\074
-\130\077\055\100\045\102\366\201\234\361\211\020\310\016\252\170
-\117\070\011\127\260\074\300\010\374\065\216\361\110\121\215\014
-\161\164\272\204\304\327\162\233\204\174\070\116\144\006\047\052
-\341\247\265\354\010\231\264\012\015\324\205\163\310\022\341\065
-\355\361\005\061\035\163\231\014\353\226\312\335\323\346\205\252
-\360\212\373\165\301\362\011\074\145\145\144\363\114\330\255\313
-\210\151\363\344\203\267\014\275\027\132\226\027\312\133\377\255
-\273\034\351\055\204\200\330\041\276\205\122\331\324\164\271\151
-\205\272\115\355\050\062\353\371\141\112\344\304\066\036\031\334
-\157\204\021\037\225\365\203\050\030\250\063\222\103\047\335\135
-\023\004\105\117\207\325\106\315\075\250\272\360\363\270\126\044
-\105\353\067\307\341\166\117\162\071\030\337\176\164\162\307\163
-\055\071\352\140\346\255\021\242\126\207\173\303\150\232\376\370
-\214\160\250\337\145\062\364\244\100\214\241\302\104\003\016\224
-\000\147\240\161\000\202\110
-END
-CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
-
-# Trust for Certificate "ComSign CA"
-# Issuer: C=IL,O=ComSign,CN=ComSign CA
-# Serial Number:14:13:96:83:14:55:8c:ea:7b:63:e5:fc:34:87:77:44
-# Subject: C=IL,O=ComSign,CN=ComSign CA
-# Not Valid Before: Wed Mar 24 11:32:18 2004
-# Not Valid After : Mon Mar 19 15:02:18 2029
-# Fingerprint (MD5): CD:F4:39:F3:B5:18:50:D7:3E:A4:C5:91:A0:3E:21:4B
-# Fingerprint (SHA1): E1:A4:5B:14:1A:21:DA:1A:79:F4:1A:42:A9:61:D6:69:CD:06:34:C1
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "ComSign CA"
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\341\244\133\024\032\041\332\032\171\364\032\102\251\141\326\151
-\315\006\064\301
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\315\364\071\363\265\030\120\327\076\244\305\221\240\076\041\113
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\064\061\023\060\021\006\003\125\004\003\023\012\103\157\155
-\123\151\147\156\040\103\101\061\020\060\016\006\003\125\004\012
-\023\007\103\157\155\123\151\147\156\061\013\060\011\006\003\125
-\004\006\023\002\111\114
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\020\024\023\226\203\024\125\214\352\173\143\345\374\064\207
-\167\104
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
# Certificate "Cybertrust Global Root"
#
# Issuer: CN=Cybertrust Global Root,O="Cybertrust, Inc"
@@ -19149,707 +18692,6 @@ CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
#
-# Certificate "Certplus Root CA G1"
-#
-# Issuer: CN=Certplus Root CA G1,O=Certplus,C=FR
-# Serial Number:11:20:55:83:e4:2d:3e:54:56:85:2d:83:37:b7:2c:dc:46:11
-# Subject: CN=Certplus Root CA G1,O=Certplus,C=FR
-# Not Valid Before: Mon May 26 00:00:00 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): 15:2A:40:2B:FC:DF:2C:D5:48:05:4D:22:75:B3:9C:7F:CA:3E:C0:97:80:78:B0:F0:EA:76:E5:61:A6:C7:43:3E
-# Fingerprint (SHA1): 22:FD:D0:B7:FD:A2:4E:0D:AC:49:2C:A0:AC:A6:7B:6A:1F:E3:F7:66
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "Certplus Root CA G1"
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
-\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
-\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
-\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
-\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\125\203\344\055\076\124\126\205\055\203\067\267
-\054\334\106\021
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\005\153\060\202\003\123\240\003\002\001\002\002\022\021
-\040\125\203\344\055\076\124\126\205\055\203\067\267\054\334\106
-\021\060\015\006\011\052\206\110\206\367\015\001\001\015\005\000
-\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
-\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
-\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
-\060\036\027\015\061\064\060\065\062\066\060\060\060\060\060\060
-\132\027\015\063\070\060\061\061\065\060\060\060\060\060\060\132
-\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
-\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
-\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
-\060\202\002\042\060\015\006\011\052\206\110\206\367\015\001\001
-\001\005\000\003\202\002\017\000\060\202\002\012\002\202\002\001
-\000\332\120\207\266\332\270\251\076\235\144\372\126\063\232\126
-\075\026\345\003\225\262\064\034\232\155\142\005\324\330\217\347
-\211\144\237\272\333\144\213\144\346\171\052\141\315\257\217\132
-\211\221\145\271\130\374\264\003\137\221\077\055\020\025\340\176
-\317\274\374\177\103\147\250\255\136\066\043\330\230\263\115\363
-\103\236\071\174\052\374\354\210\325\210\356\160\275\205\026\055
-\352\113\211\074\243\161\102\376\034\375\323\034\055\020\270\206
-\124\352\103\270\333\306\207\332\250\256\200\045\317\172\046\035
-\252\221\260\110\157\256\265\336\236\330\327\372\000\375\306\217
-\320\121\273\142\175\244\261\214\262\377\040\021\272\065\143\005
-\206\107\140\103\063\220\366\107\242\003\117\226\115\235\117\301
-\352\352\234\242\376\064\056\336\267\312\033\166\244\267\255\237
-\351\250\324\170\077\170\376\362\070\011\066\035\322\026\002\310
-\354\052\150\257\365\216\224\357\055\023\172\036\102\112\035\025
-\061\256\014\004\127\374\141\163\363\061\126\206\061\200\240\304
-\021\156\060\166\343\224\360\137\004\304\254\207\162\211\230\305
-\235\314\127\010\232\364\014\374\175\172\005\072\372\107\200\071
-\266\317\204\023\167\157\047\352\377\226\147\027\010\155\351\015
-\326\043\120\060\260\025\164\023\076\345\057\377\016\315\304\013
-\112\135\360\330\000\063\111\146\353\241\030\174\131\056\075\050
-\271\141\161\313\265\245\272\270\352\334\342\160\157\010\152\334
-\207\147\064\357\337\060\162\335\363\311\077\043\377\065\341\276
-\041\051\040\060\201\344\031\245\040\351\045\312\163\061\164\051
-\276\342\102\325\363\262\046\146\307\150\375\031\263\347\040\223
-\231\350\135\340\136\207\347\106\350\045\234\012\051\044\324\315
-\130\206\122\100\044\262\173\017\230\022\040\044\366\220\154\107
-\310\015\273\030\040\056\331\375\374\213\362\051\352\207\164\225
-\340\102\120\170\204\004\101\141\260\364\041\043\217\055\313\050
-\041\362\152\154\364\032\246\305\024\264\067\145\117\225\375\200
-\310\370\162\345\045\153\304\140\261\173\155\216\112\212\163\316
-\131\373\160\172\163\006\023\331\323\164\067\044\101\012\021\157
-\227\334\347\344\176\241\275\025\362\272\207\017\075\150\212\026
-\007\002\003\001\000\001\243\143\060\141\060\016\006\003\125\035
-\017\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035
-\023\001\001\377\004\005\060\003\001\001\377\060\035\006\003\125
-\035\016\004\026\004\024\250\301\300\233\221\250\103\025\174\135
-\006\047\264\052\121\330\227\013\201\261\060\037\006\003\125\035
-\043\004\030\060\026\200\024\250\301\300\233\221\250\103\025\174
-\135\006\047\264\052\121\330\227\013\201\261\060\015\006\011\052
-\206\110\206\367\015\001\001\015\005\000\003\202\002\001\000\234
-\126\157\001\176\321\275\114\365\212\306\360\046\037\344\340\070
-\030\314\062\303\051\073\235\101\051\064\141\306\327\360\000\241
-\353\244\162\217\224\027\274\023\054\165\264\127\356\012\174\011
-\172\334\325\312\241\320\064\023\370\167\253\237\345\376\330\036
-\164\212\205\007\217\177\314\171\172\312\226\315\315\375\117\373
-\375\043\015\220\365\364\136\323\306\141\175\236\021\340\002\356
-\011\004\331\007\335\246\212\267\014\203\044\273\203\120\222\376
-\140\165\021\076\330\235\260\212\172\265\340\235\233\313\220\122
-\113\260\223\052\324\076\026\063\345\236\306\145\025\076\144\073
-\004\077\333\014\217\137\134\035\151\037\257\363\351\041\214\363
-\357\227\366\232\267\031\266\204\164\234\243\124\265\160\116\143
-\330\127\135\123\041\233\100\222\103\372\326\167\125\063\117\144
-\325\373\320\054\152\216\155\045\246\357\205\350\002\304\123\076
-\271\236\207\274\314\065\032\336\241\351\212\143\207\145\036\021
-\052\333\143\167\227\024\276\232\024\231\021\262\300\356\260\117
-\370\024\041\062\103\117\237\253\242\313\250\017\252\073\006\125
-\306\022\051\127\010\324\067\327\207\047\255\111\131\247\221\253
-\104\172\136\215\160\333\227\316\110\120\261\163\223\366\360\203
-\140\371\315\361\341\061\375\133\174\161\041\143\024\024\252\257
-\305\336\223\176\150\261\354\042\242\252\220\165\236\265\103\162
-\352\144\243\204\113\375\014\250\046\153\161\227\356\126\143\146
-\350\102\124\371\307\035\337\320\217\133\337\310\060\157\210\376
-\015\304\063\034\123\250\243\375\110\020\362\344\012\116\341\025
-\127\374\156\144\060\302\125\021\334\352\251\315\112\124\254\051
-\143\104\317\112\100\240\326\150\131\033\063\371\357\072\213\333
-\040\222\334\102\204\277\001\253\207\300\325\040\202\333\306\271
-\203\205\102\134\017\103\073\152\111\065\325\230\364\025\277\372
-\141\201\014\011\040\030\322\320\027\014\313\110\000\120\351\166
-\202\214\144\327\072\240\007\125\314\036\061\300\357\072\264\145
-\373\343\277\102\153\236\017\250\275\153\230\334\330\333\313\213
-\244\335\327\131\364\156\335\376\252\303\221\320\056\102\007\300
-\014\115\123\315\044\261\114\133\036\121\364\337\351\222\372
-END
-CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
-
-# Trust for "Certplus Root CA G1"
-# Issuer: CN=Certplus Root CA G1,O=Certplus,C=FR
-# Serial Number:11:20:55:83:e4:2d:3e:54:56:85:2d:83:37:b7:2c:dc:46:11
-# Subject: CN=Certplus Root CA G1,O=Certplus,C=FR
-# Not Valid Before: Mon May 26 00:00:00 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): 15:2A:40:2B:FC:DF:2C:D5:48:05:4D:22:75:B3:9C:7F:CA:3E:C0:97:80:78:B0:F0:EA:76:E5:61:A6:C7:43:3E
-# Fingerprint (SHA1): 22:FD:D0:B7:FD:A2:4E:0D:AC:49:2C:A0:AC:A6:7B:6A:1F:E3:F7:66
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "Certplus Root CA G1"
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\042\375\320\267\375\242\116\015\254\111\054\240\254\246\173\152
-\037\343\367\146
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\177\011\234\367\331\271\134\151\151\126\325\067\076\024\015\102
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
-\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
-\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\125\203\344\055\076\124\126\205\055\203\067\267
-\054\334\106\021
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
-# Certificate "Certplus Root CA G2"
-#
-# Issuer: CN=Certplus Root CA G2,O=Certplus,C=FR
-# Serial Number:11:20:d9:91:ce:ae:a3:e8:c5:e7:ff:e9:02:af:cf:73:bc:55
-# Subject: CN=Certplus Root CA G2,O=Certplus,C=FR
-# Not Valid Before: Mon May 26 00:00:00 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): 6C:C0:50:41:E6:44:5E:74:69:6C:4C:FB:C9:F8:0F:54:3B:7E:AB:BB:44:B4:CE:6F:78:7C:6A:99:71:C4:2F:17
-# Fingerprint (SHA1): 4F:65:8E:1F:E9:06:D8:28:02:E9:54:47:41:C9:54:25:5D:69:CC:1A
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "Certplus Root CA G2"
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
-\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
-\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\062
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
-\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
-\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\062
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\331\221\316\256\243\350\305\347\377\351\002\257
-\317\163\274\125
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\002\034\060\202\001\242\240\003\002\001\002\002\022\021
-\040\331\221\316\256\243\350\305\347\377\351\002\257\317\163\274
-\125\060\012\006\010\052\206\110\316\075\004\003\003\060\076\061
-\013\060\011\006\003\125\004\006\023\002\106\122\061\021\060\017
-\006\003\125\004\012\014\010\103\145\162\164\160\154\165\163\061
-\034\060\032\006\003\125\004\003\014\023\103\145\162\164\160\154
-\165\163\040\122\157\157\164\040\103\101\040\107\062\060\036\027
-\015\061\064\060\065\062\066\060\060\060\060\060\060\132\027\015
-\063\070\060\061\061\065\060\060\060\060\060\060\132\060\076\061
-\013\060\011\006\003\125\004\006\023\002\106\122\061\021\060\017
-\006\003\125\004\012\014\010\103\145\162\164\160\154\165\163\061
-\034\060\032\006\003\125\004\003\014\023\103\145\162\164\160\154
-\165\163\040\122\157\157\164\040\103\101\040\107\062\060\166\060
-\020\006\007\052\206\110\316\075\002\001\006\005\053\201\004\000
-\042\003\142\000\004\315\017\133\126\202\337\360\105\032\326\255
-\367\171\360\035\311\254\226\326\236\116\234\037\264\102\021\312
-\206\277\155\373\205\243\305\345\031\134\327\356\246\077\151\147
-\330\170\342\246\311\304\333\055\171\056\347\213\215\002\157\061
-\042\115\006\343\140\162\105\235\016\102\167\236\316\317\345\177
-\205\233\030\344\374\314\056\162\323\026\223\116\312\231\143\134
-\241\005\052\154\006\243\143\060\141\060\016\006\003\125\035\017
-\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035\023
-\001\001\377\004\005\060\003\001\001\377\060\035\006\003\125\035
-\016\004\026\004\024\332\203\143\002\171\216\332\114\306\074\043
-\024\330\217\303\040\253\050\140\131\060\037\006\003\125\035\043
-\004\030\060\026\200\024\332\203\143\002\171\216\332\114\306\074
-\043\024\330\217\303\040\253\050\140\131\060\012\006\010\052\206
-\110\316\075\004\003\003\003\150\000\060\145\002\060\160\376\260
-\013\331\367\203\227\354\363\125\035\324\334\263\006\016\376\063
-\230\235\213\071\220\153\224\041\355\266\327\135\326\114\327\041
-\247\347\277\041\017\053\315\367\052\334\205\007\235\002\061\000
-\206\024\026\345\334\260\145\302\300\216\024\237\277\044\026\150
-\345\274\371\171\151\334\255\105\053\367\266\061\163\314\006\245
-\123\223\221\032\223\256\160\152\147\272\327\236\345\141\032\137
-END
-CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
-
-# Trust for "Certplus Root CA G2"
-# Issuer: CN=Certplus Root CA G2,O=Certplus,C=FR
-# Serial Number:11:20:d9:91:ce:ae:a3:e8:c5:e7:ff:e9:02:af:cf:73:bc:55
-# Subject: CN=Certplus Root CA G2,O=Certplus,C=FR
-# Not Valid Before: Mon May 26 00:00:00 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): 6C:C0:50:41:E6:44:5E:74:69:6C:4C:FB:C9:F8:0F:54:3B:7E:AB:BB:44:B4:CE:6F:78:7C:6A:99:71:C4:2F:17
-# Fingerprint (SHA1): 4F:65:8E:1F:E9:06:D8:28:02:E9:54:47:41:C9:54:25:5D:69:CC:1A
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "Certplus Root CA G2"
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\117\145\216\037\351\006\330\050\002\351\124\107\101\311\124\045
-\135\151\314\032
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\247\356\304\170\055\033\356\055\271\051\316\326\247\226\062\061
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
-\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
-\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\062
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\331\221\316\256\243\350\305\347\377\351\002\257
-\317\163\274\125
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
-# Certificate "OpenTrust Root CA G1"
-#
-# Issuer: CN=OpenTrust Root CA G1,O=OpenTrust,C=FR
-# Serial Number:11:20:b3:90:55:39:7d:7f:36:6d:64:c2:a7:9f:6b:63:8e:67
-# Subject: CN=OpenTrust Root CA G1,O=OpenTrust,C=FR
-# Not Valid Before: Mon May 26 08:45:50 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): 56:C7:71:28:D9:8C:18:D9:1B:4C:FD:FF:BC:25:EE:91:03:D4:75:8E:A2:AB:AD:82:6A:90:F3:45:7D:46:0E:B4
-# Fingerprint (SHA1): 79:91:E8:34:F7:E2:EE:DD:08:95:01:52:E9:55:2D:14:E9:58:D5:7E
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "OpenTrust Root CA G1"
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\061
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\061
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\263\220\125\071\175\177\066\155\144\302\247\237
-\153\143\216\147
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\005\157\060\202\003\127\240\003\002\001\002\002\022\021
-\040\263\220\125\071\175\177\066\155\144\302\247\237\153\143\216
-\147\060\015\006\011\052\206\110\206\367\015\001\001\013\005\000
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\061\060\036\027\015\061\064\060\065\062\066\060\070\064\065
-\065\060\132\027\015\063\070\060\061\061\065\060\060\060\060\060
-\060\132\060\100\061\013\060\011\006\003\125\004\006\023\002\106
-\122\061\022\060\020\006\003\125\004\012\014\011\117\160\145\156
-\124\162\165\163\164\061\035\060\033\006\003\125\004\003\014\024
-\117\160\145\156\124\162\165\163\164\040\122\157\157\164\040\103
-\101\040\107\061\060\202\002\042\060\015\006\011\052\206\110\206
-\367\015\001\001\001\005\000\003\202\002\017\000\060\202\002\012
-\002\202\002\001\000\370\171\106\332\226\305\060\136\212\161\003
-\055\160\244\273\260\305\010\334\315\346\065\300\200\244\021\055
-\335\346\207\256\135\075\221\322\207\154\067\267\332\142\236\233
-\302\044\327\217\361\333\246\246\337\106\157\121\246\161\313\076
-\033\061\147\142\367\021\133\064\047\325\171\116\214\233\130\275
-\042\020\015\134\047\014\335\060\345\250\323\135\041\070\164\027
-\376\343\037\266\117\073\153\055\333\175\140\037\214\175\114\005
-\302\353\001\026\025\230\024\216\321\220\167\042\077\354\302\071
-\270\171\072\360\111\044\342\225\221\334\141\064\222\214\124\164
-\357\261\175\214\001\342\070\175\301\137\152\137\044\262\216\142
-\027\255\171\040\255\253\035\267\340\264\226\110\117\146\103\020
-\006\026\044\003\341\340\234\216\306\106\117\216\032\231\341\217
-\271\216\063\154\151\336\130\255\240\016\247\144\124\021\151\104
-\146\117\114\022\247\216\054\175\304\324\133\305\000\064\060\301
-\331\231\376\062\316\007\204\264\116\315\012\377\066\115\142\361
-\247\143\127\344\333\152\247\256\277\053\271\311\346\262\047\211
-\345\176\232\034\115\150\306\301\030\336\063\053\121\106\113\034
-\216\367\075\014\371\212\064\024\304\373\063\065\043\361\314\361
-\052\307\245\273\260\242\316\376\123\153\115\101\033\146\050\262
-\226\372\247\256\012\116\271\071\063\104\234\164\301\223\034\370
-\340\236\044\045\103\361\233\043\202\252\337\054\040\260\334\066
-\116\003\263\174\002\324\346\173\032\252\207\023\277\076\241\164
-\273\233\016\341\300\223\237\327\244\146\312\273\033\073\343\060
-\364\063\131\212\007\162\003\125\347\163\152\003\061\156\157\226
-\033\343\242\237\257\222\307\355\365\102\267\045\114\073\023\004
-\317\034\226\257\034\042\243\320\253\005\262\114\022\043\122\334
-\375\031\133\047\234\036\073\172\375\102\043\333\043\200\023\360
-\274\121\025\124\224\246\167\076\320\164\121\275\121\024\010\071
-\067\313\037\064\251\060\235\122\204\056\125\220\261\272\337\125
-\000\013\330\126\055\261\111\111\162\200\251\142\327\300\366\030
-\021\004\125\315\164\173\317\141\160\171\364\173\054\134\134\222
-\374\345\270\132\253\114\223\225\241\047\356\245\276\317\161\043
-\102\272\233\166\055\002\003\001\000\001\243\143\060\141\060\016
-\006\003\125\035\017\001\001\377\004\004\003\002\001\006\060\017
-\006\003\125\035\023\001\001\377\004\005\060\003\001\001\377\060
-\035\006\003\125\035\016\004\026\004\024\227\106\041\127\041\065
-\332\066\125\307\363\361\067\160\345\010\366\223\051\266\060\037
-\006\003\125\035\043\004\030\060\026\200\024\227\106\041\127\041
-\065\332\066\125\307\363\361\067\160\345\010\366\223\051\266\060
-\015\006\011\052\206\110\206\367\015\001\001\013\005\000\003\202
-\002\001\000\035\335\002\140\174\340\065\247\346\230\173\352\104
-\316\147\100\117\362\223\156\146\324\071\211\046\254\323\115\004
-\074\273\207\041\077\067\364\161\045\332\113\272\253\226\202\201
-\221\266\355\331\261\244\145\227\342\157\144\131\244\226\356\140
-\312\037\043\373\105\272\377\217\044\360\312\251\061\177\171\037
-\200\263\055\062\272\144\147\140\257\271\131\315\337\232\111\323
-\250\202\261\371\230\224\212\314\340\273\340\004\033\231\140\261
-\106\145\334\010\242\262\106\236\104\210\352\223\176\127\026\322
-\025\162\137\056\113\253\324\235\143\270\343\110\345\376\204\056
-\130\012\237\103\035\376\267\030\222\206\103\113\016\234\062\206
-\054\140\365\351\110\352\225\355\160\051\361\325\057\375\065\264
-\127\317\333\205\110\231\271\302\157\154\217\315\170\225\254\144
-\050\375\126\260\303\157\303\276\131\122\341\137\204\217\200\362
-\364\015\066\255\166\263\243\265\341\144\166\072\130\334\175\117
-\136\126\154\345\125\131\127\245\337\361\212\146\060\214\324\122
-\142\070\167\264\276\050\327\312\066\304\233\005\360\370\025\333
-\333\361\357\064\235\035\170\112\210\126\147\156\140\377\217\310
-\213\341\216\275\102\251\063\012\131\102\022\022\052\372\261\235
-\103\216\005\233\231\332\142\255\127\066\263\035\266\015\171\055
-\226\270\353\362\014\113\014\245\224\306\060\247\046\031\055\355
-\114\006\120\060\361\375\130\075\271\113\027\137\031\264\152\204
-\124\264\070\117\071\242\015\226\150\303\050\224\375\355\055\037
-\112\153\103\226\056\220\001\020\373\070\246\201\013\320\277\165
-\323\324\271\316\361\077\157\016\034\036\067\161\345\030\207\165
-\031\077\120\271\136\244\105\064\255\260\312\346\345\023\166\017
-\061\024\251\216\055\224\326\325\205\115\163\025\117\113\362\262
-\076\355\154\275\375\016\235\146\163\260\075\264\367\277\250\340
-\021\244\304\256\165\011\112\143\000\110\040\246\306\235\013\011
-\212\264\340\346\316\076\307\076\046\070\351\053\336\246\010\111
-\003\004\220\212\351\217\277\350\266\264\052\243\043\215\034\034
-\262\071\222\250\217\002\134\100\071\165\324\163\101\002\167\336
-\315\340\103\207\326\344\272\112\303\154\022\177\376\052\346\043
-\326\214\161
-END
-CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
-
-# Trust for "OpenTrust Root CA G1"
-# Issuer: CN=OpenTrust Root CA G1,O=OpenTrust,C=FR
-# Serial Number:11:20:b3:90:55:39:7d:7f:36:6d:64:c2:a7:9f:6b:63:8e:67
-# Subject: CN=OpenTrust Root CA G1,O=OpenTrust,C=FR
-# Not Valid Before: Mon May 26 08:45:50 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): 56:C7:71:28:D9:8C:18:D9:1B:4C:FD:FF:BC:25:EE:91:03:D4:75:8E:A2:AB:AD:82:6A:90:F3:45:7D:46:0E:B4
-# Fingerprint (SHA1): 79:91:E8:34:F7:E2:EE:DD:08:95:01:52:E9:55:2D:14:E9:58:D5:7E
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "OpenTrust Root CA G1"
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\171\221\350\064\367\342\356\335\010\225\001\122\351\125\055\024
-\351\130\325\176
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\166\000\314\201\051\315\125\136\210\152\172\056\367\115\071\332
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\061
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\263\220\125\071\175\177\066\155\144\302\247\237
-\153\143\216\147
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
-# Certificate "OpenTrust Root CA G2"
-#
-# Issuer: CN=OpenTrust Root CA G2,O=OpenTrust,C=FR
-# Serial Number:11:20:a1:69:1b:bf:bd:b9:bd:52:96:8f:23:e8:48:bf:26:11
-# Subject: CN=OpenTrust Root CA G2,O=OpenTrust,C=FR
-# Not Valid Before: Mon May 26 00:00:00 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): 27:99:58:29:FE:6A:75:15:C1:BF:E8:48:F9:C4:76:1D:B1:6C:22:59:29:25:7B:F4:0D:08:94:F2:9E:A8:BA:F2
-# Fingerprint (SHA1): 79:5F:88:60:C5:AB:7C:3D:92:E6:CB:F4:8D:E1:45:CD:11:EF:60:0B
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "OpenTrust Root CA G2"
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\062
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\062
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\241\151\033\277\275\271\275\122\226\217\043\350
-\110\277\046\021
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\005\157\060\202\003\127\240\003\002\001\002\002\022\021
-\040\241\151\033\277\275\271\275\122\226\217\043\350\110\277\046
-\021\060\015\006\011\052\206\110\206\367\015\001\001\015\005\000
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\062\060\036\027\015\061\064\060\065\062\066\060\060\060\060
-\060\060\132\027\015\063\070\060\061\061\065\060\060\060\060\060
-\060\132\060\100\061\013\060\011\006\003\125\004\006\023\002\106
-\122\061\022\060\020\006\003\125\004\012\014\011\117\160\145\156
-\124\162\165\163\164\061\035\060\033\006\003\125\004\003\014\024
-\117\160\145\156\124\162\165\163\164\040\122\157\157\164\040\103
-\101\040\107\062\060\202\002\042\060\015\006\011\052\206\110\206
-\367\015\001\001\001\005\000\003\202\002\017\000\060\202\002\012
-\002\202\002\001\000\314\266\127\245\063\224\020\201\062\123\337
-\141\176\017\166\071\317\134\302\123\165\035\111\172\226\070\335
-\242\163\152\361\157\336\136\242\132\271\161\041\276\066\331\241
-\374\274\356\154\250\174\064\032\161\032\350\032\330\137\016\104
-\006\355\247\340\363\322\141\013\340\062\242\226\321\070\360\302
-\332\001\027\374\344\254\117\350\356\211\036\164\253\117\277\036
-\011\266\066\152\126\363\341\356\226\211\146\044\006\344\315\102
-\072\112\335\340\232\260\304\202\105\263\376\311\253\134\174\076
-\311\353\027\057\014\175\156\256\245\217\310\254\045\012\157\372
-\325\105\230\322\065\011\366\003\103\224\376\331\277\040\225\171
-\200\230\212\331\211\065\273\121\033\244\067\175\374\231\073\253
-\377\277\254\015\217\103\261\231\173\026\020\176\035\157\107\304
-\025\217\004\226\010\006\102\004\370\204\326\035\274\221\246\102
-\276\111\325\152\210\077\274\055\121\321\236\215\340\122\314\127
-\335\065\065\130\333\264\217\044\210\344\213\337\334\153\124\322
-\201\053\262\316\222\113\034\037\106\372\035\330\222\313\166\147
-\265\011\231\011\345\254\027\024\125\160\306\074\240\126\012\003
-\263\334\142\031\337\310\265\060\177\365\074\046\165\021\275\327
-\033\263\207\236\007\257\145\161\345\240\317\032\247\011\020\035
-\223\211\146\133\350\074\142\062\265\265\072\156\351\205\001\213
-\236\103\214\147\163\050\131\133\353\343\334\054\314\245\046\162
-\142\022\264\346\234\203\104\366\121\244\342\300\172\044\127\312
-\016\245\077\072\265\073\213\345\166\356\160\346\222\336\026\134
-\050\133\227\031\047\222\376\172\222\124\316\223\071\012\026\207
-\274\143\263\365\261\223\134\340\156\267\320\352\371\142\062\210
-\104\373\277\047\050\266\060\225\135\022\050\271\225\276\217\123
-\030\345\242\030\026\342\126\244\262\054\020\365\035\067\246\370
-\267\366\320\131\134\211\367\302\325\265\224\164\321\325\376\033
-\266\360\346\326\036\173\322\074\313\250\343\365\030\363\041\037
-\156\357\115\150\006\173\055\135\156\103\211\246\300\371\240\277
-\202\036\317\123\177\264\353\054\333\135\366\152\175\100\044\005
-\162\211\070\001\223\313\161\302\071\135\006\021\366\157\170\370
-\067\015\071\204\047\002\003\001\000\001\243\143\060\141\060\016
-\006\003\125\035\017\001\001\377\004\004\003\002\001\006\060\017
-\006\003\125\035\023\001\001\377\004\005\060\003\001\001\377\060
-\035\006\003\125\035\016\004\026\004\024\152\071\372\102\042\367
-\346\211\000\115\136\175\063\203\313\270\156\167\206\257\060\037
-\006\003\125\035\043\004\030\060\026\200\024\152\071\372\102\042
-\367\346\211\000\115\136\175\063\203\313\270\156\167\206\257\060
-\015\006\011\052\206\110\206\367\015\001\001\015\005\000\003\202
-\002\001\000\230\313\253\100\074\345\063\002\227\177\055\207\246
-\217\324\136\112\257\270\036\347\273\161\373\200\144\045\251\263
-\032\076\150\135\047\046\247\272\052\341\360\127\203\012\144\117
-\036\042\164\033\351\220\137\360\254\317\377\117\150\172\070\244
-\020\154\015\261\307\244\167\200\030\266\242\050\104\166\247\064
-\235\161\204\057\312\131\322\107\210\231\101\042\311\060\230\141
-\156\075\250\250\005\155\321\037\300\121\104\126\177\047\065\002
-\335\136\230\012\102\353\060\277\215\241\233\121\252\073\352\223
-\106\144\305\000\171\336\041\153\366\127\240\206\327\006\162\354
-\160\106\113\213\163\335\240\041\165\076\334\035\300\217\323\117
-\163\034\205\331\376\177\142\310\225\157\266\323\173\214\272\123
-\302\157\233\104\114\171\320\035\160\263\327\237\002\364\262\007
-\260\307\345\370\255\043\016\246\126\311\051\022\167\110\331\057
-\106\375\073\360\374\164\160\222\245\216\070\010\037\144\060\266
-\267\113\373\066\254\020\216\240\122\063\143\235\003\065\126\305
-\151\275\306\043\132\047\224\366\244\022\370\055\063\074\241\126
-\245\137\326\031\351\355\174\010\275\167\315\047\144\314\224\332
-\116\106\120\207\340\371\301\123\200\036\273\255\373\107\122\213
-\033\375\242\371\336\016\042\267\075\063\131\154\324\336\365\225
-\006\062\015\121\031\101\134\076\117\006\367\271\053\200\047\366
-\243\252\172\174\006\341\103\303\023\071\142\032\066\275\340\050
-\056\224\002\344\051\056\140\125\256\100\075\260\164\222\136\360
-\040\144\226\077\137\105\135\210\265\212\332\002\240\133\105\124
-\336\070\075\011\300\250\112\145\106\026\374\252\277\124\116\115
-\133\276\070\103\267\050\312\213\063\252\032\045\272\045\134\051
-\057\133\112\156\214\352\055\234\052\366\005\166\340\167\227\200
-\210\335\147\023\157\035\150\044\213\117\267\164\201\345\364\140
-\237\172\125\327\076\067\332\026\153\076\167\254\256\030\160\225
-\010\171\051\003\212\376\301\073\263\077\032\017\244\073\136\037
-\130\241\225\311\253\057\163\112\320\055\156\232\131\017\125\030
-\170\055\074\121\246\227\213\346\273\262\160\252\114\021\336\377
-\174\053\067\324\172\321\167\064\217\347\371\102\367\074\201\014
-\113\122\012
-END
-CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
-
-# Trust for "OpenTrust Root CA G2"
-# Issuer: CN=OpenTrust Root CA G2,O=OpenTrust,C=FR
-# Serial Number:11:20:a1:69:1b:bf:bd:b9:bd:52:96:8f:23:e8:48:bf:26:11
-# Subject: CN=OpenTrust Root CA G2,O=OpenTrust,C=FR
-# Not Valid Before: Mon May 26 00:00:00 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): 27:99:58:29:FE:6A:75:15:C1:BF:E8:48:F9:C4:76:1D:B1:6C:22:59:29:25:7B:F4:0D:08:94:F2:9E:A8:BA:F2
-# Fingerprint (SHA1): 79:5F:88:60:C5:AB:7C:3D:92:E6:CB:F4:8D:E1:45:CD:11:EF:60:0B
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "OpenTrust Root CA G2"
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\171\137\210\140\305\253\174\075\222\346\313\364\215\341\105\315
-\021\357\140\013
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\127\044\266\131\044\153\256\310\376\034\014\040\362\300\116\353
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\062
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\241\151\033\277\275\271\275\122\226\217\043\350
-\110\277\046\021
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
-# Certificate "OpenTrust Root CA G3"
-#
-# Issuer: CN=OpenTrust Root CA G3,O=OpenTrust,C=FR
-# Serial Number:11:20:e6:f8:4c:fc:24:b0:be:05:40:ac:da:83:1b:34:60:3f
-# Subject: CN=OpenTrust Root CA G3,O=OpenTrust,C=FR
-# Not Valid Before: Mon May 26 00:00:00 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): B7:C3:62:31:70:6E:81:07:8C:36:7C:B8:96:19:8F:1E:32:08:DD:92:69:49:DD:8F:57:09:A4:10:F7:5B:62:92
-# Fingerprint (SHA1): 6E:26:64:F3:56:BF:34:55:BF:D1:93:3F:7C:01:DE:D8:13:DA:8A:A6
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "OpenTrust Root CA G3"
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\063
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\063
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\346\370\114\374\044\260\276\005\100\254\332\203
-\033\064\140\077
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\002\041\060\202\001\246\240\003\002\001\002\002\022\021
-\040\346\370\114\374\044\260\276\005\100\254\332\203\033\064\140
-\077\060\012\006\010\052\206\110\316\075\004\003\003\060\100\061
-\013\060\011\006\003\125\004\006\023\002\106\122\061\022\060\020
-\006\003\125\004\012\014\011\117\160\145\156\124\162\165\163\164
-\061\035\060\033\006\003\125\004\003\014\024\117\160\145\156\124
-\162\165\163\164\040\122\157\157\164\040\103\101\040\107\063\060
-\036\027\015\061\064\060\065\062\066\060\060\060\060\060\060\132
-\027\015\063\070\060\061\061\065\060\060\060\060\060\060\132\060
-\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061\022
-\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162\165
-\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160\145
-\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040\107
-\063\060\166\060\020\006\007\052\206\110\316\075\002\001\006\005
-\053\201\004\000\042\003\142\000\004\112\356\130\256\115\312\146
-\336\006\072\243\021\374\340\030\360\156\034\272\055\060\014\211
-\331\326\356\233\163\203\251\043\025\214\057\131\212\132\335\024
-\352\235\131\053\103\267\006\354\062\266\272\356\101\265\255\135
-\241\205\314\352\035\024\146\243\147\176\106\342\224\363\347\266
-\126\241\025\131\241\117\067\227\271\042\036\275\021\353\364\262
-\037\136\303\024\232\345\331\227\231\243\143\060\141\060\016\006
-\003\125\035\017\001\001\377\004\004\003\002\001\006\060\017\006
-\003\125\035\023\001\001\377\004\005\060\003\001\001\377\060\035
-\006\003\125\035\016\004\026\004\024\107\167\303\024\213\142\071
-\014\311\157\341\120\115\320\020\130\334\225\210\155\060\037\006
-\003\125\035\043\004\030\060\026\200\024\107\167\303\024\213\142
-\071\014\311\157\341\120\115\320\020\130\334\225\210\155\060\012
-\006\010\052\206\110\316\075\004\003\003\003\151\000\060\146\002
-\061\000\217\250\334\235\272\014\004\027\372\025\351\075\057\051
-\001\227\277\201\026\063\100\223\154\374\371\355\200\160\157\252
-\217\333\204\302\213\365\065\312\006\334\144\157\150\026\341\217
-\221\271\002\061\000\330\113\245\313\302\320\010\154\351\030\373
-\132\335\115\137\044\013\260\000\041\045\357\217\247\004\046\161
-\342\174\151\345\135\232\370\101\037\073\071\223\223\235\125\352
-\315\215\361\373\301
-END
-CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
-
-# Trust for "OpenTrust Root CA G3"
-# Issuer: CN=OpenTrust Root CA G3,O=OpenTrust,C=FR
-# Serial Number:11:20:e6:f8:4c:fc:24:b0:be:05:40:ac:da:83:1b:34:60:3f
-# Subject: CN=OpenTrust Root CA G3,O=OpenTrust,C=FR
-# Not Valid Before: Mon May 26 00:00:00 2014
-# Not Valid After : Fri Jan 15 00:00:00 2038
-# Fingerprint (SHA-256): B7:C3:62:31:70:6E:81:07:8C:36:7C:B8:96:19:8F:1E:32:08:DD:92:69:49:DD:8F:57:09:A4:10:F7:5B:62:92
-# Fingerprint (SHA1): 6E:26:64:F3:56:BF:34:55:BF:D1:93:3F:7C:01:DE:D8:13:DA:8A:A6
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "OpenTrust Root CA G3"
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\156\046\144\363\126\277\064\125\277\321\223\077\174\001\336\330
-\023\332\212\246
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\041\067\264\027\026\222\173\147\106\160\251\226\327\250\023\044
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
-\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
-\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
-\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
-\107\063
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\022\021\040\346\370\114\374\044\260\276\005\100\254\332\203
-\033\064\140\077
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
# Certificate "ISRG Root X1"
#
# Issuer: CN=ISRG Root X1,O=Internet Security Research Group,C=US
@@ -22993,3 +21835,1321 @@ CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "GlobalSign Root CA - R6"
+#
+# Issuer: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R6
+# Serial Number:45:e6:bb:03:83:33:c3:85:65:48:e6:ff:45:51
+# Subject: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R6
+# Not Valid Before: Wed Dec 10 00:00:00 2014
+# Not Valid After : Sun Dec 10 00:00:00 2034
+# Fingerprint (SHA-256): 2C:AB:EA:FE:37:D0:6C:A2:2A:BA:73:91:C0:03:3D:25:98:29:52:C4:53:64:73:49:76:3A:3A:B5:AD:6C:CF:69
+# Fingerprint (SHA1): 80:94:64:0E:B5:A7:A1:CA:11:9C:1F:DD:D5:9F:81:02:63:A7:FB:D1
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GlobalSign Root CA - R6"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\114\061\040\060\036\006\003\125\004\013\023\027\107\154\157
+\142\141\154\123\151\147\156\040\122\157\157\164\040\103\101\040
+\055\040\122\066\061\023\060\021\006\003\125\004\012\023\012\107
+\154\157\142\141\154\123\151\147\156\061\023\060\021\006\003\125
+\004\003\023\012\107\154\157\142\141\154\123\151\147\156
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\114\061\040\060\036\006\003\125\004\013\023\027\107\154\157
+\142\141\154\123\151\147\156\040\122\157\157\164\040\103\101\040
+\055\040\122\066\061\023\060\021\006\003\125\004\012\023\012\107
+\154\157\142\141\154\123\151\147\156\061\023\060\021\006\003\125
+\004\003\023\012\107\154\157\142\141\154\123\151\147\156
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\016\105\346\273\003\203\063\303\205\145\110\346\377\105\121
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\005\203\060\202\003\153\240\003\002\001\002\002\016\105
+\346\273\003\203\063\303\205\145\110\346\377\105\121\060\015\006
+\011\052\206\110\206\367\015\001\001\014\005\000\060\114\061\040
+\060\036\006\003\125\004\013\023\027\107\154\157\142\141\154\123
+\151\147\156\040\122\157\157\164\040\103\101\040\055\040\122\066
+\061\023\060\021\006\003\125\004\012\023\012\107\154\157\142\141
+\154\123\151\147\156\061\023\060\021\006\003\125\004\003\023\012
+\107\154\157\142\141\154\123\151\147\156\060\036\027\015\061\064
+\061\062\061\060\060\060\060\060\060\060\132\027\015\063\064\061
+\062\061\060\060\060\060\060\060\060\132\060\114\061\040\060\036
+\006\003\125\004\013\023\027\107\154\157\142\141\154\123\151\147
+\156\040\122\157\157\164\040\103\101\040\055\040\122\066\061\023
+\060\021\006\003\125\004\012\023\012\107\154\157\142\141\154\123
+\151\147\156\061\023\060\021\006\003\125\004\003\023\012\107\154
+\157\142\141\154\123\151\147\156\060\202\002\042\060\015\006\011
+\052\206\110\206\367\015\001\001\001\005\000\003\202\002\017\000
+\060\202\002\012\002\202\002\001\000\225\007\350\163\312\146\371
+\354\024\312\173\074\367\015\010\361\264\105\013\054\202\264\110
+\306\353\133\074\256\203\270\101\222\063\024\244\157\177\351\052
+\314\306\260\210\153\305\266\211\321\306\262\377\024\316\121\024
+\041\354\112\335\033\132\306\326\207\356\115\072\025\006\355\144
+\146\013\222\200\312\104\336\163\224\116\363\247\211\177\117\170
+\143\010\310\022\120\155\102\146\057\115\271\171\050\115\122\032
+\212\032\200\267\031\201\016\176\304\212\274\144\114\041\034\103
+\150\327\075\074\212\305\262\146\325\220\232\267\061\006\305\276
+\342\155\062\006\246\036\371\271\353\252\243\270\277\276\202\143
+\120\320\360\030\211\337\344\017\171\365\352\242\037\052\322\160
+\056\173\347\274\223\273\155\123\342\110\174\214\020\007\070\377
+\146\262\167\141\176\340\352\214\074\252\264\244\366\363\225\112
+\022\007\155\375\214\262\211\317\320\240\141\167\310\130\164\260
+\324\043\072\367\135\072\312\242\333\235\011\336\135\104\055\220
+\361\201\315\127\222\372\176\274\120\004\143\064\337\153\223\030
+\276\153\066\262\071\344\254\044\066\267\360\357\266\034\023\127
+\223\266\336\262\370\342\205\267\163\242\270\065\252\105\362\340
+\235\066\241\157\124\212\361\162\126\156\056\210\305\121\102\104
+\025\224\356\243\305\070\226\233\116\116\132\013\107\363\006\066
+\111\167\060\274\161\067\345\246\354\041\010\165\374\346\141\026
+\077\167\325\331\221\227\204\012\154\324\002\115\164\300\024\355
+\375\071\373\203\362\136\024\241\004\260\013\351\376\356\217\341
+\156\013\262\010\263\141\146\011\152\261\006\072\145\226\131\300
+\360\065\375\311\332\050\215\032\021\207\160\201\012\250\232\165
+\035\236\072\206\005\000\236\333\200\326\045\371\334\005\236\047
+\131\114\166\071\133\352\371\245\241\330\203\017\321\377\337\060
+\021\371\205\317\063\110\365\312\155\144\024\054\172\130\117\323
+\113\010\111\305\225\144\032\143\016\171\075\365\263\214\312\130
+\255\234\102\105\171\156\016\207\031\134\124\261\145\266\277\214
+\233\334\023\351\015\157\270\056\334\147\156\311\213\021\265\204
+\024\212\000\031\160\203\171\221\227\221\324\032\047\277\067\036
+\062\007\330\024\143\074\050\114\257\002\003\001\000\001\243\143
+\060\141\060\016\006\003\125\035\017\001\001\377\004\004\003\002
+\001\006\060\017\006\003\125\035\023\001\001\377\004\005\060\003
+\001\001\377\060\035\006\003\125\035\016\004\026\004\024\256\154
+\005\243\223\023\342\242\347\342\327\034\326\307\360\177\310\147
+\123\240\060\037\006\003\125\035\043\004\030\060\026\200\024\256
+\154\005\243\223\023\342\242\347\342\327\034\326\307\360\177\310
+\147\123\240\060\015\006\011\052\206\110\206\367\015\001\001\014
+\005\000\003\202\002\001\000\203\045\355\350\321\375\225\122\315
+\236\300\004\240\221\151\346\134\320\204\336\334\255\242\117\350
+\107\170\326\145\230\251\133\250\074\207\174\002\212\321\156\267
+\026\163\346\137\300\124\230\325\164\276\301\315\342\021\221\255
+\043\030\075\335\341\162\104\226\264\225\136\300\173\216\231\170
+\026\103\023\126\127\263\242\263\073\265\167\334\100\162\254\243
+\353\233\065\076\261\010\041\241\347\304\103\067\171\062\276\265
+\347\234\054\114\274\103\051\231\216\060\323\254\041\340\343\035
+\372\330\007\063\166\124\000\042\052\271\115\040\056\160\150\332
+\345\123\374\203\134\323\235\362\377\104\014\104\146\362\322\343
+\275\106\000\032\155\002\272\045\135\215\241\061\121\335\124\106
+\034\115\333\231\226\357\032\034\004\134\246\025\357\170\340\171
+\376\135\333\076\252\114\125\375\232\025\251\157\341\246\373\337
+\160\060\351\303\356\102\106\355\302\223\005\211\372\175\143\173
+\077\320\161\201\174\000\350\230\256\016\170\064\303\045\373\257
+\012\237\040\153\335\073\023\217\022\214\342\101\032\110\172\163
+\240\167\151\307\266\134\177\202\310\036\376\130\033\050\053\250
+\154\255\136\155\300\005\322\173\267\353\200\376\045\067\376\002
+\233\150\254\102\135\303\356\365\314\334\360\120\165\322\066\151
+\234\346\173\004\337\156\006\151\266\336\012\011\110\131\207\353
+\173\024\140\172\144\252\151\103\357\221\307\114\354\030\335\154
+\357\123\055\214\231\341\136\362\162\076\317\124\310\275\147\354
+\244\017\114\105\377\323\271\060\043\007\114\217\020\277\206\226
+\331\231\132\264\231\127\034\244\314\273\025\211\123\272\054\005
+\017\344\304\236\031\261\030\064\325\114\235\272\355\367\037\257
+\044\225\004\170\250\003\273\356\201\345\332\137\174\213\112\241
+\220\164\045\247\263\076\113\310\054\126\275\307\310\357\070\342
+\134\222\360\171\367\234\204\272\164\055\141\001\040\176\176\321
+\362\117\007\131\137\213\055\103\122\353\106\014\224\341\365\146
+\107\171\167\325\124\133\037\255\044\067\313\105\132\116\240\104
+\110\310\330\260\231\305\025\204\011\366\326\111\111\300\145\270
+\346\032\161\156\240\250\361\202\350\105\076\154\326\002\327\012
+\147\203\005\132\311\244\020
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "GlobalSign Root CA - R6"
+# Issuer: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R6
+# Serial Number:45:e6:bb:03:83:33:c3:85:65:48:e6:ff:45:51
+# Subject: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R6
+# Not Valid Before: Wed Dec 10 00:00:00 2014
+# Not Valid After : Sun Dec 10 00:00:00 2034
+# Fingerprint (SHA-256): 2C:AB:EA:FE:37:D0:6C:A2:2A:BA:73:91:C0:03:3D:25:98:29:52:C4:53:64:73:49:76:3A:3A:B5:AD:6C:CF:69
+# Fingerprint (SHA1): 80:94:64:0E:B5:A7:A1:CA:11:9C:1F:DD:D5:9F:81:02:63:A7:FB:D1
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GlobalSign Root CA - R6"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\200\224\144\016\265\247\241\312\021\234\037\335\325\237\201\002
+\143\247\373\321
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\117\335\007\344\324\042\144\071\036\014\067\102\352\321\306\256
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\114\061\040\060\036\006\003\125\004\013\023\027\107\154\157
+\142\141\154\123\151\147\156\040\122\157\157\164\040\103\101\040
+\055\040\122\066\061\023\060\021\006\003\125\004\012\023\012\107
+\154\157\142\141\154\123\151\147\156\061\023\060\021\006\003\125
+\004\003\023\012\107\154\157\142\141\154\123\151\147\156
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\016\105\346\273\003\203\063\303\205\145\110\346\377\105\121
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "OISTE WISeKey Global Root GC CA"
+#
+# Issuer: CN=OISTE WISeKey Global Root GC CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH
+# Serial Number:21:2a:56:0c:ae:da:0c:ab:40:45:bf:2b:a2:2d:3a:ea
+# Subject: CN=OISTE WISeKey Global Root GC CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH
+# Not Valid Before: Tue May 09 09:48:34 2017
+# Not Valid After : Fri May 09 09:58:33 2042
+# Fingerprint (SHA-256): 85:60:F9:1C:36:24:DA:BA:95:70:B5:FE:A0:DB:E3:6F:F1:1A:83:23:BE:94:86:85:4F:B3:F3:4A:55:71:19:8D
+# Fingerprint (SHA1): E0:11:84:5E:34:DE:BE:88:81:B9:9C:F6:16:26:D1:96:1F:C3:B9:31
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "OISTE WISeKey Global Root GC CA"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\155\061\013\060\011\006\003\125\004\006\023\002\103\110\061
+\020\060\016\006\003\125\004\012\023\007\127\111\123\145\113\145
+\171\061\042\060\040\006\003\125\004\013\023\031\117\111\123\124
+\105\040\106\157\165\156\144\141\164\151\157\156\040\105\156\144
+\157\162\163\145\144\061\050\060\046\006\003\125\004\003\023\037
+\117\111\123\124\105\040\127\111\123\145\113\145\171\040\107\154
+\157\142\141\154\040\122\157\157\164\040\107\103\040\103\101
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\155\061\013\060\011\006\003\125\004\006\023\002\103\110\061
+\020\060\016\006\003\125\004\012\023\007\127\111\123\145\113\145
+\171\061\042\060\040\006\003\125\004\013\023\031\117\111\123\124
+\105\040\106\157\165\156\144\141\164\151\157\156\040\105\156\144
+\157\162\163\145\144\061\050\060\046\006\003\125\004\003\023\037
+\117\111\123\124\105\040\127\111\123\145\113\145\171\040\107\154
+\157\142\141\154\040\122\157\157\164\040\107\103\040\103\101
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\041\052\126\014\256\332\014\253\100\105\277\053\242\055
+\072\352
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\002\151\060\202\001\357\240\003\002\001\002\002\020\041
+\052\126\014\256\332\014\253\100\105\277\053\242\055\072\352\060
+\012\006\010\052\206\110\316\075\004\003\003\060\155\061\013\060
+\011\006\003\125\004\006\023\002\103\110\061\020\060\016\006\003
+\125\004\012\023\007\127\111\123\145\113\145\171\061\042\060\040
+\006\003\125\004\013\023\031\117\111\123\124\105\040\106\157\165
+\156\144\141\164\151\157\156\040\105\156\144\157\162\163\145\144
+\061\050\060\046\006\003\125\004\003\023\037\117\111\123\124\105
+\040\127\111\123\145\113\145\171\040\107\154\157\142\141\154\040
+\122\157\157\164\040\107\103\040\103\101\060\036\027\015\061\067
+\060\065\060\071\060\071\064\070\063\064\132\027\015\064\062\060
+\065\060\071\060\071\065\070\063\063\132\060\155\061\013\060\011
+\006\003\125\004\006\023\002\103\110\061\020\060\016\006\003\125
+\004\012\023\007\127\111\123\145\113\145\171\061\042\060\040\006
+\003\125\004\013\023\031\117\111\123\124\105\040\106\157\165\156
+\144\141\164\151\157\156\040\105\156\144\157\162\163\145\144\061
+\050\060\046\006\003\125\004\003\023\037\117\111\123\124\105\040
+\127\111\123\145\113\145\171\040\107\154\157\142\141\154\040\122
+\157\157\164\040\107\103\040\103\101\060\166\060\020\006\007\052
+\206\110\316\075\002\001\006\005\053\201\004\000\042\003\142\000
+\004\114\351\120\300\306\017\162\030\274\330\361\272\263\211\342
+\171\112\243\026\247\153\124\044\333\121\377\352\364\011\044\303
+\013\042\237\313\152\047\202\201\015\322\300\257\061\344\164\202
+\156\312\045\331\214\165\235\361\333\320\232\242\113\041\176\026
+\247\143\220\322\071\324\261\207\170\137\030\226\017\120\033\065
+\067\017\152\306\334\331\023\115\244\216\220\067\346\275\133\061
+\221\243\124\060\122\060\016\006\003\125\035\017\001\001\377\004
+\004\003\002\001\006\060\017\006\003\125\035\023\001\001\377\004
+\005\060\003\001\001\377\060\035\006\003\125\035\016\004\026\004
+\024\110\207\024\254\343\303\236\220\140\072\327\312\211\356\323
+\255\214\264\120\146\060\020\006\011\053\006\001\004\001\202\067
+\025\001\004\003\002\001\000\060\012\006\010\052\206\110\316\075
+\004\003\003\003\150\000\060\145\002\060\046\307\151\133\334\325
+\347\262\347\310\014\214\214\303\335\171\214\033\143\325\311\122
+\224\116\115\202\112\163\036\262\200\204\251\045\300\114\132\155
+\111\051\140\170\023\342\176\110\353\144\002\061\000\333\064\040
+\062\010\377\232\111\002\266\210\336\024\257\135\154\231\161\215
+\032\077\213\327\340\242\066\206\034\007\202\072\166\123\375\302
+\242\355\357\173\260\200\117\130\017\113\123\071\275
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "OISTE WISeKey Global Root GC CA"
+# Issuer: CN=OISTE WISeKey Global Root GC CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH
+# Serial Number:21:2a:56:0c:ae:da:0c:ab:40:45:bf:2b:a2:2d:3a:ea
+# Subject: CN=OISTE WISeKey Global Root GC CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH
+# Not Valid Before: Tue May 09 09:48:34 2017
+# Not Valid After : Fri May 09 09:58:33 2042
+# Fingerprint (SHA-256): 85:60:F9:1C:36:24:DA:BA:95:70:B5:FE:A0:DB:E3:6F:F1:1A:83:23:BE:94:86:85:4F:B3:F3:4A:55:71:19:8D
+# Fingerprint (SHA1): E0:11:84:5E:34:DE:BE:88:81:B9:9C:F6:16:26:D1:96:1F:C3:B9:31
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "OISTE WISeKey Global Root GC CA"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\340\021\204\136\064\336\276\210\201\271\234\366\026\046\321\226
+\037\303\271\061
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\251\326\271\055\057\223\144\370\245\151\312\221\351\150\007\043
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\155\061\013\060\011\006\003\125\004\006\023\002\103\110\061
+\020\060\016\006\003\125\004\012\023\007\127\111\123\145\113\145
+\171\061\042\060\040\006\003\125\004\013\023\031\117\111\123\124
+\105\040\106\157\165\156\144\141\164\151\157\156\040\105\156\144
+\157\162\163\145\144\061\050\060\046\006\003\125\004\003\023\037
+\117\111\123\124\105\040\127\111\123\145\113\145\171\040\107\154
+\157\142\141\154\040\122\157\157\164\040\107\103\040\103\101
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\041\052\126\014\256\332\014\253\100\105\277\053\242\055
+\072\352
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "GTS Root R1"
+#
+# Issuer: CN=GTS Root R1,O=Google Trust Services LLC,C=US
+# Serial Number:6e:47:a9:c5:4b:47:0c:0d:ec:33:d0:89:b9:1c:f4:e1
+# Subject: CN=GTS Root R1,O=Google Trust Services LLC,C=US
+# Not Valid Before: Wed Jun 22 00:00:00 2016
+# Not Valid After : Sun Jun 22 00:00:00 2036
+# Fingerprint (SHA-256): 2A:57:54:71:E3:13:40:BC:21:58:1C:BD:2C:F1:3E:15:84:63:20:3E:CE:94:BC:F9:D3:CC:19:6B:F0:9A:54:72
+# Fingerprint (SHA1): E1:C9:50:E6:EF:22:F8:4C:56:45:72:8B:92:20:60:D7:D5:A7:A3:E8
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GTS Root R1"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\061
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\061
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\156\107\251\305\113\107\014\015\354\063\320\211\271\034
+\364\341
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\005\132\060\202\003\102\240\003\002\001\002\002\020\156
+\107\251\305\113\107\014\015\354\063\320\211\271\034\364\341\060
+\015\006\011\052\206\110\206\367\015\001\001\014\005\000\060\107
+\061\013\060\011\006\003\125\004\006\023\002\125\123\061\042\060
+\040\006\003\125\004\012\023\031\107\157\157\147\154\145\040\124
+\162\165\163\164\040\123\145\162\166\151\143\145\163\040\114\114
+\103\061\024\060\022\006\003\125\004\003\023\013\107\124\123\040
+\122\157\157\164\040\122\061\060\036\027\015\061\066\060\066\062
+\062\060\060\060\060\060\060\132\027\015\063\066\060\066\062\062
+\060\060\060\060\060\060\132\060\107\061\013\060\011\006\003\125
+\004\006\023\002\125\123\061\042\060\040\006\003\125\004\012\023
+\031\107\157\157\147\154\145\040\124\162\165\163\164\040\123\145
+\162\166\151\143\145\163\040\114\114\103\061\024\060\022\006\003
+\125\004\003\023\013\107\124\123\040\122\157\157\164\040\122\061
+\060\202\002\042\060\015\006\011\052\206\110\206\367\015\001\001
+\001\005\000\003\202\002\017\000\060\202\002\012\002\202\002\001
+\000\266\021\002\213\036\343\241\167\233\073\334\277\224\076\267
+\225\247\100\074\241\375\202\371\175\062\006\202\161\366\366\214
+\177\373\350\333\274\152\056\227\227\243\214\113\371\053\366\261
+\371\316\204\035\261\371\305\227\336\357\271\362\243\351\274\022
+\211\136\247\252\122\253\370\043\047\313\244\261\234\143\333\327
+\231\176\360\012\136\353\150\246\364\306\132\107\015\115\020\063
+\343\116\261\023\243\310\030\154\113\354\374\011\220\337\235\144
+\051\045\043\007\241\264\322\075\056\140\340\317\322\011\207\273
+\315\110\360\115\302\302\172\210\212\273\272\317\131\031\326\257
+\217\260\007\260\236\061\361\202\301\300\337\056\246\155\154\031
+\016\265\330\176\046\032\105\003\075\260\171\244\224\050\255\017
+\177\046\345\250\010\376\226\350\074\150\224\123\356\203\072\210
+\053\025\226\011\262\340\172\214\056\165\326\234\353\247\126\144
+\217\226\117\150\256\075\227\302\204\217\300\274\100\300\013\134
+\275\366\207\263\065\154\254\030\120\177\204\340\114\315\222\323
+\040\351\063\274\122\231\257\062\265\051\263\045\052\264\110\371
+\162\341\312\144\367\346\202\020\215\350\235\302\212\210\372\070
+\146\212\374\143\371\001\371\170\375\173\134\167\372\166\207\372
+\354\337\261\016\171\225\127\264\275\046\357\326\001\321\353\026
+\012\273\216\013\265\305\305\212\125\253\323\254\352\221\113\051
+\314\031\244\062\045\116\052\361\145\104\320\002\316\252\316\111
+\264\352\237\174\203\260\100\173\347\103\253\247\154\243\217\175
+\211\201\372\114\245\377\325\216\303\316\113\340\265\330\263\216
+\105\317\166\300\355\100\053\375\123\017\260\247\325\073\015\261
+\212\242\003\336\061\255\314\167\352\157\173\076\326\337\221\042
+\022\346\276\372\330\062\374\020\143\024\121\162\336\135\326\026
+\223\275\051\150\063\357\072\146\354\007\212\046\337\023\327\127
+\145\170\047\336\136\111\024\000\242\000\177\232\250\041\266\251
+\261\225\260\245\271\015\026\021\332\307\154\110\074\100\340\176
+\015\132\315\126\074\321\227\005\271\313\113\355\071\113\234\304
+\077\322\125\023\156\044\260\326\161\372\364\301\272\314\355\033
+\365\376\201\101\330\000\230\075\072\310\256\172\230\067\030\005
+\225\002\003\001\000\001\243\102\060\100\060\016\006\003\125\035
+\017\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035
+\023\001\001\377\004\005\060\003\001\001\377\060\035\006\003\125
+\035\016\004\026\004\024\344\257\053\046\161\032\053\110\047\205
+\057\122\146\054\357\360\211\023\161\076\060\015\006\011\052\206
+\110\206\367\015\001\001\014\005\000\003\202\002\001\000\070\226
+\012\356\075\264\226\036\137\357\235\234\013\063\237\053\340\312
+\375\322\216\012\037\101\164\245\174\252\204\324\345\362\036\346
+\067\122\062\234\013\321\141\035\277\050\301\266\104\051\065\165
+\167\230\262\174\331\275\164\254\212\150\343\251\061\011\051\001
+\140\163\343\107\174\123\250\220\112\047\357\113\327\237\223\347
+\202\066\316\232\150\014\202\347\317\324\020\026\157\137\016\231
+\134\366\037\161\175\357\357\173\057\176\352\066\326\227\160\013
+\025\356\327\134\126\152\063\245\343\111\070\014\270\175\373\215
+\205\244\261\131\136\364\152\341\335\241\366\144\104\256\346\121
+\203\041\146\306\021\076\363\316\107\356\234\050\037\045\332\377
+\254\146\225\335\065\017\134\357\040\054\142\375\221\272\251\314
+\374\132\234\223\201\203\051\227\112\174\132\162\264\071\320\267
+\167\313\171\375\151\072\222\067\355\156\070\145\106\176\351\140
+\275\171\210\227\137\070\022\364\356\257\133\202\310\206\325\341
+\231\155\214\004\362\166\272\111\366\156\351\155\036\137\240\357
+\047\202\166\100\370\246\323\130\134\017\054\102\332\102\306\173
+\210\064\307\301\330\105\233\301\076\305\141\035\331\143\120\111
+\366\064\205\152\340\030\305\156\107\253\101\102\051\233\366\140
+\015\322\061\323\143\230\043\223\132\000\201\110\264\357\315\212
+\315\311\317\231\356\331\236\252\066\341\150\113\161\111\024\066
+\050\072\075\035\316\232\217\045\346\200\161\141\053\265\173\314
+\371\045\026\201\341\061\137\241\243\176\026\244\234\026\152\227
+\030\275\166\162\245\013\236\035\066\346\057\241\057\276\160\221
+\017\250\346\332\370\304\222\100\154\045\176\173\263\011\334\262
+\027\255\200\104\360\150\245\217\224\165\377\164\132\350\250\002
+\174\014\011\342\251\113\013\240\205\013\142\271\357\241\061\222
+\373\357\366\121\004\211\154\350\251\164\241\273\027\263\265\375
+\111\017\174\074\354\203\030\040\103\116\325\223\272\264\064\261
+\037\026\066\037\014\346\144\071\026\114\334\340\376\035\310\251
+\142\075\100\352\312\305\064\002\264\256\211\210\063\065\334\054
+\023\163\330\047\361\320\162\356\165\073\042\336\230\150\146\133
+\361\306\143\107\125\034\272\245\010\121\165\246\110\045
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "GTS Root R1"
+# Issuer: CN=GTS Root R1,O=Google Trust Services LLC,C=US
+# Serial Number:6e:47:a9:c5:4b:47:0c:0d:ec:33:d0:89:b9:1c:f4:e1
+# Subject: CN=GTS Root R1,O=Google Trust Services LLC,C=US
+# Not Valid Before: Wed Jun 22 00:00:00 2016
+# Not Valid After : Sun Jun 22 00:00:00 2036
+# Fingerprint (SHA-256): 2A:57:54:71:E3:13:40:BC:21:58:1C:BD:2C:F1:3E:15:84:63:20:3E:CE:94:BC:F9:D3:CC:19:6B:F0:9A:54:72
+# Fingerprint (SHA1): E1:C9:50:E6:EF:22:F8:4C:56:45:72:8B:92:20:60:D7:D5:A7:A3:E8
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GTS Root R1"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\341\311\120\346\357\042\370\114\126\105\162\213\222\040\140\327
+\325\247\243\350
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\202\032\357\324\322\112\362\237\342\075\227\006\024\160\162\205
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\061
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\156\107\251\305\113\107\014\015\354\063\320\211\271\034
+\364\341
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "GTS Root R2"
+#
+# Issuer: CN=GTS Root R2,O=Google Trust Services LLC,C=US
+# Serial Number:6e:47:a9:c6:5a:b3:e7:20:c5:30:9a:3f:68:52:f2:6f
+# Subject: CN=GTS Root R2,O=Google Trust Services LLC,C=US
+# Not Valid Before: Wed Jun 22 00:00:00 2016
+# Not Valid After : Sun Jun 22 00:00:00 2036
+# Fingerprint (SHA-256): C4:5D:7B:B0:8E:6D:67:E6:2E:42:35:11:0B:56:4E:5F:78:FD:92:EF:05:8C:84:0A:EA:4E:64:55:D7:58:5C:60
+# Fingerprint (SHA1): D2:73:96:2A:2A:5E:39:9F:73:3F:E1:C7:1E:64:3F:03:38:34:FC:4D
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GTS Root R2"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\062
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\062
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\156\107\251\306\132\263\347\040\305\060\232\077\150\122
+\362\157
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\005\132\060\202\003\102\240\003\002\001\002\002\020\156
+\107\251\306\132\263\347\040\305\060\232\077\150\122\362\157\060
+\015\006\011\052\206\110\206\367\015\001\001\014\005\000\060\107
+\061\013\060\011\006\003\125\004\006\023\002\125\123\061\042\060
+\040\006\003\125\004\012\023\031\107\157\157\147\154\145\040\124
+\162\165\163\164\040\123\145\162\166\151\143\145\163\040\114\114
+\103\061\024\060\022\006\003\125\004\003\023\013\107\124\123\040
+\122\157\157\164\040\122\062\060\036\027\015\061\066\060\066\062
+\062\060\060\060\060\060\060\132\027\015\063\066\060\066\062\062
+\060\060\060\060\060\060\132\060\107\061\013\060\011\006\003\125
+\004\006\023\002\125\123\061\042\060\040\006\003\125\004\012\023
+\031\107\157\157\147\154\145\040\124\162\165\163\164\040\123\145
+\162\166\151\143\145\163\040\114\114\103\061\024\060\022\006\003
+\125\004\003\023\013\107\124\123\040\122\157\157\164\040\122\062
+\060\202\002\042\060\015\006\011\052\206\110\206\367\015\001\001
+\001\005\000\003\202\002\017\000\060\202\002\012\002\202\002\001
+\000\316\336\375\246\373\354\354\024\064\074\007\006\132\154\131
+\367\031\065\335\367\301\235\125\252\323\315\073\244\223\162\357
+\012\372\155\235\366\360\205\200\133\241\110\122\237\071\305\267
+\356\050\254\357\313\166\150\024\271\337\255\001\154\231\037\304
+\042\035\237\376\162\167\340\054\133\257\344\004\277\117\162\240
+\032\064\230\350\071\150\354\225\045\173\166\241\346\151\271\205
+\031\275\211\214\376\255\355\066\352\163\274\377\203\342\313\175
+\301\322\316\112\263\215\005\236\213\111\223\337\301\133\320\156
+\136\360\056\060\056\202\374\372\274\264\027\012\110\345\210\233
+\305\233\153\336\260\312\264\003\360\332\364\220\270\145\144\367
+\134\114\255\350\176\146\136\231\327\270\302\076\310\320\023\235
+\255\356\344\105\173\211\125\367\212\037\142\122\204\022\263\302
+\100\227\343\212\037\107\221\246\164\132\322\370\261\143\050\020
+\270\263\011\270\126\167\100\242\046\230\171\306\376\337\045\356
+\076\345\240\177\324\141\017\121\113\074\077\214\332\341\160\164
+\330\302\150\241\371\301\014\351\241\342\177\273\125\074\166\006
+\356\152\116\314\222\210\060\115\232\275\117\013\110\232\204\265
+\230\243\325\373\163\301\127\141\335\050\126\165\023\256\207\216
+\347\014\121\011\020\165\210\114\274\215\371\173\074\324\042\110
+\037\052\334\353\153\273\104\261\313\063\161\062\106\257\255\112
+\361\214\350\164\072\254\347\032\042\163\200\322\060\367\045\102
+\307\042\073\073\022\255\226\056\306\303\166\007\252\040\267\065
+\111\127\351\222\111\350\166\026\162\061\147\053\226\176\212\243
+\307\224\126\042\277\152\113\176\001\041\262\043\062\337\344\232
+\104\155\131\133\135\365\000\240\034\233\306\170\227\215\220\377
+\233\310\252\264\257\021\121\071\136\331\373\147\255\325\133\021
+\235\062\232\033\275\325\272\133\245\311\313\045\151\123\125\047
+\134\340\312\066\313\210\141\373\036\267\320\313\356\026\373\323
+\246\114\336\222\245\324\342\337\365\006\124\336\056\235\113\264
+\223\060\252\201\316\335\032\334\121\163\015\117\160\351\345\266
+\026\041\031\171\262\346\211\013\165\144\312\325\253\274\011\301
+\030\241\377\324\124\241\205\074\375\024\044\003\262\207\323\244
+\267\002\003\001\000\001\243\102\060\100\060\016\006\003\125\035
+\017\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035
+\023\001\001\377\004\005\060\003\001\001\377\060\035\006\003\125
+\035\016\004\026\004\024\273\377\312\216\043\237\117\231\312\333
+\342\150\246\245\025\047\027\036\331\016\060\015\006\011\052\206
+\110\206\367\015\001\001\014\005\000\003\202\002\001\000\266\151
+\360\246\167\376\236\356\013\201\255\341\300\251\307\371\065\035
+\100\202\253\346\004\264\337\313\367\035\017\203\360\176\023\115
+\215\214\356\343\063\042\303\071\374\100\337\156\101\113\102\123
+\276\026\210\361\322\070\136\304\150\231\034\230\122\223\214\347
+\150\355\033\152\163\172\005\100\115\177\145\073\326\130\361\316
+\203\107\140\343\377\227\251\234\140\167\030\125\265\176\010\223
+\317\320\366\074\147\003\025\141\011\371\201\171\365\354\123\244
+\237\311\217\001\213\163\304\167\166\334\203\242\365\014\111\032
+\250\166\336\222\233\144\370\263\054\305\047\323\007\300\010\200
+\244\230\222\343\001\226\002\252\002\356\217\073\305\321\155\012
+\063\060\163\170\271\117\124\026\277\013\007\241\244\134\346\313
+\311\134\204\217\017\340\025\167\054\176\046\176\332\304\113\333
+\247\026\167\007\260\315\165\350\162\102\326\225\204\235\206\203
+\362\344\220\315\011\107\324\213\003\160\332\132\306\003\102\364
+\355\067\242\360\033\120\124\113\016\330\204\336\031\050\231\201
+\107\256\011\033\077\110\321\303\157\342\260\140\027\365\356\043
+\002\245\332\000\133\155\220\253\356\242\351\033\073\351\307\104
+\047\105\216\153\237\365\244\204\274\167\371\153\227\254\076\121
+\105\242\021\246\314\205\356\012\150\362\076\120\070\172\044\142
+\036\027\040\067\155\152\115\267\011\233\311\374\244\130\365\266
+\373\234\116\030\273\225\002\347\241\255\233\007\356\066\153\044
+\322\071\206\301\223\203\120\322\201\106\250\137\142\127\054\273
+\154\144\210\010\156\357\023\124\137\335\055\304\147\143\323\317
+\211\067\277\235\040\364\373\172\203\233\240\036\201\000\120\302
+\344\014\042\131\122\020\355\103\126\207\000\370\024\122\247\035
+\213\223\214\242\115\106\177\047\306\161\233\044\336\344\332\206
+\213\015\176\153\040\301\300\236\341\145\330\152\243\246\350\205
+\213\072\007\010\034\272\365\217\125\232\030\165\176\345\354\201
+\146\321\041\163\241\065\104\013\200\075\133\234\136\157\052\027
+\226\321\203\043\210\146\155\346\206\342\160\062\057\122\042\347
+\310\347\177\304\054\140\135\057\303\257\236\105\005\303\204\002
+\267\375\054\010\122\117\202\335\243\360\324\206\011\002
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "GTS Root R2"
+# Issuer: CN=GTS Root R2,O=Google Trust Services LLC,C=US
+# Serial Number:6e:47:a9:c6:5a:b3:e7:20:c5:30:9a:3f:68:52:f2:6f
+# Subject: CN=GTS Root R2,O=Google Trust Services LLC,C=US
+# Not Valid Before: Wed Jun 22 00:00:00 2016
+# Not Valid After : Sun Jun 22 00:00:00 2036
+# Fingerprint (SHA-256): C4:5D:7B:B0:8E:6D:67:E6:2E:42:35:11:0B:56:4E:5F:78:FD:92:EF:05:8C:84:0A:EA:4E:64:55:D7:58:5C:60
+# Fingerprint (SHA1): D2:73:96:2A:2A:5E:39:9F:73:3F:E1:C7:1E:64:3F:03:38:34:FC:4D
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GTS Root R2"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\322\163\226\052\052\136\071\237\163\077\341\307\036\144\077\003
+\070\064\374\115
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\104\355\232\016\244\011\073\000\362\256\114\243\306\141\260\213
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\062
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\156\107\251\306\132\263\347\040\305\060\232\077\150\122
+\362\157
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "GTS Root R3"
+#
+# Issuer: CN=GTS Root R3,O=Google Trust Services LLC,C=US
+# Serial Number:6e:47:a9:c7:6c:a9:73:24:40:89:0f:03:55:dd:8d:1d
+# Subject: CN=GTS Root R3,O=Google Trust Services LLC,C=US
+# Not Valid Before: Wed Jun 22 00:00:00 2016
+# Not Valid After : Sun Jun 22 00:00:00 2036
+# Fingerprint (SHA-256): 15:D5:B8:77:46:19:EA:7D:54:CE:1C:A6:D0:B0:C4:03:E0:37:A9:17:F1:31:E8:A0:4E:1E:6B:7A:71:BA:BC:E5
+# Fingerprint (SHA1): 30:D4:24:6F:07:FF:DB:91:89:8A:0B:E9:49:66:11:EB:8C:5E:46:E5
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GTS Root R3"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\063
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\063
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\156\107\251\307\154\251\163\044\100\211\017\003\125\335
+\215\035
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\002\014\060\202\001\221\240\003\002\001\002\002\020\156
+\107\251\307\154\251\163\044\100\211\017\003\125\335\215\035\060
+\012\006\010\052\206\110\316\075\004\003\003\060\107\061\013\060
+\011\006\003\125\004\006\023\002\125\123\061\042\060\040\006\003
+\125\004\012\023\031\107\157\157\147\154\145\040\124\162\165\163
+\164\040\123\145\162\166\151\143\145\163\040\114\114\103\061\024
+\060\022\006\003\125\004\003\023\013\107\124\123\040\122\157\157
+\164\040\122\063\060\036\027\015\061\066\060\066\062\062\060\060
+\060\060\060\060\132\027\015\063\066\060\066\062\062\060\060\060
+\060\060\060\132\060\107\061\013\060\011\006\003\125\004\006\023
+\002\125\123\061\042\060\040\006\003\125\004\012\023\031\107\157
+\157\147\154\145\040\124\162\165\163\164\040\123\145\162\166\151
+\143\145\163\040\114\114\103\061\024\060\022\006\003\125\004\003
+\023\013\107\124\123\040\122\157\157\164\040\122\063\060\166\060
+\020\006\007\052\206\110\316\075\002\001\006\005\053\201\004\000
+\042\003\142\000\004\037\117\063\207\063\051\212\241\204\336\313
+\307\041\130\101\211\352\126\235\053\113\205\306\035\114\047\274
+\177\046\121\162\157\342\237\326\243\312\314\105\024\106\213\255
+\357\176\206\214\354\261\176\057\377\251\161\235\030\204\105\004
+\101\125\156\053\352\046\177\273\220\001\343\113\031\272\344\124
+\226\105\011\261\325\154\221\104\255\204\023\216\232\214\015\200
+\014\062\366\340\047\243\102\060\100\060\016\006\003\125\035\017
+\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035\023
+\001\001\377\004\005\060\003\001\001\377\060\035\006\003\125\035
+\016\004\026\004\024\301\361\046\272\240\055\256\205\201\317\323
+\361\052\022\275\270\012\147\375\274\060\012\006\010\052\206\110
+\316\075\004\003\003\003\151\000\060\146\002\061\000\200\133\244
+\174\043\300\225\245\054\334\276\211\157\043\271\243\335\145\000
+\122\136\221\254\310\235\162\164\202\123\013\175\251\100\275\150
+\140\305\341\270\124\073\301\066\027\045\330\301\275\002\061\000
+\236\065\222\164\205\045\121\365\044\354\144\122\044\120\245\037
+\333\350\313\311\166\354\354\202\156\365\205\030\123\350\270\343
+\232\051\252\226\323\203\043\311\244\173\141\263\314\002\350\135
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "GTS Root R3"
+# Issuer: CN=GTS Root R3,O=Google Trust Services LLC,C=US
+# Serial Number:6e:47:a9:c7:6c:a9:73:24:40:89:0f:03:55:dd:8d:1d
+# Subject: CN=GTS Root R3,O=Google Trust Services LLC,C=US
+# Not Valid Before: Wed Jun 22 00:00:00 2016
+# Not Valid After : Sun Jun 22 00:00:00 2036
+# Fingerprint (SHA-256): 15:D5:B8:77:46:19:EA:7D:54:CE:1C:A6:D0:B0:C4:03:E0:37:A9:17:F1:31:E8:A0:4E:1E:6B:7A:71:BA:BC:E5
+# Fingerprint (SHA1): 30:D4:24:6F:07:FF:DB:91:89:8A:0B:E9:49:66:11:EB:8C:5E:46:E5
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GTS Root R3"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\060\324\044\157\007\377\333\221\211\212\013\351\111\146\021\353
+\214\136\106\345
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\032\171\133\153\004\122\234\135\307\164\063\033\045\232\371\045
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\063
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\156\107\251\307\154\251\163\044\100\211\017\003\125\335
+\215\035
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "GTS Root R4"
+#
+# Issuer: CN=GTS Root R4,O=Google Trust Services LLC,C=US
+# Serial Number:6e:47:a9:c8:8b:94:b6:e8:bb:3b:2a:d8:a2:b2:c1:99
+# Subject: CN=GTS Root R4,O=Google Trust Services LLC,C=US
+# Not Valid Before: Wed Jun 22 00:00:00 2016
+# Not Valid After : Sun Jun 22 00:00:00 2036
+# Fingerprint (SHA-256): 71:CC:A5:39:1F:9E:79:4B:04:80:25:30:B3:63:E1:21:DA:8A:30:43:BB:26:66:2F:EA:4D:CA:7F:C9:51:A4:BD
+# Fingerprint (SHA1): 2A:1D:60:27:D9:4A:B1:0A:1C:4D:91:5C:CD:33:A0:CB:3E:2D:54:CB
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GTS Root R4"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\064
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\064
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\156\107\251\310\213\224\266\350\273\073\052\330\242\262
+\301\231
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\002\012\060\202\001\221\240\003\002\001\002\002\020\156
+\107\251\310\213\224\266\350\273\073\052\330\242\262\301\231\060
+\012\006\010\052\206\110\316\075\004\003\003\060\107\061\013\060
+\011\006\003\125\004\006\023\002\125\123\061\042\060\040\006\003
+\125\004\012\023\031\107\157\157\147\154\145\040\124\162\165\163
+\164\040\123\145\162\166\151\143\145\163\040\114\114\103\061\024
+\060\022\006\003\125\004\003\023\013\107\124\123\040\122\157\157
+\164\040\122\064\060\036\027\015\061\066\060\066\062\062\060\060
+\060\060\060\060\132\027\015\063\066\060\066\062\062\060\060\060
+\060\060\060\132\060\107\061\013\060\011\006\003\125\004\006\023
+\002\125\123\061\042\060\040\006\003\125\004\012\023\031\107\157
+\157\147\154\145\040\124\162\165\163\164\040\123\145\162\166\151
+\143\145\163\040\114\114\103\061\024\060\022\006\003\125\004\003
+\023\013\107\124\123\040\122\157\157\164\040\122\064\060\166\060
+\020\006\007\052\206\110\316\075\002\001\006\005\053\201\004\000
+\042\003\142\000\004\363\164\163\247\150\213\140\256\103\270\065
+\305\201\060\173\113\111\235\373\301\141\316\346\336\106\275\153
+\325\141\030\065\256\100\335\163\367\211\221\060\132\353\074\356
+\205\174\242\100\166\073\251\306\270\107\330\052\347\222\221\152
+\163\351\261\162\071\237\051\237\242\230\323\137\136\130\206\145
+\017\241\204\145\006\321\334\213\311\307\163\310\214\152\057\345
+\304\253\321\035\212\243\102\060\100\060\016\006\003\125\035\017
+\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035\023
+\001\001\377\004\005\060\003\001\001\377\060\035\006\003\125\035
+\016\004\026\004\024\200\114\326\353\164\377\111\066\243\325\330
+\374\265\076\305\152\360\224\035\214\060\012\006\010\052\206\110
+\316\075\004\003\003\003\147\000\060\144\002\060\152\120\122\164
+\010\304\160\334\236\120\164\041\350\215\172\041\303\117\226\156
+\025\321\042\065\141\055\372\010\067\356\031\155\255\333\262\314
+\175\007\064\365\140\031\054\265\064\331\157\040\002\060\003\161
+\261\272\243\140\013\206\355\232\010\152\225\150\237\342\263\341
+\223\144\174\136\223\246\337\171\055\215\205\343\224\317\043\135
+\161\314\362\260\115\326\376\231\310\224\251\165\242\343
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "GTS Root R4"
+# Issuer: CN=GTS Root R4,O=Google Trust Services LLC,C=US
+# Serial Number:6e:47:a9:c8:8b:94:b6:e8:bb:3b:2a:d8:a2:b2:c1:99
+# Subject: CN=GTS Root R4,O=Google Trust Services LLC,C=US
+# Not Valid Before: Wed Jun 22 00:00:00 2016
+# Not Valid After : Sun Jun 22 00:00:00 2036
+# Fingerprint (SHA-256): 71:CC:A5:39:1F:9E:79:4B:04:80:25:30:B3:63:E1:21:DA:8A:30:43:BB:26:66:2F:EA:4D:CA:7F:C9:51:A4:BD
+# Fingerprint (SHA1): 2A:1D:60:27:D9:4A:B1:0A:1C:4D:91:5C:CD:33:A0:CB:3E:2D:54:CB
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "GTS Root R4"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\052\035\140\047\331\112\261\012\034\115\221\134\315\063\240\313
+\076\055\124\313
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\135\266\152\304\140\027\044\152\032\231\250\113\356\136\264\046
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\125\123\061
+\042\060\040\006\003\125\004\012\023\031\107\157\157\147\154\145
+\040\124\162\165\163\164\040\123\145\162\166\151\143\145\163\040
+\114\114\103\061\024\060\022\006\003\125\004\003\023\013\107\124
+\123\040\122\157\157\164\040\122\064
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\156\107\251\310\213\224\266\350\273\073\052\330\242\262
+\301\231
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "UCA Global G2 Root"
+#
+# Issuer: CN=UCA Global G2 Root,O=UniTrust,C=CN
+# Serial Number:5d:df:b1:da:5a:a3:ed:5d:be:5a:65:20:65:03:90:ef
+# Subject: CN=UCA Global G2 Root,O=UniTrust,C=CN
+# Not Valid Before: Fri Mar 11 00:00:00 2016
+# Not Valid After : Mon Dec 31 00:00:00 2040
+# Fingerprint (SHA-256): 9B:EA:11:C9:76:FE:01:47:64:C1:BE:56:A6:F9:14:B5:A5:60:31:7A:BD:99:88:39:33:82:E5:16:1A:A0:49:3C
+# Fingerprint (SHA1): 28:F9:78:16:19:7A:FF:18:25:18:AA:44:FE:C1:A0:CE:5C:B6:4C:8A
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "UCA Global G2 Root"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\075\061\013\060\011\006\003\125\004\006\023\002\103\116\061
+\021\060\017\006\003\125\004\012\014\010\125\156\151\124\162\165
+\163\164\061\033\060\031\006\003\125\004\003\014\022\125\103\101
+\040\107\154\157\142\141\154\040\107\062\040\122\157\157\164
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\075\061\013\060\011\006\003\125\004\006\023\002\103\116\061
+\021\060\017\006\003\125\004\012\014\010\125\156\151\124\162\165
+\163\164\061\033\060\031\006\003\125\004\003\014\022\125\103\101
+\040\107\154\157\142\141\154\040\107\062\040\122\157\157\164
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\135\337\261\332\132\243\355\135\276\132\145\040\145\003
+\220\357
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\005\106\060\202\003\056\240\003\002\001\002\002\020\135
+\337\261\332\132\243\355\135\276\132\145\040\145\003\220\357\060
+\015\006\011\052\206\110\206\367\015\001\001\013\005\000\060\075
+\061\013\060\011\006\003\125\004\006\023\002\103\116\061\021\060
+\017\006\003\125\004\012\014\010\125\156\151\124\162\165\163\164
+\061\033\060\031\006\003\125\004\003\014\022\125\103\101\040\107
+\154\157\142\141\154\040\107\062\040\122\157\157\164\060\036\027
+\015\061\066\060\063\061\061\060\060\060\060\060\060\132\027\015
+\064\060\061\062\063\061\060\060\060\060\060\060\132\060\075\061
+\013\060\011\006\003\125\004\006\023\002\103\116\061\021\060\017
+\006\003\125\004\012\014\010\125\156\151\124\162\165\163\164\061
+\033\060\031\006\003\125\004\003\014\022\125\103\101\040\107\154
+\157\142\141\154\040\107\062\040\122\157\157\164\060\202\002\042
+\060\015\006\011\052\206\110\206\367\015\001\001\001\005\000\003
+\202\002\017\000\060\202\002\012\002\202\002\001\000\305\346\053
+\157\174\357\046\005\047\243\201\044\332\157\313\001\371\231\232
+\251\062\302\042\207\141\101\221\073\313\303\150\033\006\305\114
+\251\053\301\147\027\042\035\053\355\371\051\211\223\242\170\275
+\222\153\240\243\015\242\176\312\223\263\246\321\214\065\325\165
+\371\027\366\317\105\305\345\172\354\167\223\240\217\043\256\016
+\032\003\177\276\324\320\355\056\173\253\106\043\133\377\054\346
+\124\172\224\300\052\025\360\311\215\260\172\073\044\341\327\150
+\342\061\074\006\063\106\266\124\021\246\245\057\042\124\052\130
+\015\001\002\361\372\025\121\147\154\300\372\327\266\033\177\321
+\126\210\057\032\072\215\073\273\202\021\340\107\000\320\122\207
+\253\373\206\176\017\044\153\100\235\064\147\274\215\307\055\206
+\157\171\076\216\251\074\027\113\177\260\231\343\260\161\140\334
+\013\365\144\303\316\103\274\155\161\271\322\336\047\133\212\350
+\330\306\256\341\131\175\317\050\055\065\270\225\126\032\361\262
+\130\113\267\022\067\310\174\263\355\113\200\341\215\372\062\043
+\266\157\267\110\225\010\261\104\116\205\214\072\002\124\040\057
+\337\277\127\117\073\072\220\041\327\301\046\065\124\040\354\307
+\077\107\354\357\132\277\113\172\301\255\073\027\120\134\142\330
+\017\113\112\334\053\372\156\274\163\222\315\354\307\120\350\101
+\226\327\251\176\155\330\351\035\217\212\265\271\130\222\272\112
+\222\053\014\126\375\200\353\010\360\136\051\156\033\034\014\257
+\217\223\211\255\333\275\243\236\041\312\211\031\354\337\265\303
+\032\353\026\376\170\066\114\326\156\320\076\027\034\220\027\153
+\046\272\373\172\057\277\021\034\030\016\055\163\003\217\240\345
+\065\240\132\342\114\165\035\161\341\071\070\123\170\100\314\203
+\223\327\012\236\235\133\217\212\344\345\340\110\344\110\262\107
+\315\116\052\165\052\173\362\042\366\311\276\011\221\226\127\172
+\210\210\254\356\160\254\371\334\051\343\014\034\073\022\116\104
+\326\247\116\260\046\310\363\331\032\227\221\150\352\357\215\106
+\006\322\126\105\130\232\074\014\017\203\270\005\045\303\071\317
+\073\244\064\211\267\171\022\057\107\305\347\251\227\151\374\246
+\167\147\265\337\173\361\172\145\025\344\141\126\145\002\003\001
+\000\001\243\102\060\100\060\016\006\003\125\035\017\001\001\377
+\004\004\003\002\001\006\060\017\006\003\125\035\023\001\001\377
+\004\005\060\003\001\001\377\060\035\006\003\125\035\016\004\026
+\004\024\201\304\214\314\365\344\060\377\245\014\010\137\214\025
+\147\041\164\001\337\337\060\015\006\011\052\206\110\206\367\015
+\001\001\013\005\000\003\202\002\001\000\023\145\042\365\216\053
+\255\104\344\313\377\271\150\346\303\200\110\075\004\173\372\043
+\057\172\355\066\332\262\316\155\366\346\236\345\137\130\217\313
+\067\062\241\310\145\266\256\070\075\065\033\076\274\073\266\004
+\320\274\371\111\365\233\367\205\305\066\266\313\274\370\310\071
+\325\344\137\007\275\025\124\227\164\312\312\355\117\272\272\144
+\166\237\201\270\204\105\111\114\215\157\242\353\261\314\321\303
+\224\332\104\302\346\342\352\030\350\242\037\047\005\272\327\345
+\326\251\315\335\357\166\230\215\000\016\315\033\372\003\267\216
+\200\130\016\047\077\122\373\224\242\312\136\145\311\326\204\332
+\271\065\161\363\046\300\117\167\346\201\047\322\167\073\232\024
+\157\171\364\366\320\341\323\224\272\320\127\121\275\047\005\015
+\301\375\310\022\060\356\157\215\021\053\010\235\324\324\277\200
+\105\024\232\210\104\332\060\352\264\247\343\356\357\133\202\325
+\076\326\255\170\222\333\134\074\363\330\255\372\270\153\177\304
+\066\050\266\002\025\212\124\054\234\260\027\163\216\320\067\243
+\024\074\230\225\000\014\051\005\133\236\111\111\261\137\307\343
+\313\317\047\145\216\065\027\267\127\310\060\331\101\133\271\024
+\266\350\302\017\224\061\247\224\230\314\152\353\265\341\047\365
+\020\250\001\350\216\022\142\350\210\314\265\177\106\227\300\233
+\020\146\070\032\066\106\137\042\150\075\337\311\306\023\047\253
+\123\006\254\242\074\206\006\145\157\261\176\261\051\104\232\243
+\272\111\151\050\151\217\327\345\137\255\004\206\144\157\032\240
+\014\305\010\142\316\200\243\320\363\354\150\336\276\063\307\027
+\133\177\200\304\114\114\261\246\204\212\303\073\270\011\315\024
+\201\272\030\343\124\127\066\376\333\057\174\107\241\072\063\310
+\371\130\073\104\117\261\312\002\211\004\226\050\150\305\113\270
+\046\211\273\326\063\057\120\325\376\232\211\272\030\062\222\124
+\306\133\340\235\371\136\345\015\042\233\366\332\342\310\041\262
+\142\041\252\206\100\262\056\144\323\137\310\343\176\021\147\105
+\037\005\376\343\242\357\263\250\263\363\175\217\370\014\037\042
+\037\055\160\264\270\001\064\166\060\000\345\043\170\247\126\327
+\120\037\212\373\006\365\302\031\360\320
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "UCA Global G2 Root"
+# Issuer: CN=UCA Global G2 Root,O=UniTrust,C=CN
+# Serial Number:5d:df:b1:da:5a:a3:ed:5d:be:5a:65:20:65:03:90:ef
+# Subject: CN=UCA Global G2 Root,O=UniTrust,C=CN
+# Not Valid Before: Fri Mar 11 00:00:00 2016
+# Not Valid After : Mon Dec 31 00:00:00 2040
+# Fingerprint (SHA-256): 9B:EA:11:C9:76:FE:01:47:64:C1:BE:56:A6:F9:14:B5:A5:60:31:7A:BD:99:88:39:33:82:E5:16:1A:A0:49:3C
+# Fingerprint (SHA1): 28:F9:78:16:19:7A:FF:18:25:18:AA:44:FE:C1:A0:CE:5C:B6:4C:8A
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "UCA Global G2 Root"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\050\371\170\026\031\172\377\030\045\030\252\104\376\301\240\316
+\134\266\114\212
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\200\376\360\304\112\360\134\142\062\237\034\272\170\251\120\370
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\075\061\013\060\011\006\003\125\004\006\023\002\103\116\061
+\021\060\017\006\003\125\004\012\014\010\125\156\151\124\162\165
+\163\164\061\033\060\031\006\003\125\004\003\014\022\125\103\101
+\040\107\154\157\142\141\154\040\107\062\040\122\157\157\164
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\135\337\261\332\132\243\355\135\276\132\145\040\145\003
+\220\357
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "UCA Extended Validation Root"
+#
+# Issuer: CN=UCA Extended Validation Root,O=UniTrust,C=CN
+# Serial Number:4f:d2:2b:8f:f5:64:c8:33:9e:4f:34:58:66:23:70:60
+# Subject: CN=UCA Extended Validation Root,O=UniTrust,C=CN
+# Not Valid Before: Fri Mar 13 00:00:00 2015
+# Not Valid After : Fri Dec 31 00:00:00 2038
+# Fingerprint (SHA-256): D4:3A:F9:B3:54:73:75:5C:96:84:FC:06:D7:D8:CB:70:EE:5C:28:E7:73:FB:29:4E:B4:1E:E7:17:22:92:4D:24
+# Fingerprint (SHA1): A3:A1:B0:6F:24:61:23:4A:E3:36:A5:C2:37:FC:A6:FF:DD:F0:D7:3A
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "UCA Extended Validation Root"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\103\116\061
+\021\060\017\006\003\125\004\012\014\010\125\156\151\124\162\165
+\163\164\061\045\060\043\006\003\125\004\003\014\034\125\103\101
+\040\105\170\164\145\156\144\145\144\040\126\141\154\151\144\141
+\164\151\157\156\040\122\157\157\164
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\103\116\061
+\021\060\017\006\003\125\004\012\014\010\125\156\151\124\162\165
+\163\164\061\045\060\043\006\003\125\004\003\014\034\125\103\101
+\040\105\170\164\145\156\144\145\144\040\126\141\154\151\144\141
+\164\151\157\156\040\122\157\157\164
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\117\322\053\217\365\144\310\063\236\117\064\130\146\043
+\160\140
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\005\132\060\202\003\102\240\003\002\001\002\002\020\117
+\322\053\217\365\144\310\063\236\117\064\130\146\043\160\140\060
+\015\006\011\052\206\110\206\367\015\001\001\013\005\000\060\107
+\061\013\060\011\006\003\125\004\006\023\002\103\116\061\021\060
+\017\006\003\125\004\012\014\010\125\156\151\124\162\165\163\164
+\061\045\060\043\006\003\125\004\003\014\034\125\103\101\040\105
+\170\164\145\156\144\145\144\040\126\141\154\151\144\141\164\151
+\157\156\040\122\157\157\164\060\036\027\015\061\065\060\063\061
+\063\060\060\060\060\060\060\132\027\015\063\070\061\062\063\061
+\060\060\060\060\060\060\132\060\107\061\013\060\011\006\003\125
+\004\006\023\002\103\116\061\021\060\017\006\003\125\004\012\014
+\010\125\156\151\124\162\165\163\164\061\045\060\043\006\003\125
+\004\003\014\034\125\103\101\040\105\170\164\145\156\144\145\144
+\040\126\141\154\151\144\141\164\151\157\156\040\122\157\157\164
+\060\202\002\042\060\015\006\011\052\206\110\206\367\015\001\001
+\001\005\000\003\202\002\017\000\060\202\002\012\002\202\002\001
+\000\251\011\007\050\023\002\260\231\340\144\252\036\103\026\172
+\163\261\221\240\165\076\250\372\343\070\000\172\354\211\152\040
+\017\213\305\260\233\063\003\132\206\306\130\206\325\301\205\273
+\117\306\234\100\115\312\276\356\151\226\270\255\201\060\232\174
+\222\005\353\005\053\232\110\320\270\166\076\226\310\040\273\322
+\260\361\217\330\254\105\106\377\252\147\140\264\167\176\152\037
+\074\032\122\172\004\075\007\074\205\015\204\320\037\166\012\367
+\152\024\337\162\343\064\174\127\116\126\001\076\171\361\252\051
+\073\154\372\370\217\155\115\310\065\337\256\353\334\044\356\171
+\105\247\205\266\005\210\336\210\135\045\174\227\144\147\011\331
+\277\132\025\005\206\363\011\036\354\130\062\063\021\363\167\144
+\260\166\037\344\020\065\027\033\362\016\261\154\244\052\243\163
+\374\011\037\036\062\031\123\021\347\331\263\054\056\166\056\241
+\243\336\176\152\210\011\350\362\007\212\370\262\315\020\347\342
+\163\100\223\273\010\321\077\341\374\013\224\263\045\357\174\246
+\327\321\257\237\377\226\232\365\221\173\230\013\167\324\176\350
+\007\322\142\265\225\071\343\363\361\155\017\016\145\204\212\143
+\124\305\200\266\340\236\113\175\107\046\247\001\010\135\321\210
+\236\327\303\062\104\372\202\112\012\150\124\177\070\123\003\314
+\244\000\063\144\121\131\013\243\202\221\172\136\354\026\302\363
+\052\346\142\332\052\333\131\142\020\045\112\052\201\013\107\007
+\103\006\160\207\322\372\223\021\051\172\110\115\353\224\307\160
+\115\257\147\325\121\261\200\040\001\001\264\172\010\246\220\177
+\116\340\357\007\101\207\257\152\245\136\213\373\317\120\262\232
+\124\257\303\211\272\130\055\365\060\230\261\066\162\071\176\111
+\004\375\051\247\114\171\344\005\127\333\224\271\026\123\215\106
+\263\035\225\141\127\126\177\257\360\026\133\141\130\157\066\120
+\021\013\330\254\053\225\026\032\016\037\010\315\066\064\145\020
+\142\146\325\200\137\024\040\137\055\014\240\170\012\150\326\054
+\327\351\157\053\322\112\005\223\374\236\157\153\147\377\210\361
+\116\245\151\112\122\067\005\352\306\026\215\322\304\231\321\202
+\053\073\272\065\165\367\121\121\130\363\310\007\335\344\264\003
+\177\002\003\001\000\001\243\102\060\100\060\035\006\003\125\035
+\016\004\026\004\024\331\164\072\344\060\075\015\367\022\334\176
+\132\005\237\036\064\232\367\341\024\060\017\006\003\125\035\023
+\001\001\377\004\005\060\003\001\001\377\060\016\006\003\125\035
+\017\001\001\377\004\004\003\002\001\206\060\015\006\011\052\206
+\110\206\367\015\001\001\013\005\000\003\202\002\001\000\066\215
+\227\314\102\025\144\051\067\233\046\054\326\373\256\025\151\054
+\153\032\032\367\137\266\371\007\114\131\352\363\311\310\271\256
+\314\272\056\172\334\300\365\260\055\300\073\257\237\160\005\021
+\152\237\045\117\001\051\160\343\345\014\341\352\132\174\334\111
+\273\301\036\052\201\365\026\113\162\221\310\242\061\271\252\332
+\374\235\037\363\135\100\002\023\374\116\034\006\312\263\024\220
+\124\027\031\022\032\361\037\327\014\151\132\366\161\170\364\224
+\175\221\013\216\354\220\124\216\274\157\241\114\253\374\164\144
+\375\161\232\370\101\007\241\315\221\344\074\232\340\233\062\071
+\163\253\052\325\151\310\170\221\046\061\175\342\307\060\361\374
+\024\170\167\022\016\023\364\335\026\224\277\113\147\173\160\123
+\205\312\260\273\363\070\115\054\220\071\300\015\302\135\153\351
+\342\345\325\210\215\326\054\277\253\033\276\265\050\207\022\027
+\164\156\374\175\374\217\320\207\046\260\033\373\271\154\253\342
+\236\075\025\301\073\056\147\002\130\221\237\357\370\102\037\054
+\267\150\365\165\255\317\265\366\377\021\175\302\360\044\245\255
+\323\372\240\074\251\372\135\334\245\240\357\104\244\276\326\350
+\345\344\023\226\027\173\006\076\062\355\307\267\102\274\166\243
+\330\145\070\053\070\065\121\041\016\016\157\056\064\023\100\341
+\053\147\014\155\112\101\060\030\043\132\062\125\231\311\027\340
+\074\336\366\354\171\255\053\130\031\242\255\054\042\032\225\216
+\276\226\220\135\102\127\304\371\024\003\065\053\034\055\121\127
+\010\247\072\336\077\344\310\264\003\163\302\301\046\200\273\013
+\102\037\255\015\257\046\162\332\314\276\263\243\203\130\015\202
+\305\037\106\121\343\234\030\314\215\233\215\354\111\353\165\120
+\325\214\050\131\312\164\064\332\214\013\041\253\036\352\033\345
+\307\375\025\076\300\027\252\373\043\156\046\106\313\372\371\261
+\162\153\151\317\042\204\013\142\017\254\331\031\000\224\242\166
+\074\324\055\232\355\004\236\055\006\142\020\067\122\034\205\162
+\033\047\345\314\306\061\354\067\354\143\131\233\013\035\166\314
+\176\062\232\210\225\010\066\122\273\336\166\137\166\111\111\255
+\177\275\145\040\262\311\301\053\166\030\166\237\126\261
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "UCA Extended Validation Root"
+# Issuer: CN=UCA Extended Validation Root,O=UniTrust,C=CN
+# Serial Number:4f:d2:2b:8f:f5:64:c8:33:9e:4f:34:58:66:23:70:60
+# Subject: CN=UCA Extended Validation Root,O=UniTrust,C=CN
+# Not Valid Before: Fri Mar 13 00:00:00 2015
+# Not Valid After : Fri Dec 31 00:00:00 2038
+# Fingerprint (SHA-256): D4:3A:F9:B3:54:73:75:5C:96:84:FC:06:D7:D8:CB:70:EE:5C:28:E7:73:FB:29:4E:B4:1E:E7:17:22:92:4D:24
+# Fingerprint (SHA1): A3:A1:B0:6F:24:61:23:4A:E3:36:A5:C2:37:FC:A6:FF:DD:F0:D7:3A
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "UCA Extended Validation Root"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\243\241\260\157\044\141\043\112\343\066\245\302\067\374\246\377
+\335\360\327\072
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\241\363\137\103\306\064\233\332\277\214\176\005\123\255\226\342
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\107\061\013\060\011\006\003\125\004\006\023\002\103\116\061
+\021\060\017\006\003\125\004\012\014\010\125\156\151\124\162\165
+\163\164\061\045\060\043\006\003\125\004\003\014\034\125\103\101
+\040\105\170\164\145\156\144\145\144\040\126\141\154\151\144\141
+\164\151\157\156\040\122\157\157\164
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\020\117\322\053\217\365\144\310\063\236\117\064\130\146\043
+\160\140
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "Certigna Root CA"
+#
+# Issuer: CN=Certigna Root CA,OU=0002 48146308100036,O=Dhimyotis,C=FR
+# Serial Number:00:ca:e9:1b:89:f1:55:03:0d:a3:e6:41:6d:c4:e3:a6:e1
+# Subject: CN=Certigna Root CA,OU=0002 48146308100036,O=Dhimyotis,C=FR
+# Not Valid Before: Tue Oct 01 08:32:27 2013
+# Not Valid After : Sat Oct 01 08:32:27 2033
+# Fingerprint (SHA-256): D4:8D:3D:23:EE:DB:50:A4:59:E5:51:97:60:1C:27:77:4B:9D:7B:18:C9:4D:5A:05:95:11:A1:02:50:B9:31:68
+# Fingerprint (SHA1): 2D:0D:52:14:FF:9E:AD:99:24:01:74:20:47:6E:6C:85:27:27:F5:43
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Certigna Root CA"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\132\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\104\150\151\155\171\157
+\164\151\163\061\034\060\032\006\003\125\004\013\014\023\060\060
+\060\062\040\064\070\061\064\066\063\060\070\061\060\060\060\063
+\066\061\031\060\027\006\003\125\004\003\014\020\103\145\162\164
+\151\147\156\141\040\122\157\157\164\040\103\101
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\132\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\104\150\151\155\171\157
+\164\151\163\061\034\060\032\006\003\125\004\013\014\023\060\060
+\060\062\040\064\070\061\064\066\063\060\070\061\060\060\060\063
+\066\061\031\060\027\006\003\125\004\003\014\020\103\145\162\164
+\151\147\156\141\040\122\157\157\164\040\103\101
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\021\000\312\351\033\211\361\125\003\015\243\346\101\155\304
+\343\246\341
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\006\133\060\202\004\103\240\003\002\001\002\002\021\000
+\312\351\033\211\361\125\003\015\243\346\101\155\304\343\246\341
+\060\015\006\011\052\206\110\206\367\015\001\001\013\005\000\060
+\132\061\013\060\011\006\003\125\004\006\023\002\106\122\061\022
+\060\020\006\003\125\004\012\014\011\104\150\151\155\171\157\164
+\151\163\061\034\060\032\006\003\125\004\013\014\023\060\060\060
+\062\040\064\070\061\064\066\063\060\070\061\060\060\060\063\066
+\061\031\060\027\006\003\125\004\003\014\020\103\145\162\164\151
+\147\156\141\040\122\157\157\164\040\103\101\060\036\027\015\061
+\063\061\060\060\061\060\070\063\062\062\067\132\027\015\063\063
+\061\060\060\061\060\070\063\062\062\067\132\060\132\061\013\060
+\011\006\003\125\004\006\023\002\106\122\061\022\060\020\006\003
+\125\004\012\014\011\104\150\151\155\171\157\164\151\163\061\034
+\060\032\006\003\125\004\013\014\023\060\060\060\062\040\064\070
+\061\064\066\063\060\070\061\060\060\060\063\066\061\031\060\027
+\006\003\125\004\003\014\020\103\145\162\164\151\147\156\141\040
+\122\157\157\164\040\103\101\060\202\002\042\060\015\006\011\052
+\206\110\206\367\015\001\001\001\005\000\003\202\002\017\000\060
+\202\002\012\002\202\002\001\000\315\030\071\145\032\131\261\352
+\144\026\016\214\224\044\225\174\203\323\305\071\046\334\014\357
+\026\127\215\327\330\254\243\102\177\202\312\355\315\133\333\016
+\267\055\355\105\010\027\262\331\263\313\326\027\122\162\050\333
+\216\116\236\212\266\013\371\236\204\232\115\166\336\042\051\134
+\322\263\322\006\076\060\071\251\164\243\222\126\034\241\157\114
+\012\040\155\237\043\172\264\306\332\054\344\035\054\334\263\050
+\320\023\362\114\116\002\111\241\124\100\236\346\345\005\240\055
+\204\310\377\230\154\320\353\212\032\204\010\036\267\150\043\356
+\043\325\160\316\155\121\151\020\356\241\172\302\321\042\061\302
+\202\205\322\362\125\166\120\174\045\172\311\204\134\013\254\335
+\102\116\053\347\202\242\044\211\313\220\262\320\356\043\272\146
+\114\273\142\244\371\123\132\144\173\174\230\372\243\110\236\017
+\225\256\247\030\364\152\354\056\003\105\257\360\164\370\052\315
+\172\135\321\276\104\046\062\051\361\361\365\154\314\176\002\041
+\013\237\157\244\077\276\235\123\342\317\175\251\054\174\130\032
+\227\341\075\067\067\030\146\050\322\100\305\121\212\214\303\055
+\316\123\210\044\130\144\060\026\305\252\340\326\012\246\100\337
+\170\366\365\004\174\151\023\204\274\321\321\247\006\317\001\367
+\150\300\250\127\273\072\141\255\004\214\223\343\255\374\360\333
+\104\155\131\334\111\131\256\254\232\231\066\060\101\173\166\063
+\042\207\243\302\222\206\156\371\160\356\256\207\207\225\033\304
+\172\275\061\363\324\322\345\231\377\276\110\354\165\365\170\026
+\035\246\160\301\177\074\033\241\222\373\317\310\074\326\305\223
+\012\217\365\125\072\166\225\316\131\230\212\011\225\167\062\232
+\203\272\054\004\072\227\275\324\057\276\327\154\233\242\312\175
+\155\046\311\125\325\317\303\171\122\010\011\231\007\044\055\144
+\045\153\246\041\151\233\152\335\164\115\153\227\172\101\275\253
+\027\371\220\027\110\217\066\371\055\325\305\333\356\252\205\105
+\101\372\315\072\105\261\150\346\066\114\233\220\127\354\043\271
+\207\010\302\304\011\361\227\206\052\050\115\342\164\300\332\304
+\214\333\337\342\241\027\131\316\044\131\164\061\332\177\375\060
+\155\331\334\341\152\341\374\137\002\003\001\000\001\243\202\001
+\032\060\202\001\026\060\017\006\003\125\035\023\001\001\377\004
+\005\060\003\001\001\377\060\016\006\003\125\035\017\001\001\377
+\004\004\003\002\001\006\060\035\006\003\125\035\016\004\026\004
+\024\030\207\126\340\156\167\356\044\065\074\116\163\232\037\326
+\341\342\171\176\053\060\037\006\003\125\035\043\004\030\060\026
+\200\024\030\207\126\340\156\167\356\044\065\074\116\163\232\037
+\326\341\342\171\176\053\060\104\006\003\125\035\040\004\075\060
+\073\060\071\006\004\125\035\040\000\060\061\060\057\006\010\053
+\006\001\005\005\007\002\001\026\043\150\164\164\160\163\072\057
+\057\167\167\167\167\056\143\145\162\164\151\147\156\141\056\146
+\162\057\141\165\164\157\162\151\164\145\163\057\060\155\006\003
+\125\035\037\004\146\060\144\060\057\240\055\240\053\206\051\150
+\164\164\160\072\057\057\143\162\154\056\143\145\162\164\151\147
+\156\141\056\146\162\057\143\145\162\164\151\147\156\141\162\157
+\157\164\143\141\056\143\162\154\060\061\240\057\240\055\206\053
+\150\164\164\160\072\057\057\143\162\154\056\144\150\151\155\171
+\157\164\151\163\056\143\157\155\057\143\145\162\164\151\147\156
+\141\162\157\157\164\143\141\056\143\162\154\060\015\006\011\052
+\206\110\206\367\015\001\001\013\005\000\003\202\002\001\000\224
+\270\236\117\360\343\225\010\042\347\315\150\101\367\034\125\325
+\174\000\342\055\072\211\135\150\070\057\121\042\013\112\215\313
+\351\273\135\076\273\134\075\261\050\376\344\123\125\023\317\241
+\220\033\002\035\137\146\106\011\063\050\341\015\044\227\160\323
+\020\037\352\144\127\226\273\135\332\347\304\214\117\114\144\106
+\035\134\207\343\131\336\102\321\233\250\176\246\211\335\217\034
+\311\060\202\355\073\234\315\300\351\031\340\152\330\002\165\067
+\253\367\064\050\050\221\362\004\012\117\065\343\140\046\001\372
+\320\021\214\371\021\152\356\257\075\303\120\323\217\137\063\171
+\074\206\250\163\105\220\214\040\266\162\163\027\043\276\007\145
+\345\170\222\015\272\001\300\353\214\034\146\277\254\206\167\001
+\224\015\234\346\351\071\215\037\246\121\214\231\014\071\167\341
+\264\233\372\034\147\127\157\152\152\216\251\053\114\127\171\172
+\127\042\317\315\137\143\106\215\134\131\072\206\370\062\107\142
+\243\147\015\030\221\334\373\246\153\365\110\141\163\043\131\216
+\002\247\274\104\352\364\111\235\361\124\130\371\140\257\332\030
+\244\057\050\105\334\172\240\210\206\135\363\073\347\377\051\065
+\200\374\144\103\224\346\343\034\157\276\255\016\052\143\231\053
+\311\176\205\366\161\350\006\003\225\376\336\217\110\034\132\324
+\222\350\053\356\347\061\333\272\004\152\207\230\347\305\137\357
+\175\247\042\367\001\330\115\371\211\320\016\232\005\131\244\236
+\230\331\157\053\312\160\276\144\302\125\243\364\351\257\303\222
+\051\334\210\026\044\231\074\215\046\230\266\133\267\314\316\267
+\067\007\375\046\331\230\205\044\377\131\043\003\232\355\235\235
+\250\344\136\070\316\327\122\015\157\322\077\155\261\005\153\111
+\316\212\221\106\163\364\366\057\360\250\163\167\016\145\254\241
+\215\146\122\151\176\113\150\014\307\036\067\047\203\245\214\307
+\002\344\024\315\111\001\260\163\263\375\306\220\072\157\322\154
+\355\073\356\354\221\276\242\103\135\213\000\112\146\045\104\160
+\336\100\017\370\174\025\367\242\316\074\327\136\023\214\201\027
+\030\027\321\275\361\167\020\072\324\145\071\301\047\254\127\054
+\045\124\377\242\332\117\212\141\071\136\256\075\112\214\275
+END
+CKA_NSS_MOZILLA_CA_POLICY CK_BBOOL CK_TRUE
+
+# Trust for "Certigna Root CA"
+# Issuer: CN=Certigna Root CA,OU=0002 48146308100036,O=Dhimyotis,C=FR
+# Serial Number:00:ca:e9:1b:89:f1:55:03:0d:a3:e6:41:6d:c4:e3:a6:e1
+# Subject: CN=Certigna Root CA,OU=0002 48146308100036,O=Dhimyotis,C=FR
+# Not Valid Before: Tue Oct 01 08:32:27 2013
+# Not Valid After : Sat Oct 01 08:32:27 2033
+# Fingerprint (SHA-256): D4:8D:3D:23:EE:DB:50:A4:59:E5:51:97:60:1C:27:77:4B:9D:7B:18:C9:4D:5A:05:95:11:A1:02:50:B9:31:68
+# Fingerprint (SHA1): 2D:0D:52:14:FF:9E:AD:99:24:01:74:20:47:6E:6C:85:27:27:F5:43
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Certigna Root CA"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\055\015\122\024\377\236\255\231\044\001\164\040\107\156\154\205
+\047\047\365\103
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\016\134\060\142\047\353\133\274\327\256\142\272\351\325\337\167
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\132\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\104\150\151\155\171\157
+\164\151\163\061\034\060\032\006\003\125\004\013\014\023\060\060
+\060\062\040\064\070\061\064\066\063\060\070\061\060\060\060\063
+\066\061\031\060\027\006\003\125\004\003\014\020\103\145\162\164
+\151\147\156\141\040\122\157\157\164\040\103\101
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\021\000\312\351\033\211\361\125\003\015\243\346\101\155\304
+\343\246\341
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
diff --git a/security/nss/lib/ckfw/builtins/nssckbi.h b/security/nss/lib/ckfw/builtins/nssckbi.h
index d40c8080e..157d9c40d 100644
--- a/security/nss/lib/ckfw/builtins/nssckbi.h
+++ b/security/nss/lib/ckfw/builtins/nssckbi.h
@@ -46,8 +46,8 @@
* It's recommend to switch back to 0 after having reached version 98/99.
*/
#define NSS_BUILTINS_LIBRARY_VERSION_MAJOR 2
-#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 24
-#define NSS_BUILTINS_LIBRARY_VERSION "2.24"
+#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 30
+#define NSS_BUILTINS_LIBRARY_VERSION "2.30"
/* These version numbers detail the semantic changes to the ckfw engine. */
#define NSS_BUILTINS_HARDWARE_VERSION_MAJOR 1
diff --git a/security/nss/lib/ckfw/ckfw.h b/security/nss/lib/ckfw/ckfw.h
index d4a2ead99..9e7e17e36 100644
--- a/security/nss/lib/ckfw/ckfw.h
+++ b/security/nss/lib/ckfw/ckfw.h
@@ -1604,8 +1604,8 @@ nssCKFWSession_InitPIN(
NSS_EXTERN CK_RV
nssCKFWSession_SetPIN(
NSSCKFWSession *fwSession,
- NSSItem *newPin,
- NSSItem *oldPin);
+ const NSSItem *oldPin,
+ NSSItem *newPin);
/*
* nssCKFWSession_GetOperationStateLen
diff --git a/security/nss/lib/ckfw/session.c b/security/nss/lib/ckfw/session.c
index 7efedf403..e2613089b 100644
--- a/security/nss/lib/ckfw/session.c
+++ b/security/nss/lib/ckfw/session.c
@@ -871,7 +871,7 @@ nssCKFWSession_InitPIN(
NSS_IMPLEMENT CK_RV
nssCKFWSession_SetPIN(
NSSCKFWSession *fwSession,
- NSSItem *oldPin,
+ const NSSItem *oldPin,
NSSItem *newPin)
{
CK_RV error = CKR_OK;
@@ -907,7 +907,7 @@ nssCKFWSession_SetPIN(
error = fwSession->mdSession->SetPIN(fwSession->mdSession, fwSession,
fwSession->mdToken, fwSession->fwToken, fwSession->mdInstance,
- fwSession->fwInstance, oldPin, newPin);
+ fwSession->fwInstance, (NSSItem *)oldPin, newPin);
return error;
}
diff --git a/security/nss/lib/cryptohi/cryptohi.h b/security/nss/lib/cryptohi/cryptohi.h
index e529fa34f..7b66f0b0b 100644
--- a/security/nss/lib/cryptohi/cryptohi.h
+++ b/security/nss/lib/cryptohi/cryptohi.h
@@ -14,7 +14,7 @@
#include "secoidt.h"
#include "secdert.h"
#include "cryptoht.h"
-#include "keyt.h"
+#include "keythi.h"
#include "certt.h"
SEC_BEGIN_PROTOS
diff --git a/security/nss/lib/cryptohi/key.h b/security/nss/lib/cryptohi/key.h
index 3e89b74cb..8392031c5 100644
--- a/security/nss/lib/cryptohi/key.h
+++ b/security/nss/lib/cryptohi/key.h
@@ -2,11 +2,13 @@
* 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 header is deprecated. Please include keyhi.h instead. */
-
#ifndef _KEY_H_
#define _KEY_H_
+#if defined(_MSC_VER) || defined(__GNUC__) || defined(__clang__)
+#pragma message("key.h is deprecated. Please include keyhi.h instead.")
+#endif
+
#include "keyhi.h"
#endif /* _KEY_H_ */
diff --git a/security/nss/lib/cryptohi/keyi.h b/security/nss/lib/cryptohi/keyi.h
index ee11fc905..b746d3c8d 100644
--- a/security/nss/lib/cryptohi/keyi.h
+++ b/security/nss/lib/cryptohi/keyi.h
@@ -17,8 +17,21 @@ KeyType seckey_GetKeyType(SECOidTag pubKeyOid);
SECStatus sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg,
const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg);
-SECStatus sec_RSAPSSParamsToMechanism(CK_RSA_PKCS_PSS_PARAMS *mech,
- const SECKEYRSAPSSParams *params);
+/* extract the RSA-PSS hash algorithms and salt length from
+ * parameters, taking into account of the default implications.
+ *
+ * (parameters is the parameters field of a algorithm ID structure
+ * (SECAlgorithmID)*/
+SECStatus sec_DecodeRSAPSSParams(PLArenaPool *arena,
+ const SECItem *params,
+ SECOidTag *hashAlg,
+ SECOidTag *maskHashAlg,
+ unsigned long *saltLength);
+
+/* convert the encoded RSA-PSS parameters into PKCS #11 mechanism parameters */
+SECStatus sec_DecodeRSAPSSParamsToMechanism(PLArenaPool *arena,
+ const SECItem *params,
+ CK_RSA_PKCS_PSS_PARAMS *mech);
SEC_END_PROTOS
diff --git a/security/nss/lib/cryptohi/keyt.h b/security/nss/lib/cryptohi/keyt.h
index 99da312f6..5a0d2c2e7 100644
--- a/security/nss/lib/cryptohi/keyt.h
+++ b/security/nss/lib/cryptohi/keyt.h
@@ -5,6 +5,10 @@
#ifndef _KEYT_H_
#define _KEYT_H_
+#if defined(_MSC_VER) || defined(__GNUC__) || defined(__clang__)
+#pragma message("keyt.h is deprecated. Please include keythi.h instead.")
+#endif
+
#include "keythi.h"
#endif /* _KEYT_H_ */
diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c
index 0f9353f3b..080909772 100644
--- a/security/nss/lib/cryptohi/seckey.c
+++ b/security/nss/lib/cryptohi/seckey.c
@@ -2015,66 +2015,63 @@ sec_GetMgfTypeByOidTag(SECOidTag tag)
}
SECStatus
-sec_RSAPSSParamsToMechanism(CK_RSA_PKCS_PSS_PARAMS *mech,
- const SECKEYRSAPSSParams *params)
+sec_DecodeRSAPSSParams(PLArenaPool *arena,
+ const SECItem *params,
+ SECOidTag *retHashAlg, SECOidTag *retMaskHashAlg,
+ unsigned long *retSaltLength)
{
- SECStatus rv = SECSuccess;
- SECOidTag hashAlgTag;
+ SECKEYRSAPSSParams pssParams;
+ SECOidTag hashAlg;
+ SECOidTag maskHashAlg;
unsigned long saltLength;
unsigned long trailerField;
+ SECStatus rv;
- PORT_Memset(mech, 0, sizeof(CK_RSA_PKCS_PSS_PARAMS));
+ PORT_Memset(&pssParams, 0, sizeof(pssParams));
+ rv = SEC_QuickDERDecodeItem(arena, &pssParams,
+ SECKEY_RSAPSSParamsTemplate,
+ params);
+ if (rv != SECSuccess) {
+ return rv;
+ }
- if (params->hashAlg) {
- hashAlgTag = SECOID_GetAlgorithmTag(params->hashAlg);
+ if (pssParams.hashAlg) {
+ hashAlg = SECOID_GetAlgorithmTag(pssParams.hashAlg);
} else {
- hashAlgTag = SEC_OID_SHA1; /* default, SHA-1 */
- }
- mech->hashAlg = sec_GetHashMechanismByOidTag(hashAlgTag);
- if (mech->hashAlg == CKM_INVALID_MECHANISM) {
- return SECFailure;
+ hashAlg = SEC_OID_SHA1; /* default, SHA-1 */
}
- if (params->maskAlg) {
- SECAlgorithmID maskHashAlg;
- SECOidTag maskHashAlgTag;
- PORTCheapArenaPool tmpArena;
+ if (pssParams.maskAlg) {
+ SECAlgorithmID algId;
- if (SECOID_GetAlgorithmTag(params->maskAlg) != SEC_OID_PKCS1_MGF1) {
+ if (SECOID_GetAlgorithmTag(pssParams.maskAlg) != SEC_OID_PKCS1_MGF1) {
/* only MGF1 is known to PKCS#11 */
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
- PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
- rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &maskHashAlg,
+ rv = SEC_QuickDERDecodeItem(arena, &algId,
SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
- &params->maskAlg->parameters);
- PORT_DestroyCheapArena(&tmpArena);
+ &pssParams.maskAlg->parameters);
if (rv != SECSuccess) {
return rv;
}
- maskHashAlgTag = SECOID_GetAlgorithmTag(&maskHashAlg);
- mech->mgf = sec_GetMgfTypeByOidTag(maskHashAlgTag);
- if (mech->mgf == 0) {
- return SECFailure;
- }
+ maskHashAlg = SECOID_GetAlgorithmTag(&algId);
} else {
- mech->mgf = CKG_MGF1_SHA1; /* default, MGF1 with SHA-1 */
+ maskHashAlg = SEC_OID_SHA1; /* default, MGF1 with SHA-1 */
}
- if (params->saltLength.data) {
- rv = SEC_ASN1DecodeInteger((SECItem *)&params->saltLength, &saltLength);
+ if (pssParams.saltLength.data) {
+ rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.saltLength, &saltLength);
if (rv != SECSuccess) {
return rv;
}
} else {
saltLength = 20; /* default, 20 */
}
- mech->sLen = saltLength;
- if (params->trailerField.data) {
- rv = SEC_ASN1DecodeInteger((SECItem *)&params->trailerField, &trailerField);
+ if (pssParams.trailerField.data) {
+ rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField, &trailerField);
if (rv != SECSuccess) {
return rv;
}
@@ -2086,5 +2083,46 @@ sec_RSAPSSParamsToMechanism(CK_RSA_PKCS_PSS_PARAMS *mech,
}
}
- return rv;
+ if (retHashAlg) {
+ *retHashAlg = hashAlg;
+ }
+ if (retMaskHashAlg) {
+ *retMaskHashAlg = maskHashAlg;
+ }
+ if (retSaltLength) {
+ *retSaltLength = saltLength;
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+sec_DecodeRSAPSSParamsToMechanism(PLArenaPool *arena,
+ const SECItem *params,
+ CK_RSA_PKCS_PSS_PARAMS *mech)
+{
+ SECOidTag hashAlg;
+ SECOidTag maskHashAlg;
+ unsigned long saltLength;
+ SECStatus rv;
+
+ rv = sec_DecodeRSAPSSParams(arena, params,
+ &hashAlg, &maskHashAlg, &saltLength);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ mech->hashAlg = sec_GetHashMechanismByOidTag(hashAlg);
+ if (mech->hashAlg == CKM_INVALID_MECHANISM) {
+ return SECFailure;
+ }
+
+ mech->mgf = sec_GetMgfTypeByOidTag(maskHashAlg);
+ if (mech->mgf == 0) {
+ return SECFailure;
+ }
+
+ mech->sLen = saltLength;
+
+ return SECSuccess;
}
diff --git a/security/nss/lib/cryptohi/secsign.c b/security/nss/lib/cryptohi/secsign.c
index dc10f2fa6..8a8d0f664 100644
--- a/security/nss/lib/cryptohi/secsign.c
+++ b/security/nss/lib/cryptohi/secsign.c
@@ -225,22 +225,13 @@ SGN_End(SGNContext *cx, SECItem *result)
PORT_Memset(&mech, 0, sizeof(mech));
if (cx->params && cx->params->data) {
- SECKEYRSAPSSParams params;
-
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
rv = SECFailure;
goto loser;
}
- PORT_Memset(&params, 0, sizeof(params));
- rv = SEC_QuickDERDecodeItem(arena, &params,
- SECKEY_RSAPSSParamsTemplate,
- cx->params);
- if (rv != SECSuccess) {
- goto loser;
- }
- rv = sec_RSAPSSParamsToMechanism(&mech, &params);
+ rv = sec_DecodeRSAPSSParamsToMechanism(arena, cx->params, &mech);
if (rv != SECSuccess) {
goto loser;
}
diff --git a/security/nss/lib/cryptohi/secvfy.c b/security/nss/lib/cryptohi/secvfy.c
index 83c9c579d..aa3d6778c 100644
--- a/security/nss/lib/cryptohi/secvfy.c
+++ b/security/nss/lib/cryptohi/secvfy.c
@@ -161,7 +161,7 @@ verifyPKCS1DigestInfo(const VFYContext *cx, const SECItem *digest)
pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen;
return _SGN_VerifyPKCS1DigestInfo(
cx->hashAlg, digest, &pkcs1DigestInfo,
- PR_TRUE /*XXX: unsafeAllowMissingParameters*/);
+ PR_FALSE /*XXX: unsafeAllowMissingParameters*/);
}
/*
@@ -257,25 +257,13 @@ sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg,
break;
case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
if (param && param->data) {
- SECKEYRSAPSSParams pssParam;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL) {
- return SECFailure;
- }
- PORT_Memset(&pssParam, 0, sizeof pssParam);
- rv = SEC_QuickDERDecodeItem(arena, &pssParam,
- SECKEY_RSAPSSParamsTemplate,
- param);
- if (rv != SECSuccess) {
- PORT_FreeArena(arena, PR_FALSE);
- return rv;
- }
- if (pssParam.hashAlg) {
- *hashalg = SECOID_GetAlgorithmTag(pssParam.hashAlg);
- } else {
- *hashalg = SEC_OID_SHA1; /* default, SHA-1 */
- }
- PORT_FreeArena(arena, PR_FALSE);
+ PORTCheapArenaPool tmpArena;
+
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
+ rv = sec_DecodeRSAPSSParams(&tmpArena.arena, param,
+ hashalg, NULL, NULL);
+ PORT_DestroyCheapArena(&tmpArena);
+
/* only accept hash algorithms */
if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
/* error set by HASH_GetHashTypeByOidTag */
@@ -658,27 +646,17 @@ VFY_EndWithSignature(VFYContext *cx, SECItem *sig)
if (cx->encAlg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
CK_RSA_PKCS_PSS_PARAMS mech;
SECItem mechItem = { siBuffer, (unsigned char *)&mech, sizeof(mech) };
- SECKEYRSAPSSParams params;
- PLArenaPool *arena;
+ PORTCheapArenaPool tmpArena;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL) {
- return SECFailure;
- }
-
- PORT_Memset(&params, 0, sizeof(params));
- rv = SEC_QuickDERDecodeItem(arena, &params,
- SECKEY_RSAPSSParamsTemplate,
- cx->params);
- if (rv != SECSuccess) {
- PORT_FreeArena(arena, PR_FALSE);
- return SECFailure;
- }
- rv = sec_RSAPSSParamsToMechanism(&mech, &params);
- PORT_FreeArena(arena, PR_FALSE);
+ PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
+ rv = sec_DecodeRSAPSSParamsToMechanism(&tmpArena.arena,
+ cx->params,
+ &mech);
+ PORT_DestroyCheapArena(&tmpArena);
if (rv != SECSuccess) {
return SECFailure;
}
+
rsasig.data = cx->u.buffer;
rsasig.len = SECKEY_SignatureLen(cx->key);
if (rsasig.len == 0) {
diff --git a/security/nss/lib/freebl/ctr.c b/security/nss/lib/freebl/ctr.c
index b7167d4c4..d7652c060 100644
--- a/security/nss/lib/freebl/ctr.c
+++ b/security/nss/lib/freebl/ctr.c
@@ -219,15 +219,18 @@ CTR_Update_HW_AES(CTRContext *ctr, unsigned char *outbuf,
PORT_Assert(ctr->bufPtr == blocksize);
}
- intel_aes_ctr_worker(((AESContext *)(ctr->context))->Nr)(
- ctr, outbuf, outlen, maxout, inbuf, inlen, blocksize);
- /* XXX intel_aes_ctr_worker should set *outlen. */
- PORT_Assert(*outlen == 0);
- fullblocks = (inlen / blocksize) * blocksize;
- *outlen += fullblocks;
- outbuf += fullblocks;
- inbuf += fullblocks;
- inlen -= fullblocks;
+ if (inlen >= blocksize) {
+ rv = intel_aes_ctr_worker(((AESContext *)(ctr->context))->Nr)(
+ ctr, outbuf, outlen, maxout, inbuf, inlen, blocksize);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ fullblocks = (inlen / blocksize) * blocksize;
+ *outlen += fullblocks;
+ outbuf += fullblocks;
+ inbuf += fullblocks;
+ inlen -= fullblocks;
+ }
if (inlen == 0) {
return SECSuccess;
diff --git a/security/nss/lib/freebl/freebl.gyp b/security/nss/lib/freebl/freebl.gyp
index 004807483..288ff07a3 100644
--- a/security/nss/lib/freebl/freebl.gyp
+++ b/security/nss/lib/freebl/freebl.gyp
@@ -7,6 +7,30 @@
],
'targets': [
{
+ 'target_name': 'intel-gcm-s_lib',
+ 'type': 'static_library',
+ 'sources': [
+ 'intel-aes.s',
+ 'intel-gcm.s',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ],
+ 'conditions': [
+ [ 'cc_is_clang==1', {
+ 'cflags': [
+ '-no-integrated-as',
+ ],
+ 'cflags_mozilla': [
+ '-no-integrated-as',
+ ],
+ 'asflags_mozilla': [
+ '-no-integrated-as',
+ ],
+ }],
+ ],
+ },
+ {
'target_name': 'intel-gcm-wrap_c_lib',
'type': 'static_library',
'sources': [
@@ -15,12 +39,19 @@
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
],
+ 'conditions': [
+ [ '(OS=="linux" or OS=="android") and target_arch=="x64"', {
+ 'dependencies': [
+ 'intel-gcm-s_lib',
+ ],
+ }],
+ ],
'cflags': [
- '-mssse3'
+ '-mssse3',
],
'cflags_mozilla': [
'-mssse3'
- ]
+ ],
},
{
# TODO: make this so that all hardware accelerated code is in here.
diff --git a/security/nss/lib/freebl/freebl_base.gypi b/security/nss/lib/freebl/freebl_base.gypi
index 1372994f4..76df71497 100644
--- a/security/nss/lib/freebl/freebl_base.gypi
+++ b/security/nss/lib/freebl/freebl_base.gypi
@@ -67,14 +67,12 @@
[ 'target_arch=="x64"', {
'sources': [
'arcfour-amd64-gas.s',
- 'intel-aes.s',
- 'intel-gcm.s',
'mpi/mpi_amd64.c',
'mpi/mpi_amd64_gas.s',
'mpi/mp_comba.c',
],
'conditions': [
- [ 'cc_is_clang==1', {
+ [ 'cc_is_clang==1 and fuzz!=1', {
'cflags': [
'-no-integrated-as',
],
@@ -114,8 +112,7 @@
'intel-gcm-x64-masm.asm',
],
}],
- [ 'cc_use_gnu_ld!=1 and target_arch!="x64"', {
- # not x64
+ [ 'cc_use_gnu_ld!=1 and target_arch=="ia32"', {
'sources': [
'mpi/mpi_x86_asm.c',
'intel-aes-x86-masm.asm',
diff --git a/security/nss/lib/freebl/mpi/mpi.c b/security/nss/lib/freebl/mpi/mpi.c
index 8c893fb5f..401eac51d 100644
--- a/security/nss/lib/freebl/mpi/mpi.c
+++ b/security/nss/lib/freebl/mpi/mpi.c
@@ -4775,38 +4775,61 @@ mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
/* }}} */
/* {{{ mp_to_fixlen_octets(mp, str) */
-/* output a buffer of big endian octets exactly as long as requested. */
+/* output a buffer of big endian octets exactly as long as requested.
+ constant time on the value of mp. */
mp_err
mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size length)
{
- int ix, pos = 0;
+ int ix, jx;
unsigned int bytes;
- ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
-
- bytes = mp_unsigned_octet_size(mp);
- ARGCHK(bytes <= length, MP_BADARG);
+ ARGCHK(mp != NULL, MP_BADARG);
+ ARGCHK(str != NULL, MP_BADARG);
+ ARGCHK(!SIGN(mp), MP_BADARG);
+ ARGCHK(length > 0, MP_BADARG);
+
+ /* Constant time on the value of mp. Don't use mp_unsigned_octet_size. */
+ bytes = USED(mp) * MP_DIGIT_SIZE;
+
+ /* If the output is shorter than the native size of mp, then check that any
+ * bytes not written have zero values. This check isn't constant time on
+ * the assumption that timing-sensitive callers can guarantee that mp fits
+ * in the allocated space. */
+ ix = USED(mp) - 1;
+ if (bytes > length) {
+ unsigned int zeros = bytes - length;
+
+ while (zeros >= MP_DIGIT_SIZE) {
+ ARGCHK(DIGIT(mp, ix) == 0, MP_BADARG);
+ zeros -= MP_DIGIT_SIZE;
+ ix--;
+ }
- /* place any needed leading zeros */
- for (; length > bytes; --length) {
- *str++ = 0;
+ if (zeros > 0) {
+ mp_digit d = DIGIT(mp, ix);
+ mp_digit m = ~0ULL << ((MP_DIGIT_SIZE - zeros) * CHAR_BIT);
+ ARGCHK((d & m) == 0, MP_BADARG);
+ for (jx = MP_DIGIT_SIZE - zeros - 1; jx >= 0; jx--) {
+ *str++ = d >> (jx * CHAR_BIT);
+ }
+ ix--;
+ }
+ } else if (bytes < length) {
+ /* Place any needed leading zeros. */
+ unsigned int zeros = length - bytes;
+ memset(str, 0, zeros);
+ str += zeros;
}
- /* Iterate over each digit... */
- for (ix = USED(mp) - 1; ix >= 0; ix--) {
+ /* Iterate over each whole digit... */
+ for (; ix >= 0; ix--) {
mp_digit d = DIGIT(mp, ix);
- int jx;
/* Unpack digit bytes, high order first */
- for (jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
- unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
- if (!pos && !x) /* suppress leading zeros */
- continue;
- str[pos++] = x;
+ for (jx = MP_DIGIT_SIZE - 1; jx >= 0; jx--) {
+ *str++ = d >> (jx * CHAR_BIT);
}
}
- if (!pos)
- str[pos++] = 0;
return MP_OKAY;
} /* end mp_to_fixlen_octets() */
/* }}} */
diff --git a/security/nss/lib/freebl/mpi/mpi.h b/security/nss/lib/freebl/mpi/mpi.h
index 97af0f069..d5aef46d7 100644
--- a/security/nss/lib/freebl/mpi/mpi.h
+++ b/security/nss/lib/freebl/mpi/mpi.h
@@ -128,7 +128,8 @@ typedef int mp_sword;
#define MP_WORD_MAX UINT_MAX
#endif
-#define MP_DIGIT_BIT (CHAR_BIT * sizeof(mp_digit))
+#define MP_DIGIT_SIZE sizeof(mp_digit)
+#define MP_DIGIT_BIT (CHAR_BIT * MP_DIGIT_SIZE)
#define MP_WORD_BIT (CHAR_BIT * sizeof(mp_word))
#define MP_RADIX (1 + (mp_word)MP_DIGIT_MAX)
diff --git a/security/nss/lib/freebl/mpi/mpi_arm.c b/security/nss/lib/freebl/mpi/mpi_arm.c
index b5139f28d..27e4efdad 100644
--- a/security/nss/lib/freebl/mpi/mpi_arm.c
+++ b/security/nss/lib/freebl/mpi/mpi_arm.c
@@ -29,17 +29,17 @@ s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
"1:\n"
"mov r4, #0\n"
"ldr r6, [%0], #4\n"
- "umlal r5, r4, r6, %2\n"
- "str r5, [%3], #4\n"
+ "umlal r5, r4, r6, %3\n"
+ "str r5, [%2], #4\n"
"mov r5, r4\n"
"subs %1, #1\n"
"bne 1b\n"
"2:\n"
- "str r5, [%3]\n"
- :
- : "r"(a), "r"(a_len), "r"(b), "r"(c)
+ "str r5, [%2]\n"
+ : "+r"(a), "+l"(a_len), "+r"(c)
+ : "r"(b)
: "memory", "cc", "%r4", "%r5", "%r6");
}
@@ -57,22 +57,22 @@ s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
"1:\n"
"mov r4, #0\n"
- "ldr r6, [%3]\n"
+ "ldr r6, [%2]\n"
"adds r5, r6\n"
"adc r4, r4, #0\n"
"ldr r6, [%0], #4\n"
- "umlal r5, r4, r6, %2\n"
- "str r5, [%3], #4\n"
+ "umlal r5, r4, r6, %3\n"
+ "str r5, [%2], #4\n"
"mov r5, r4\n"
"subs %1, #1\n"
"bne 1b\n"
"2:\n"
- "str r5, [%3]\n"
- :
- : "r"(a), "r"(a_len), "r"(b), "r"(c)
+ "str r5, [%2]\n"
+ : "+r"(a), "+l"(a_len), "+r"(c)
+ : "r"(b)
: "memory", "cc", "%r4", "%r5", "%r6");
}
@@ -87,12 +87,12 @@ s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
"1:\n"
"mov r4, #0\n"
- "ldr r6, [%3]\n"
+ "ldr r6, [%2]\n"
"adds r5, r6\n"
"adc r4, r4, #0\n"
"ldr r6, [%0], #4\n"
- "umlal r5, r4, r6, %2\n"
- "str r5, [%3], #4\n"
+ "umlal r5, r4, r6, %3\n"
+ "str r5, [%2], #4\n"
"mov r5, r4\n"
"subs %1, #1\n"
@@ -107,16 +107,16 @@ s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
"2:\n"
"mov r4, #0\n"
- "ldr r6, [%3]\n"
+ "ldr r6, [%2]\n"
"adds r5, r6\n"
"adc r4, r4, #0\n"
- "str r5, [%3], #4\n"
+ "str r5, [%2], #4\n"
"movs r5, r4\n"
"bne 2b\n"
"3:\n"
- :
- : "r"(a), "r"(a_len), "r"(b), "r"(c)
+ : "+r"(a), "+l"(a_len), "+r"(c)
+ : "r"(b)
: "memory", "cc", "%r4", "%r5", "%r6");
}
#endif
@@ -167,8 +167,8 @@ s_mpv_sqr_add_prop(const mp_digit *pa, mp_size a_len, mp_digit *ps)
"bne 2b\n"
"3:"
+ : "+r"(pa), "+r"(a_len), "+r"(ps)
:
- : "r"(pa), "r"(a_len), "r"(ps)
: "memory", "cc", "%r3", "%r4", "%r5", "%r6");
}
#endif
diff --git a/security/nss/lib/freebl/rsapkcs.c b/security/nss/lib/freebl/rsapkcs.c
index ad18c8b73..875e4e28d 100644
--- a/security/nss/lib/freebl/rsapkcs.c
+++ b/security/nss/lib/freebl/rsapkcs.c
@@ -938,48 +938,56 @@ RSA_DecryptBlock(RSAPrivateKey *key,
const unsigned char *input,
unsigned int inputLen)
{
- SECStatus rv;
+ PRInt8 rv;
unsigned int modulusLen = rsa_modulusLen(&key->modulus);
unsigned int i;
- unsigned char *buffer;
+ unsigned char *buffer = NULL;
+ unsigned int outLen = 0;
+ unsigned int copyOutLen = modulusLen - 11;
- if (inputLen != modulusLen)
- goto failure;
+ if (inputLen != modulusLen || modulusLen < 10) {
+ return SECFailure;
+ }
- buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
- if (!buffer)
- goto failure;
+ if (copyOutLen > maxOutputLen) {
+ copyOutLen = maxOutputLen;
+ }
- rv = RSA_PrivateKeyOp(key, buffer, input);
- if (rv != SECSuccess)
- goto loser;
+ // Allocate enough space to decrypt + copyOutLen to allow copying outLen later.
+ buffer = PORT_ZAlloc(modulusLen + 1 + copyOutLen);
+ if (!buffer) {
+ return SECFailure;
+ }
- /* XXX(rsleevi): Constant time */
- if (buffer[0] != RSA_BLOCK_FIRST_OCTET ||
- buffer[1] != (unsigned char)RSA_BlockPublic) {
- goto loser;
+ // rv is 0 if everything is going well and 1 if an error occurs.
+ rv = RSA_PrivateKeyOp(key, buffer, input) != SECSuccess;
+ rv |= (buffer[0] != RSA_BLOCK_FIRST_OCTET) |
+ (buffer[1] != (unsigned char)RSA_BlockPublic);
+
+ // There have to be at least 8 bytes of padding.
+ for (i = 2; i < 10; i++) {
+ rv |= buffer[i] == RSA_BLOCK_AFTER_PAD_OCTET;
}
- *outputLen = 0;
- for (i = 2; i < modulusLen; i++) {
- if (buffer[i] == RSA_BLOCK_AFTER_PAD_OCTET) {
- *outputLen = modulusLen - i - 1;
- break;
- }
+
+ for (i = 10; i < modulusLen; i++) {
+ unsigned int newLen = modulusLen - i - 1;
+ unsigned int c = (buffer[i] == RSA_BLOCK_AFTER_PAD_OCTET) & (outLen == 0);
+ outLen = constantTimeCondition(c, newLen, outLen);
}
- if (*outputLen == 0)
- goto loser;
- if (*outputLen > maxOutputLen)
- goto loser;
+ rv |= outLen == 0;
+ rv |= outLen > maxOutputLen;
- PORT_Memcpy(output, buffer + modulusLen - *outputLen, *outputLen);
+ // Note that output is set even if SECFailure is returned.
+ PORT_Memcpy(output, buffer + modulusLen - outLen, copyOutLen);
+ *outputLen = constantTimeCondition(outLen > maxOutputLen, maxOutputLen,
+ outLen);
PORT_Free(buffer);
- return SECSuccess;
-loser:
- PORT_Free(buffer);
-failure:
- return SECFailure;
+ for (i = 1; i < sizeof(rv) * 8; i <<= 1) {
+ rv |= rv << i;
+ }
+ return (SECStatus)rv;
}
/*
diff --git a/security/nss/lib/jar/jarint.h b/security/nss/lib/jar/jarint.h
index 21aecef89..0f40f931f 100644
--- a/security/nss/lib/jar/jarint.h
+++ b/security/nss/lib/jar/jarint.h
@@ -5,7 +5,7 @@
/* JAR internal routines */
#include "nspr.h"
-#include "key.h"
+#include "keyhi.h"
#include "base64.h"
extern CERTCertDBHandle *JAR_open_database(void);
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
index fa8f1851e..145dcff9a 100644
--- a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
@@ -2914,7 +2914,8 @@ PKIX_PL_Cert_CheckValidity(
requiredUsages = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
allowOverride =
(PRBool)((requiredUsages & certificateUsageSSLServer) ||
- (requiredUsages & certificateUsageSSLServerWithStepUp));
+ (requiredUsages & certificateUsageSSLServerWithStepUp) ||
+ (requiredUsages & certificateUsageIPsec));
val = CERT_CheckCertValidTimes(cert->nssCert, timeToCheck, allowOverride);
if (val != secCertTimeValid){
PKIX_ERROR(PKIX_CERTCHECKCERTVALIDTIMESFAILED);
@@ -3001,8 +3002,17 @@ PKIX_PL_Cert_VerifyCertAndKeyType(
if (CERT_CheckKeyUsage(cert->nssCert, requiredKeyUsage) != SECSuccess) {
PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED);
}
- if (!(certType & requiredCertType)) {
- PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED);
+ if (certUsage != certUsageIPsec) {
+ if (!(certType & requiredCertType)) {
+ PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED);
+ }
+ } else {
+ PRBool isCritical;
+ PRBool allowed = cert_EKUAllowsIPsecIKE(cert->nssCert, &isCritical);
+ /* If the extension isn't critical, we allow any EKU value. */
+ if (isCritical && !allowed) {
+ PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED);
+ }
}
cleanup:
PKIX_DECREF(basicConstraints);
diff --git a/security/nss/lib/mozpkix/.clang-format b/security/nss/lib/mozpkix/.clang-format
new file mode 100644
index 000000000..06e3c5115
--- /dev/null
+++ b/security/nss/lib/mozpkix/.clang-format
@@ -0,0 +1,4 @@
+---
+Language: Cpp
+BasedOnStyle: Google
+...
diff --git a/security/nss/lib/mozpkix/exports.gyp b/security/nss/lib/mozpkix/exports.gyp
new file mode 100644
index 000000000..248efc910
--- /dev/null
+++ b/security/nss/lib/mozpkix/exports.gyp
@@ -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/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_mozpkix_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ '<(DEPTH)/cpputil/nss_scoped_ptrs.h',
+ 'include/pkix/Input.h',
+ 'include/pkix/Time.h',
+ 'include/pkix/Result.h',
+ 'include/pkix/pkix.h',
+ 'include/pkix/pkixnss.h',
+ 'include/pkix/pkixtypes.h',
+ 'include/pkix/pkixutil.h',
+ 'include/pkix/pkixcheck.h',
+ 'include/pkix/pkixder.h',
+ ],
+ 'destination': '<(nss_public_dist_dir)/<(module)/mozpkix'
+ },
+ ],
+ },
+ {
+ 'target_name': 'lib_mozpkix_test_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'include/pkix-test/pkixtestutil.h',
+ 'include/pkix-test/pkixtestnss.h',
+ ],
+ 'destination': '<(nss_public_dist_dir)/<(module)/mozpkix/test'
+ },
+ ],
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+} \ No newline at end of file
diff --git a/security/nss/lib/mozpkix/include/pkix-test/pkixtestnss.h b/security/nss/lib/mozpkix/include/pkix-test/pkixtestnss.h
new file mode 100644
index 000000000..5ae776f6a
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix-test/pkixtestnss.h
@@ -0,0 +1,48 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2018 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file provides some implementation-specific test utilities. This is only
+// necessary because some PSM xpcshell test utilities overlap in functionality
+// with these test utilities, so the underlying implementation is shared.
+
+#ifndef mozilla_pkix_test_pkixtestnss_h
+#define mozilla_pkix_test_pkixtestnss_h
+
+#include <keyhi.h>
+#include <keythi.h>
+#include "mozpkix/nss_scoped_ptrs.h"
+#include "mozpkix/test/pkixtestutil.h"
+
+namespace mozilla {
+namespace pkix {
+namespace test {
+
+TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
+ const ScopedSECKEYPublicKey& publicKey,
+ const ScopedSECKEYPrivateKey& privateKey);
+}
+}
+} // namespace mozilla::pkix::test
+
+#endif // mozilla_pkix_test_pkixtestnss_h
diff --git a/security/nss/lib/mozpkix/include/pkix-test/pkixtestutil.h b/security/nss/lib/mozpkix/include/pkix-test/pkixtestutil.h
new file mode 100644
index 000000000..55c435419
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix-test/pkixtestutil.h
@@ -0,0 +1,406 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_test_pkixtestutil_h
+#define mozilla_pkix_test_pkixtestutil_h
+
+#include <cstdint>
+#include <cstring>
+#include <ctime>
+#include <string>
+
+#include "mozpkix/pkixtypes.h"
+
+namespace mozilla {
+namespace pkix {
+namespace test {
+
+typedef std::basic_string<uint8_t> ByteString;
+
+inline bool ENCODING_FAILED(const ByteString& bs) { return bs.empty(); }
+
+template <size_t L>
+inline ByteString BytesToByteString(const uint8_t (&bytes)[L]) {
+ return ByteString(bytes, L);
+}
+
+// XXX: Ideally, we should define this instead:
+//
+// template <typename T, std::size_t N>
+// constexpr inline std::size_t
+// ArrayLength(T (&)[N])
+// {
+// return N;
+// }
+//
+// However, we don't because not all supported compilers support constexpr,
+// and we need to calculate array lengths in static_assert sometimes.
+//
+// XXX: Evaluates its argument twice
+#define MOZILLA_PKIX_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
+
+bool InputEqualsByteString(Input input, const ByteString& bs);
+ByteString InputToByteString(Input input);
+
+// python DottedOIDToCode.py --tlv id-kp-OCSPSigning 1.3.6.1.5.5.7.3.9
+static const uint8_t tlv_id_kp_OCSPSigning[] = {0x06, 0x08, 0x2b, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x03, 0x09};
+
+// python DottedOIDToCode.py --tlv id-kp-serverAuth 1.3.6.1.5.5.7.3.1
+static const uint8_t tlv_id_kp_serverAuth[] = {0x06, 0x08, 0x2b, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x03, 0x01};
+
+enum class TestDigestAlgorithmID {
+ MD2,
+ MD5,
+ SHA1,
+ SHA224,
+ SHA256,
+ SHA384,
+ SHA512,
+};
+
+struct TestPublicKeyAlgorithm {
+ explicit TestPublicKeyAlgorithm(const ByteString& aAlgorithmIdentifier)
+ : algorithmIdentifier(aAlgorithmIdentifier) {}
+ bool operator==(const TestPublicKeyAlgorithm& other) const {
+ return algorithmIdentifier == other.algorithmIdentifier;
+ }
+ ByteString algorithmIdentifier;
+};
+
+ByteString DSS_P();
+ByteString DSS_Q();
+ByteString DSS_G();
+
+TestPublicKeyAlgorithm DSS();
+TestPublicKeyAlgorithm RSA_PKCS1();
+
+struct TestSignatureAlgorithm {
+ TestSignatureAlgorithm(const TestPublicKeyAlgorithm& publicKeyAlg,
+ TestDigestAlgorithmID digestAlg,
+ const ByteString& algorithmIdentifier, bool accepted);
+
+ TestPublicKeyAlgorithm publicKeyAlg;
+ TestDigestAlgorithmID digestAlg;
+ ByteString algorithmIdentifier;
+ bool accepted;
+};
+
+TestSignatureAlgorithm md2WithRSAEncryption();
+TestSignatureAlgorithm md5WithRSAEncryption();
+TestSignatureAlgorithm sha1WithRSAEncryption();
+TestSignatureAlgorithm sha256WithRSAEncryption();
+
+// e.g. YMDHMS(2016, 12, 31, 1, 23, 45) => 2016-12-31:01:23:45 (GMT)
+mozilla::pkix::Time YMDHMS(uint16_t year, uint16_t month, uint16_t day,
+ uint16_t hour, uint16_t minutes, uint16_t seconds);
+
+ByteString TLV(uint8_t tag, size_t length, const ByteString& value);
+
+inline ByteString TLV(uint8_t tag, const ByteString& value) {
+ return TLV(tag, value.length(), value);
+}
+
+// Although we can't enforce it without relying on Cuser-defined literals,
+// which aren't supported by all of our compilers yet, you should only pass
+// string literals as the last parameter to the following two functions.
+
+template <size_t N>
+inline ByteString TLV(uint8_t tag, const char (&value)[N]) {
+ static_assert(N > 0, "cannot have string literal of size 0");
+ assert(value[N - 1] == 0);
+ return TLV(tag, ByteString(reinterpret_cast<const uint8_t*>(&value), N - 1));
+}
+
+template <size_t N>
+inline ByteString TLV(uint8_t tag, size_t length, const char (&value)[N]) {
+ static_assert(N > 0, "cannot have string literal of size 0");
+ assert(value[N - 1] == 0);
+ return TLV(tag, length,
+ ByteString(reinterpret_cast<const uint8_t*>(&value), N - 1));
+}
+
+ByteString Boolean(bool value);
+ByteString Integer(long value);
+
+ByteString CN(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/);
+
+inline ByteString CN(const char* value,
+ uint8_t encodingTag = 0x0c /*UTF8String*/) {
+ return CN(
+ ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)),
+ encodingTag);
+}
+
+ByteString OU(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/);
+
+inline ByteString OU(const char* value,
+ uint8_t encodingTag = 0x0c /*UTF8String*/) {
+ return OU(
+ ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)),
+ encodingTag);
+}
+
+ByteString emailAddress(const ByteString&);
+
+inline ByteString emailAddress(const char* value) {
+ return emailAddress(
+ ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)));
+}
+
+// RelativeDistinguishedName ::=
+// SET SIZE (1..MAX) OF AttributeTypeAndValue
+//
+ByteString RDN(const ByteString& avas);
+
+// Name ::= CHOICE { -- only one possibility for now --
+// rdnSequence RDNSequence }
+//
+// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+//
+ByteString Name(const ByteString& rdns);
+
+inline ByteString CNToDERName(const ByteString& cn) {
+ return Name(RDN(CN(cn)));
+}
+
+inline ByteString CNToDERName(const char* cn) { return Name(RDN(CN(cn))); }
+
+// GeneralName ::= CHOICE {
+// otherName [0] OtherName,
+// rfc822Name [1] IA5String,
+// dNSName [2] IA5String,
+// x400Address [3] ORAddress,
+// directoryName [4] Name,
+// ediPartyName [5] EDIPartyName,
+// uniformResourceIdentifier [6] IA5String,
+// iPAddress [7] OCTET STRING,
+// registeredID [8] OBJECT IDENTIFIER }
+
+inline ByteString RFC822Name(const ByteString& name) {
+ // (2 << 6) means "context-specific", 1 is the GeneralName tag.
+ return TLV((2 << 6) | 1, name);
+}
+
+template <size_t L>
+inline ByteString RFC822Name(const char (&bytes)[L]) {
+ return RFC822Name(
+ ByteString(reinterpret_cast<const uint8_t*>(&bytes), L - 1));
+}
+
+inline ByteString DNSName(const ByteString& name) {
+ // (2 << 6) means "context-specific", 2 is the GeneralName tag.
+ return TLV((2 << 6) | 2, name);
+}
+
+template <size_t L>
+inline ByteString DNSName(const char (&bytes)[L]) {
+ return DNSName(ByteString(reinterpret_cast<const uint8_t*>(&bytes), L - 1));
+}
+
+inline ByteString DirectoryName(const ByteString& name) {
+ // (2 << 6) means "context-specific", (1 << 5) means "constructed", and 4 is
+ // the DirectoryName tag.
+ return TLV((2 << 6) | (1 << 5) | 4, name);
+}
+
+inline ByteString IPAddress() {
+ // (2 << 6) means "context-specific", 7 is the GeneralName tag.
+ return TLV((2 << 6) | 7, ByteString());
+}
+
+template <size_t L>
+inline ByteString IPAddress(const uint8_t (&bytes)[L]) {
+ // (2 << 6) means "context-specific", 7 is the GeneralName tag.
+ return TLV((2 << 6) | 7, ByteString(bytes, L));
+}
+
+// Names should be zero or more GeneralNames, like DNSName and IPAddress return,
+// concatenated together.
+//
+// CreatedEncodedSubjectAltName(ByteString()) results in a SAN with an empty
+// sequence. CreateEmptyEncodedSubjectName() results in a SAN without any
+// sequence.
+ByteString CreateEncodedSubjectAltName(const ByteString& names);
+ByteString CreateEncodedEmptySubjectAltName();
+
+class TestKeyPair {
+ public:
+ virtual ~TestKeyPair() {}
+
+ const TestPublicKeyAlgorithm publicKeyAlg;
+
+ // The DER encoding of the entire SubjectPublicKeyInfo structure. This is
+ // what is encoded in certificates.
+ const ByteString subjectPublicKeyInfo;
+
+ // The DER encoding of subjectPublicKeyInfo.subjectPublicKey. This is what is
+ // hashed to create CertIDs for OCSP.
+ const ByteString subjectPublicKey;
+
+ virtual Result SignData(const ByteString& tbs,
+ const TestSignatureAlgorithm& signatureAlgorithm,
+ /*out*/ ByteString& signature) const = 0;
+
+ virtual TestKeyPair* Clone() const = 0;
+
+ protected:
+ TestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg,
+ const ByteString& spk);
+ TestKeyPair(const TestKeyPair&) = delete;
+ void operator=(const TestKeyPair&) = delete;
+};
+
+TestKeyPair* CloneReusedKeyPair();
+TestKeyPair* GenerateKeyPair();
+TestKeyPair* GenerateDSSKeyPair();
+inline void DeleteTestKeyPair(TestKeyPair* keyPair) { delete keyPair; }
+typedef std::unique_ptr<TestKeyPair> ScopedTestKeyPair;
+
+Result TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
+ Input subjectPublicKeyInfo);
+Result TestVerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
+ Input subjectPublicKeyInfo);
+Result TestDigestBuf(Input item, DigestAlgorithm digestAlg,
+ /*out*/ uint8_t* digestBuf, size_t digestBufLen);
+
+// Replace one substring in item with another of the same length, but only if
+// the substring was found exactly once. The "same length" restriction is
+// useful for avoiding invalidating lengths encoded within the item. The
+// "only once" restriction is helpful for avoiding making accidental changes.
+//
+// The string to search for must be 8 or more bytes long so that it is
+// extremely unlikely that there will ever be any false positive matches
+// in digital signatures, keys, hashes, etc.
+Result TamperOnce(/*in/out*/ ByteString& item, const ByteString& from,
+ const ByteString& to);
+
+///////////////////////////////////////////////////////////////////////////////
+// Encode Certificates
+
+enum Version { v1 = 0, v2 = 1, v3 = 2 };
+
+// signature is assumed to be the DER encoding of an AlgorithmIdentifer. It is
+// put into the signature field of the TBSCertificate. In most cases, it will
+// be the same as signatureAlgorithm, which is the algorithm actually used
+// to sign the certificate.
+// serialNumber is assumed to be the DER encoding of an INTEGER.
+//
+// If extensions is null, then no extensions will be encoded. Otherwise,
+// extensions must point to an array of ByteStrings, terminated with an empty
+// ByteString. (If the first item of the array is empty then an empty
+// Extensions sequence will be encoded.)
+ByteString CreateEncodedCertificate(
+ long version, const TestSignatureAlgorithm& signature,
+ const ByteString& serialNumber, const ByteString& issuerNameDER,
+ time_t notBefore, time_t notAfter, const ByteString& subjectNameDER,
+ const TestKeyPair& subjectKeyPair,
+ /*optional*/ const ByteString* extensions, const TestKeyPair& issuerKeyPair,
+ const TestSignatureAlgorithm& signatureAlgorithm);
+
+ByteString CreateEncodedSerialNumber(long value);
+
+enum class Critical { No = 0, Yes = 1 };
+
+ByteString CreateEncodedBasicConstraints(
+ bool isCA,
+ /*optional in*/ const long* pathLenConstraint, Critical critical);
+
+// Creates a DER-encoded extKeyUsage extension with one EKU OID.
+ByteString CreateEncodedEKUExtension(Input eku, Critical critical);
+
+///////////////////////////////////////////////////////////////////////////////
+// Encode OCSP responses
+
+class OCSPResponseExtension final {
+ public:
+ OCSPResponseExtension();
+
+ ByteString id;
+ bool critical;
+ ByteString value;
+ OCSPResponseExtension* next;
+};
+
+class OCSPResponseContext final {
+ public:
+ OCSPResponseContext(const CertID& certID, std::time_t time);
+
+ const CertID& certID;
+ // TODO(bug 980538): add a way to specify what certificates are included.
+
+ // The fields below are in the order that they appear in an OCSP response.
+
+ enum OCSPResponseStatus {
+ successful = 0,
+ malformedRequest = 1,
+ internalError = 2,
+ tryLater = 3,
+ // 4 is not used
+ sigRequired = 5,
+ unauthorized = 6,
+ };
+ uint8_t responseStatus; // an OCSPResponseStatus or an invalid value
+ bool skipResponseBytes; // If true, don't include responseBytes
+
+ // responderID
+ ByteString signerNameDER; // If set, responderID will use the byName
+ // form; otherwise responderID will use the
+ // byKeyHash form.
+
+ std::time_t producedAt;
+
+ // SingleResponse extensions (for the certID given in the constructor).
+ OCSPResponseExtension* singleExtensions;
+ // ResponseData extensions.
+ OCSPResponseExtension* responseExtensions;
+ bool includeEmptyExtensions; // If true, include the extension wrapper
+ // regardless of if there are any actual
+ // extensions.
+ ScopedTestKeyPair signerKeyPair;
+ TestSignatureAlgorithm signatureAlgorithm;
+ bool badSignature; // If true, alter the signature to fail verification
+ const ByteString* certs; // optional; array terminated by an empty string
+
+ // The following fields are on a per-SingleResponse basis. In the future we
+ // may support including multiple SingleResponses per response.
+ enum CertStatus {
+ good = 0,
+ revoked = 1,
+ unknown = 2,
+ };
+ uint8_t certStatus; // CertStatus or an invalid value
+ std::time_t revocationTime; // For certStatus == revoked
+ std::time_t thisUpdate;
+ std::time_t nextUpdate;
+ bool includeNextUpdate;
+};
+
+ByteString CreateEncodedOCSPResponse(OCSPResponseContext& context);
+}
+}
+} // namespace mozilla::pkix::test
+
+#endif // mozilla_pkix_test_pkixtestutil_h
diff --git a/security/nss/lib/mozpkix/include/pkix/Input.h b/security/nss/lib/mozpkix/include/pkix/Input.h
new file mode 100644
index 000000000..11b2a0f7e
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/Input.h
@@ -0,0 +1,310 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_Input_h
+#define mozilla_pkix_Input_h
+
+#include <algorithm>
+
+#include "mozpkix/Result.h"
+#include "stdint.h"
+
+namespace mozilla {
+namespace pkix {
+
+class Reader;
+
+// An Input is a safety-oriented immutable weak reference to a array of bytes
+// of a known size. The data can only be legally accessed by constructing a
+// Reader object, which guarantees all accesses to the data are memory safe.
+// Neither Input not Reader provide any facilities for modifying the data
+// they reference.
+//
+// Inputs are small and should usually be passed by value, not by reference,
+// though for inline functions the distinction doesn't matter:
+//
+// Result GoodExample(Input input);
+// Result BadExample(const Input& input);
+// Result WorseExample(const uint8_t* input, size_t len);
+//
+// Note that in the example, GoodExample has the same performance
+// characteristics as WorseExample, but with much better safety guarantees.
+class Input final {
+ public:
+ typedef uint16_t size_type;
+
+ // This constructor is useful for inputs that are statically known to be of a
+ // fixed size, e.g.:
+ //
+ // static const uint8_t EXPECTED_BYTES[] = { 0x00, 0x01, 0x02 };
+ // const Input expected(EXPECTED_BYTES);
+ //
+ // This is equivalent to (and preferred over):
+ //
+ // static const uint8_t EXPECTED_BYTES[] = { 0x00, 0x01, 0x02 };
+ // Input expected;
+ // Result rv = expected.Init(EXPECTED_BYTES, sizeof EXPECTED_BYTES);
+ template <size_type N>
+ explicit Input(const uint8_t (&aData)[N]) : data(aData), len(N) {}
+
+ // Construct a valid, empty, Init-able Input.
+ Input() : data(nullptr), len(0u) {}
+
+ // This is intentionally not explicit in order to allow value semantics.
+ Input(const Input&) = default;
+
+ // Initialize the input. data must be non-null and len must be less than
+ // 65536. Init may not be called more than once.
+ Result Init(const uint8_t* aData, size_t aLen) {
+ if (this->data) {
+ // already initialized
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+ if (!aData || aLen > 0xffffu) {
+ // input too large
+ return Result::ERROR_BAD_DER;
+ }
+
+ this->data = aData;
+ this->len = aLen;
+
+ return Success;
+ }
+
+ // Initialize the input to be equivalent to the given input. Init may not be
+ // called more than once.
+ //
+ // This is basically operator=, but it wasn't given that name because
+ // normally callers do not check the result of operator=, and normally
+ // operator= can be used multiple times.
+ Result Init(Input other) { return Init(other.data, other.len); }
+
+ // Returns the length of the input.
+ //
+ // Having the return type be size_type instead of size_t avoids the need for
+ // callers to ensure that the result is small enough.
+ size_type GetLength() const { return static_cast<size_type>(len); }
+
+ // Don't use this. It is here because we have some "friend" functions that we
+ // don't want to declare in this header file.
+ const uint8_t* UnsafeGetData() const { return data; }
+
+ private:
+ const uint8_t* data;
+ size_t len;
+
+ void operator=(const Input&) = delete; // Use Init instead.
+};
+
+inline bool InputsAreEqual(const Input& a, const Input& b) {
+ return a.GetLength() == b.GetLength() &&
+ std::equal(a.UnsafeGetData(), a.UnsafeGetData() + a.GetLength(),
+ b.UnsafeGetData());
+}
+
+// An Reader is a cursor/iterator through the contents of an Input, designed to
+// maximize safety during parsing while minimizing the performance cost of that
+// safety. In particular, all methods do strict bounds checking to ensure
+// buffer overflows are impossible, and they are all inline so that the
+// compiler can coalesce as many of those checks together as possible.
+//
+// In general, Reader allows for one byte of lookahead and no backtracking.
+// However, the Match* functions internally may have more lookahead.
+class Reader final {
+ public:
+ Reader() : input(nullptr), end(nullptr) {}
+
+ explicit Reader(Input aInput)
+ : input(aInput.UnsafeGetData()),
+ end(aInput.UnsafeGetData() + aInput.GetLength()) {}
+
+ Result Init(Input aInput) {
+ if (this->input) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+ this->input = aInput.UnsafeGetData();
+ this->end = aInput.UnsafeGetData() + aInput.GetLength();
+ return Success;
+ }
+
+ bool Peek(uint8_t expectedByte) const {
+ return input < end && *input == expectedByte;
+ }
+
+ Result Read(uint8_t& out) {
+ Result rv = EnsureLength(1);
+ if (rv != Success) {
+ return rv;
+ }
+ out = *input++;
+ return Success;
+ }
+
+ Result Read(uint16_t& out) {
+ Result rv = EnsureLength(2);
+ if (rv != Success) {
+ return rv;
+ }
+ out = *input++;
+ out <<= 8u;
+ out |= *input++;
+ return Success;
+ }
+
+ template <Input::size_type N>
+ bool MatchRest(const uint8_t (&toMatch)[N]) {
+ // Normally we use EnsureLength which compares (input + len < end), but
+ // here we want to be sure that there is nothing following the matched
+ // bytes
+ if (static_cast<size_t>(end - input) != N) {
+ return false;
+ }
+ if (!std::equal(input, end, toMatch)) {
+ return false;
+ }
+ input = end;
+ return true;
+ }
+
+ bool MatchRest(Input toMatch) {
+ // Normally we use EnsureLength which compares (input + len < end), but
+ // here we want to be sure that there is nothing following the matched
+ // bytes
+ size_t remaining = static_cast<size_t>(end - input);
+ if (toMatch.GetLength() != remaining) {
+ return false;
+ }
+ if (!std::equal(input, end, toMatch.UnsafeGetData())) {
+ return false;
+ }
+ input = end;
+ return true;
+ }
+
+ Result Skip(Input::size_type len) {
+ Result rv = EnsureLength(len);
+ if (rv != Success) {
+ return rv;
+ }
+ input += len;
+ return Success;
+ }
+
+ Result Skip(Input::size_type len, Reader& skipped) {
+ Result rv = EnsureLength(len);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = skipped.Init(input, len);
+ if (rv != Success) {
+ return rv;
+ }
+ input += len;
+ return Success;
+ }
+
+ Result Skip(Input::size_type len, /*out*/ Input& skipped) {
+ Result rv = EnsureLength(len);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = skipped.Init(input, len);
+ if (rv != Success) {
+ return rv;
+ }
+ input += len;
+ return Success;
+ }
+
+ void SkipToEnd() { input = end; }
+
+ Result SkipToEnd(/*out*/ Input& skipped) {
+ return Skip(static_cast<Input::size_type>(end - input), skipped);
+ }
+
+ Result EnsureLength(Input::size_type len) {
+ if (static_cast<size_t>(end - input) < len) {
+ return Result::ERROR_BAD_DER;
+ }
+ return Success;
+ }
+
+ bool AtEnd() const { return input == end; }
+
+ class Mark final {
+ public:
+ Mark(const Mark&) = default; // Intentionally not explicit.
+ private:
+ friend class Reader;
+ Mark(const Reader& aInput, const uint8_t* aMark)
+ : input(aInput), mark(aMark) {}
+ const Reader& input;
+ const uint8_t* const mark;
+ void operator=(const Mark&) = delete;
+ };
+
+ Mark GetMark() const { return Mark(*this, input); }
+
+ Result GetInput(const Mark& mark, /*out*/ Input& item) {
+ if (&mark.input != this || mark.mark > input) {
+ return NotReached("invalid mark", Result::FATAL_ERROR_INVALID_ARGS);
+ }
+ return item.Init(mark.mark,
+ static_cast<Input::size_type>(input - mark.mark));
+ }
+
+ private:
+ Result Init(const uint8_t* data, Input::size_type len) {
+ if (input) {
+ // already initialized
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+ input = data;
+ end = data + len;
+ return Success;
+ }
+
+ const uint8_t* input;
+ const uint8_t* end;
+
+ Reader(const Reader&) = delete;
+ void operator=(const Reader&) = delete;
+};
+
+inline bool InputContains(const Input& input, uint8_t toFind) {
+ Reader reader(input);
+ for (;;) {
+ uint8_t b;
+ if (reader.Read(b) != Success) {
+ return false;
+ }
+ if (b == toFind) {
+ return true;
+ }
+ }
+}
+}
+} // namespace mozilla::pkix
+
+#endif // mozilla_pkix_Input_h
diff --git a/security/nss/lib/mozpkix/include/pkix/Result.h b/security/nss/lib/mozpkix/include/pkix/Result.h
new file mode 100644
index 000000000..29461dc1a
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/Result.h
@@ -0,0 +1,219 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_Result_h
+#define mozilla_pkix_Result_h
+
+#include <cassert>
+
+namespace mozilla {
+namespace pkix {
+
+static const unsigned int FATAL_ERROR_FLAG = 0x800;
+
+// ----------------------------------------------------------------------------
+// SELECTED ERROR CODE EXPLANATIONS
+//
+// Result::ERROR_UNTRUSTED_CERT
+// means that the end-entity certificate was actively distrusted.
+// Result::ERROR_UNTRUSTED_ISSUER
+// means that path building failed because of active distrust.
+// Result::ERROR_INVALID_DER_TIME
+// means the DER-encoded time was unexpected, such as being before the
+// UNIX epoch (allowed by X500, but not valid here).
+// Result::ERROR_EXPIRED_CERTIFICATE
+// means the end entity certificate expired.
+// Result::ERROR_EXPIRED_ISSUER_CERTIFICATE
+// means the CA certificate expired.
+// Result::ERROR_UNKNOWN_ISSUER
+// means that the CA could not be found in the root store.
+// Result::ERROR_POLICY_VALIDATION_FAILED
+// means that an encoded policy could not be applied or wasn't present
+// when expected. Usually this is in the context of Extended Validation.
+// Result::ERROR_BAD_CERT_DOMAIN
+// means that the certificate's name couldn't be matched to the
+// reference identifier.
+// Result::ERROR_CERT_NOT_IN_NAME_SPACE
+// typically means the certificate violates name constraints applied
+// by the issuer.
+// Result::ERROR_BAD_DER
+// means the input was improperly encoded.
+// Result::ERROR_UNKNOWN_ERROR
+// means that an external library (NSS) provided an error we didn't
+// anticipate. See the map below in Result.h to add new ones.
+// Result::FATAL_ERROR_LIBRARY_FAILURE
+// is an unexpected fatal error indicating a library had an unexpected
+// failure, and we can't proceed.
+// Result::FATAL_ERROR_INVALID_ARGS
+// means that we violated our own expectations on inputs and there's a
+// bug somewhere.
+// Result::FATAL_ERROR_INVALID_STATE
+// means that we violated our own expectations on state and there's a
+// bug somewhere.
+// Result::FATAL_ERROR_NO_MEMORY
+// means a memory allocation failed, prohibiting validation.
+// ----------------------------------------------------------------------------
+
+// The first argument to MOZILLA_PKIX_MAP() is used for building the mapping
+// from error code to error name in MapResultToName.
+//
+// The second argument is for defining the value for the enum literal in the
+// Result enum class.
+//
+// The third argument to MOZILLA_PKIX_MAP() is used, along with the first
+// argument, for maintaining the mapping of mozilla::pkix error codes to
+// NSS/NSPR error codes in pkixnss.cpp.
+#define MOZILLA_PKIX_MAP_LIST \
+ MOZILLA_PKIX_MAP(Success, 0, 0) \
+ MOZILLA_PKIX_MAP(ERROR_BAD_DER, 1, SEC_ERROR_BAD_DER) \
+ MOZILLA_PKIX_MAP(ERROR_CA_CERT_INVALID, 2, SEC_ERROR_CA_CERT_INVALID) \
+ MOZILLA_PKIX_MAP(ERROR_BAD_SIGNATURE, 3, SEC_ERROR_BAD_SIGNATURE) \
+ MOZILLA_PKIX_MAP(ERROR_CERT_BAD_ACCESS_LOCATION, 4, \
+ SEC_ERROR_CERT_BAD_ACCESS_LOCATION) \
+ MOZILLA_PKIX_MAP(ERROR_CERT_NOT_IN_NAME_SPACE, 5, \
+ SEC_ERROR_CERT_NOT_IN_NAME_SPACE) \
+ MOZILLA_PKIX_MAP(ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 6, \
+ SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) \
+ MOZILLA_PKIX_MAP(ERROR_CONNECT_REFUSED, 7, PR_CONNECT_REFUSED_ERROR) \
+ MOZILLA_PKIX_MAP(ERROR_EXPIRED_CERTIFICATE, 8, \
+ SEC_ERROR_EXPIRED_CERTIFICATE) \
+ MOZILLA_PKIX_MAP(ERROR_EXTENSION_VALUE_INVALID, 9, \
+ SEC_ERROR_EXTENSION_VALUE_INVALID) \
+ MOZILLA_PKIX_MAP(ERROR_INADEQUATE_CERT_TYPE, 10, \
+ SEC_ERROR_INADEQUATE_CERT_TYPE) \
+ MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_USAGE, 11, \
+ SEC_ERROR_INADEQUATE_KEY_USAGE) \
+ MOZILLA_PKIX_MAP(ERROR_INVALID_ALGORITHM, 12, SEC_ERROR_INVALID_ALGORITHM) \
+ MOZILLA_PKIX_MAP(ERROR_INVALID_DER_TIME, 13, SEC_ERROR_INVALID_TIME) \
+ MOZILLA_PKIX_MAP(ERROR_KEY_PINNING_FAILURE, 14, \
+ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE) \
+ MOZILLA_PKIX_MAP(ERROR_PATH_LEN_CONSTRAINT_INVALID, 15, \
+ SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID) \
+ MOZILLA_PKIX_MAP(ERROR_POLICY_VALIDATION_FAILED, 16, \
+ SEC_ERROR_POLICY_VALIDATION_FAILED) \
+ MOZILLA_PKIX_MAP(ERROR_REVOKED_CERTIFICATE, 17, \
+ SEC_ERROR_REVOKED_CERTIFICATE) \
+ MOZILLA_PKIX_MAP(ERROR_UNKNOWN_CRITICAL_EXTENSION, 18, \
+ SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) \
+ MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ERROR, 19, PR_UNKNOWN_ERROR) \
+ MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ISSUER, 20, SEC_ERROR_UNKNOWN_ISSUER) \
+ MOZILLA_PKIX_MAP(ERROR_UNTRUSTED_CERT, 21, SEC_ERROR_UNTRUSTED_CERT) \
+ MOZILLA_PKIX_MAP(ERROR_UNTRUSTED_ISSUER, 22, SEC_ERROR_UNTRUSTED_ISSUER) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_BAD_SIGNATURE, 23, SEC_ERROR_OCSP_BAD_SIGNATURE) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_INVALID_SIGNING_CERT, 24, \
+ SEC_ERROR_OCSP_INVALID_SIGNING_CERT) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_REQUEST, 25, \
+ SEC_ERROR_OCSP_MALFORMED_REQUEST) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_RESPONSE, 26, \
+ SEC_ERROR_OCSP_MALFORMED_RESPONSE) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_OLD_RESPONSE, 27, SEC_ERROR_OCSP_OLD_RESPONSE) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_REQUEST_NEEDS_SIG, 28, \
+ SEC_ERROR_OCSP_REQUEST_NEEDS_SIG) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_RESPONDER_CERT_INVALID, 29, \
+ SEC_ERROR_OCSP_RESPONDER_CERT_INVALID) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_SERVER_ERROR, 30, SEC_ERROR_OCSP_SERVER_ERROR) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_TRY_SERVER_LATER, 31, \
+ SEC_ERROR_OCSP_TRY_SERVER_LATER) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_UNAUTHORIZED_REQUEST, 32, \
+ SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, 33, \
+ SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_CERT, 34, SEC_ERROR_OCSP_UNKNOWN_CERT) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_FUTURE_RESPONSE, 35, \
+ SEC_ERROR_OCSP_FUTURE_RESPONSE) \
+ MOZILLA_PKIX_MAP(ERROR_INVALID_KEY, 36, SEC_ERROR_INVALID_KEY) \
+ MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_KEYALG, 37, SEC_ERROR_UNSUPPORTED_KEYALG) \
+ MOZILLA_PKIX_MAP(ERROR_EXPIRED_ISSUER_CERTIFICATE, 38, \
+ SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) \
+ MOZILLA_PKIX_MAP(ERROR_CA_CERT_USED_AS_END_ENTITY, 39, \
+ MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY) \
+ MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_SIZE, 40, \
+ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE) \
+ MOZILLA_PKIX_MAP(ERROR_V1_CERT_USED_AS_CA, 41, \
+ MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA) \
+ MOZILLA_PKIX_MAP(ERROR_BAD_CERT_DOMAIN, 42, SSL_ERROR_BAD_CERT_DOMAIN) \
+ MOZILLA_PKIX_MAP(ERROR_NO_RFC822NAME_MATCH, 43, \
+ MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH) \
+ MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_ELLIPTIC_CURVE, 44, \
+ SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE) \
+ MOZILLA_PKIX_MAP(ERROR_NOT_YET_VALID_CERTIFICATE, 45, \
+ MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE) \
+ MOZILLA_PKIX_MAP(ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE, 46, \
+ MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE) \
+ MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_EC_POINT_FORM, 47, \
+ SEC_ERROR_UNSUPPORTED_EC_POINT_FORM) \
+ MOZILLA_PKIX_MAP(ERROR_SIGNATURE_ALGORITHM_MISMATCH, 48, \
+ MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH) \
+ MOZILLA_PKIX_MAP(ERROR_OCSP_RESPONSE_FOR_CERT_MISSING, 49, \
+ MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING) \
+ MOZILLA_PKIX_MAP(ERROR_VALIDITY_TOO_LONG, 50, \
+ MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG) \
+ MOZILLA_PKIX_MAP(ERROR_REQUIRED_TLS_FEATURE_MISSING, 51, \
+ MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING) \
+ MOZILLA_PKIX_MAP(ERROR_INVALID_INTEGER_ENCODING, 52, \
+ MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING) \
+ MOZILLA_PKIX_MAP(ERROR_EMPTY_ISSUER_NAME, 53, \
+ MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME) \
+ MOZILLA_PKIX_MAP(ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, 54, \
+ MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED) \
+ MOZILLA_PKIX_MAP(ERROR_SELF_SIGNED_CERT, 55, \
+ MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT) \
+ MOZILLA_PKIX_MAP(ERROR_MITM_DETECTED, 56, MOZILLA_PKIX_ERROR_MITM_DETECTED) \
+ MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_ARGS, FATAL_ERROR_FLAG | 1, \
+ SEC_ERROR_INVALID_ARGS) \
+ MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \
+ PR_INVALID_STATE_ERROR) \
+ MOZILLA_PKIX_MAP(FATAL_ERROR_LIBRARY_FAILURE, FATAL_ERROR_FLAG | 3, \
+ SEC_ERROR_LIBRARY_FAILURE) \
+ MOZILLA_PKIX_MAP(FATAL_ERROR_NO_MEMORY, FATAL_ERROR_FLAG | 4, \
+ SEC_ERROR_NO_MEMORY) \
+/* nothing here */
+
+enum class Result {
+#define MOZILLA_PKIX_MAP(name, value, nss_name) name = value,
+ MOZILLA_PKIX_MAP_LIST
+#undef MOZILLA_PKIX_MAP
+};
+
+// Returns the stringified name of the given result, e.g. "Result::Success",
+// or nullptr if result is unknown (invalid).
+const char* MapResultToName(Result result);
+
+// We write many comparisons as (x != Success), and this shortened name makes
+// those comparisons clearer, especially because the shortened name often
+// results in less line wrapping.
+static const Result Success = Result::Success;
+
+inline bool IsFatalError(Result rv) {
+ return (static_cast<unsigned int>(rv) & FATAL_ERROR_FLAG) != 0;
+}
+
+inline Result NotReached(const char* /*explanation*/, Result result) {
+ assert(false);
+ return result;
+}
+}
+} // namespace mozilla::pkix
+
+#endif // mozilla_pkix_Result_h
diff --git a/security/nss/lib/mozpkix/include/pkix/Time.h b/security/nss/lib/mozpkix/include/pkix/Time.h
new file mode 100644
index 000000000..8aea5479b
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/Time.h
@@ -0,0 +1,137 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2014 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_Time_h
+#define mozilla_pkix_Time_h
+
+#include <stdint.h>
+#include <ctime>
+#include <limits>
+
+#include "mozpkix/Result.h"
+
+namespace mozilla {
+namespace pkix {
+
+// Time with a range from the first second of year 0 (AD) through at least the
+// last second of year 9999, which is the range of legal times in X.509 and
+// OCSP. This type has second-level precision. The time zone is always UTC.
+//
+// Pass by value, not by reference.
+class Time final {
+ public:
+ // Construct an uninitialized instance.
+ //
+ // This will fail to compile because there is no default constructor:
+ // Time x;
+ //
+ // This will succeed, leaving the time uninitialized:
+ // Time x(Time::uninitialized);
+ enum Uninitialized { uninitialized };
+ explicit Time(Uninitialized) {}
+
+ bool operator==(const Time& other) const {
+ return elapsedSecondsAD == other.elapsedSecondsAD;
+ }
+ bool operator>(const Time& other) const {
+ return elapsedSecondsAD > other.elapsedSecondsAD;
+ }
+ bool operator>=(const Time& other) const {
+ return elapsedSecondsAD >= other.elapsedSecondsAD;
+ }
+ bool operator<(const Time& other) const {
+ return elapsedSecondsAD < other.elapsedSecondsAD;
+ }
+ bool operator<=(const Time& other) const {
+ return elapsedSecondsAD <= other.elapsedSecondsAD;
+ }
+
+ Result AddSeconds(uint64_t seconds) {
+ if (std::numeric_limits<uint64_t>::max() - elapsedSecondsAD < seconds) {
+ return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow
+ }
+ elapsedSecondsAD += seconds;
+ return Success;
+ }
+
+ Result SubtractSeconds(uint64_t seconds) {
+ if (seconds > elapsedSecondsAD) {
+ return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow
+ }
+ elapsedSecondsAD -= seconds;
+ return Success;
+ }
+
+ static const uint64_t ONE_DAY_IN_SECONDS =
+ UINT64_C(24) * UINT64_C(60) * UINT64_C(60);
+
+ private:
+ // This constructor is hidden to prevent accidents like this:
+ //
+ // Time foo(time_t t)
+ // {
+ // // WRONG! 1970-01-01-00:00:00 == time_t(0), but not Time(0)!
+ // return Time(t);
+ // }
+ explicit Time(uint64_t aElapsedSecondsAD)
+ : elapsedSecondsAD(aElapsedSecondsAD) {}
+ friend Time TimeFromElapsedSecondsAD(uint64_t);
+ friend class Duration;
+
+ uint64_t elapsedSecondsAD;
+};
+
+inline Time TimeFromElapsedSecondsAD(uint64_t aElapsedSecondsAD) {
+ return Time(aElapsedSecondsAD);
+}
+
+Time Now();
+
+// Note the epoch is the unix epoch (ie 00:00:00 UTC, 1 January 1970)
+Time TimeFromEpochInSeconds(uint64_t secondsSinceEpoch);
+
+class Duration final {
+ public:
+ Duration(Time timeA, Time timeB)
+ : durationInSeconds(
+ timeA < timeB ? timeB.elapsedSecondsAD - timeA.elapsedSecondsAD
+ : timeA.elapsedSecondsAD - timeB.elapsedSecondsAD) {}
+
+ explicit Duration(uint64_t aDurationInSeconds)
+ : durationInSeconds(aDurationInSeconds) {}
+
+ bool operator>(const Duration& other) const {
+ return durationInSeconds > other.durationInSeconds;
+ }
+ bool operator<(const Duration& other) const {
+ return durationInSeconds < other.durationInSeconds;
+ }
+
+ private:
+ uint64_t durationInSeconds;
+};
+}
+} // namespace mozilla::pkix
+
+#endif // mozilla_pkix_Time_h
diff --git a/security/nss/lib/mozpkix/include/pkix/pkix.h b/security/nss/lib/mozpkix/include/pkix/pkix.h
new file mode 100644
index 000000000..1cd6548e4
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/pkix.h
@@ -0,0 +1,160 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_pkix_h
+#define mozilla_pkix_pkix_h
+
+#include "mozpkix/pkixtypes.h"
+
+namespace mozilla {
+namespace pkix {
+
+// ----------------------------------------------------------------------------
+// LIMITED SUPPORT FOR CERTIFICATE POLICIES
+//
+// If SEC_OID_X509_ANY_POLICY is passed as the value of the requiredPolicy
+// parameter then all policy validation will be skipped. Otherwise, path
+// building and validation will be done for the given policy.
+//
+// In RFC 5280 terms:
+//
+// * user-initial-policy-set = { requiredPolicy }.
+// * initial-explicit-policy = true
+// * initial-any-policy-inhibit = false
+//
+// We allow intermediate cerificates to use this extension but since
+// we do not process the inhibit anyPolicy extesion we will fail if this
+// extension is present. TODO(bug 989051)
+// Because we force explicit policy and because we prohibit policy mapping, we
+// do not bother processing the policy mapping, or policy constraint.
+//
+// ----------------------------------------------------------------------------
+// ERROR RANKING
+//
+// BuildCertChain prioritizes certain checks ahead of others so that when a
+// certificate chain has multiple errors, the "most serious" error is
+// returned. In practice, this ranking of seriousness is tied directly to how
+// Firefox's certificate error override mechanism.
+//
+// The ranking is:
+//
+// 1. Active distrust (Result::ERROR_UNTRUSTED_CERT).
+// 2. Problems with issuer-independent properties for CA certificates.
+// 3. Unknown issuer (Result::ERROR_UNKNOWN_ISSUER).
+// 4. Problems with issuer-independent properties for EE certificates.
+// 5. Revocation.
+//
+// In particular, if BuildCertChain returns Result::ERROR_UNKNOWN_ISSUER then
+// the caller can call CERT_CheckCertValidTimes to determine if the certificate
+// is ALSO expired.
+//
+// It would be better if revocation were prioritized above expiration and
+// unknown issuer. However, it is impossible to do revocation checking without
+// knowing the issuer, since the issuer information is needed to validate the
+// revocation information. Also, generally revocation checking only works
+// during the validity period of the certificate.
+//
+// In general, when path building fails, BuildCertChain will return
+// Result::ERROR_UNKNOWN_ISSUER. However, if all attempted paths resulted in
+// the same error (which is trivially true when there is only one potential
+// path), more specific errors will be returned.
+//
+// ----------------------------------------------------------------------------
+// Meanings of specific error codes can be found in Result.h
+
+// This function attempts to find a trustworthy path from the supplied
+// certificate to a trust anchor. In the event that no trusted path is found,
+// the method returns an error result; the error ranking is described above.
+//
+// Parameters:
+// time:
+// Timestamp for which the chain should be valid; this is useful to
+// analyze whether a record was trustworthy when it was made.
+// requiredKeyUsageIfPresent:
+// What key usage bits must be set, if the extension is present at all,
+// to be considered a valid chain. Multiple values should be OR'd
+// together. If you don't want to specify anything, use
+// KeyUsage::noParticularKeyUsageRequired.
+// requiredEKUIfPresent:
+// What extended key usage bits must be set, if the EKU extension
+// exists, to be considered a valid chain. Multiple values should be
+// OR'd together. If you don't want to specify anything, use
+// KeyPurposeId::anyExtendedKeyUsage.
+// requiredPolicy:
+// This is the policy to apply; typically included in EV certificates.
+// If there is no policy, pass in CertPolicyId::anyPolicy.
+Result BuildCertChain(TrustDomain& trustDomain, Input cert, Time time,
+ EndEntityOrCA endEntityOrCA,
+ KeyUsage requiredKeyUsageIfPresent,
+ KeyPurposeId requiredEKUIfPresent,
+ const CertPolicyId& requiredPolicy,
+ /*optional*/ const Input* stapledOCSPResponse);
+
+// Verify that the given end-entity cert, which is assumed to have been already
+// validated with BuildCertChain, is valid for the given hostname. The matching
+// function attempts to implement RFC 6125 with a couple of differences:
+// - IP addresses are out of scope of RFC 6125, but this method accepts them for
+// backward compatibility (see SearchNames in pkixnames.cpp)
+// - A wildcard in a DNS-ID may only appear as the entirety of the first label.
+Result CheckCertHostname(Input cert, Input hostname,
+ NameMatchingPolicy& nameMatchingPolicy);
+
+// Construct an RFC-6960-encoded OCSP request, ready for submission to a
+// responder, for the provided CertID. The request has no extensions.
+static const size_t OCSP_REQUEST_MAX_LENGTH = 127;
+Result CreateEncodedOCSPRequest(TrustDomain& trustDomain, const CertID& certID,
+ /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH],
+ /*out*/ size_t& outLen);
+
+// The out parameter expired will be true if the response has expired. If the
+// response also indicates a revoked or unknown certificate, that error
+// will be returned. Otherwise, Result::ERROR_OCSP_OLD_RESPONSE will be
+// returned for an expired response.
+//
+// The optional parameter thisUpdate will be the thisUpdate value of
+// the encoded response if it is considered trustworthy. Only
+// good, unknown, or revoked responses that verify correctly are considered
+// trustworthy. If the response is not trustworthy, thisUpdate will be 0.
+// Similarly, the optional parameter validThrough will be the time through
+// which the encoded response is considered trustworthy (that is, as long as
+// the given time at which to validate is less than or equal to validThrough,
+// the response will be considered trustworthy).
+Result VerifyEncodedOCSPResponse(
+ TrustDomain& trustDomain, const CertID& certID, Time time,
+ uint16_t maxLifetimeInDays, Input encodedResponse,
+ /* out */ bool& expired,
+ /* optional out */ Time* thisUpdate = nullptr,
+ /* optional out */ Time* validThrough = nullptr);
+
+// Check that the TLSFeature extensions in a given end-entity cert (which is
+// assumed to have been already validated with BuildCertChain) are satisfied.
+// The only feature which we cancurrently process a requirement for is
+// status_request (OCSP stapling) so we reject any extension that specifies a
+// requirement for another value. Empty extensions are also rejected.
+Result CheckTLSFeaturesAreSatisfied(Input& cert,
+ const Input* stapledOCSPResponse);
+}
+} // namespace mozilla::pkix
+
+#endif // mozilla_pkix_pkix_h
diff --git a/security/nss/lib/mozpkix/include/pkix/pkixcheck.h b/security/nss/lib/mozpkix/include/pkix/pkixcheck.h
new file mode 100644
index 000000000..e04780e57
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/pkixcheck.h
@@ -0,0 +1,65 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_pkixcheck_h
+#define mozilla_pkix_pkixcheck_h
+
+#include "mozpkix/pkixtypes.h"
+
+namespace mozilla {
+namespace pkix {
+
+class BackCert;
+
+Result CheckIssuerIndependentProperties(TrustDomain& trustDomain,
+ const BackCert& cert, Time time,
+ KeyUsage requiredKeyUsageIfPresent,
+ KeyPurposeId requiredEKUIfPresent,
+ const CertPolicyId& requiredPolicy,
+ unsigned int subCACount,
+ /*out*/ TrustLevel& trustLevel);
+
+Result CheckNameConstraints(Input encodedNameConstraints,
+ const BackCert& firstChild,
+ KeyPurposeId requiredEKUIfPresent);
+
+Result CheckIssuer(Input encodedIssuer);
+
+// ParseValidity and CheckValidity are usually used together. First you parse
+// the dates from the DER Validity sequence, then you compare them to the time
+// at which you are validating. They are separate so that the notBefore and
+// notAfter times can be used for other things before they are checked against
+// the time of validation.
+Result ParseValidity(Input encodedValidity,
+ /*optional out*/ Time* notBeforeOut = nullptr,
+ /*optional out*/ Time* notAfterOut = nullptr);
+Result CheckValidity(Time time, Time notBefore, Time notAfter);
+
+// Check that a subject has TLS Feature (rfc7633) requirements that match its
+// potential issuer
+Result CheckTLSFeatures(const BackCert& subject, BackCert& potentialIssuer);
+}
+} // namespace mozilla::pkix
+
+#endif // mozilla_pkix_pkixcheck_h
diff --git a/security/nss/lib/mozpkix/include/pkix/pkixder.h b/security/nss/lib/mozpkix/include/pkix/pkixder.h
new file mode 100644
index 000000000..3aae0ecf6
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/pkixder.h
@@ -0,0 +1,520 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_pkixder_h
+#define mozilla_pkix_pkixder_h
+
+// Expect* functions advance the input mark and return Success if the input
+// matches the given criteria; they fail with the input mark in an undefined
+// state if the input does not match the criteria.
+//
+// Match* functions advance the input mark and return true if the input matches
+// the given criteria; they return false without changing the input mark if the
+// input does not match the criteria.
+//
+// Skip* functions unconditionally advance the input mark and return Success if
+// they are able to do so; otherwise they fail with the input mark in an
+// undefined state.
+
+#include "mozpkix/Input.h"
+#include "mozpkix/pkixtypes.h"
+
+namespace mozilla {
+namespace pkix {
+namespace der {
+
+enum Class : uint8_t {
+ UNIVERSAL = 0 << 6,
+ // APPLICATION = 1 << 6, // unused
+ CONTEXT_SPECIFIC = 2 << 6,
+ // PRIVATE = 3 << 6 // unused
+};
+
+enum Constructed { CONSTRUCTED = 1 << 5 };
+
+enum Tag : uint8_t {
+ BOOLEAN = UNIVERSAL | 0x01,
+ INTEGER = UNIVERSAL | 0x02,
+ BIT_STRING = UNIVERSAL | 0x03,
+ OCTET_STRING = UNIVERSAL | 0x04,
+ NULLTag = UNIVERSAL | 0x05,
+ OIDTag = UNIVERSAL | 0x06,
+ ENUMERATED = UNIVERSAL | 0x0a,
+ UTF8String = UNIVERSAL | 0x0c,
+ SEQUENCE = UNIVERSAL | CONSTRUCTED | 0x10, // 0x30
+ SET = UNIVERSAL | CONSTRUCTED | 0x11, // 0x31
+ PrintableString = UNIVERSAL | 0x13,
+ TeletexString = UNIVERSAL | 0x14,
+ IA5String = UNIVERSAL | 0x16,
+ UTCTime = UNIVERSAL | 0x17,
+ GENERALIZED_TIME = UNIVERSAL | 0x18,
+};
+
+enum class EmptyAllowed { No = 0, Yes = 1 };
+
+Result ReadTagAndGetValue(Reader& input, /*out*/ uint8_t& tag,
+ /*out*/ Input& value);
+Result End(Reader& input);
+
+inline Result ExpectTagAndGetValue(Reader& input, uint8_t tag,
+ /*out*/ Input& value) {
+ uint8_t actualTag;
+ Result rv = ReadTagAndGetValue(input, actualTag, value);
+ if (rv != Success) {
+ return rv;
+ }
+ if (tag != actualTag) {
+ return Result::ERROR_BAD_DER;
+ }
+ return Success;
+}
+
+inline Result ExpectTagAndGetValue(Reader& input, uint8_t tag,
+ /*out*/ Reader& value) {
+ Input valueInput;
+ Result rv = ExpectTagAndGetValue(input, tag, valueInput);
+ if (rv != Success) {
+ return rv;
+ }
+ return value.Init(valueInput);
+}
+
+inline Result ExpectTagAndEmptyValue(Reader& input, uint8_t tag) {
+ Reader value;
+ Result rv = ExpectTagAndGetValue(input, tag, value);
+ if (rv != Success) {
+ return rv;
+ }
+ return End(value);
+}
+
+inline Result ExpectTagAndSkipValue(Reader& input, uint8_t tag) {
+ Input ignoredValue;
+ return ExpectTagAndGetValue(input, tag, ignoredValue);
+}
+
+// Like ExpectTagAndGetValue, except the output Input will contain the
+// encoded tag and length along with the value.
+inline Result ExpectTagAndGetTLV(Reader& input, uint8_t tag,
+ /*out*/ Input& tlv) {
+ Reader::Mark mark(input.GetMark());
+ Result rv = ExpectTagAndSkipValue(input, tag);
+ if (rv != Success) {
+ return rv;
+ }
+ return input.GetInput(mark, tlv);
+}
+
+inline Result End(Reader& input) {
+ if (!input.AtEnd()) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ return Success;
+}
+
+template <typename Decoder>
+inline Result Nested(Reader& input, uint8_t tag, Decoder decoder) {
+ Reader nested;
+ Result rv = ExpectTagAndGetValue(input, tag, nested);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = decoder(nested);
+ if (rv != Success) {
+ return rv;
+ }
+ return End(nested);
+}
+
+template <typename Decoder>
+inline Result Nested(Reader& input, uint8_t outerTag, uint8_t innerTag,
+ Decoder decoder) {
+ Reader nestedInput;
+ Result rv = ExpectTagAndGetValue(input, outerTag, nestedInput);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = Nested(nestedInput, innerTag, decoder);
+ if (rv != Success) {
+ return rv;
+ }
+ return End(nestedInput);
+}
+
+// This can be used to decode constructs like this:
+//
+// ...
+// foos SEQUENCE OF Foo,
+// ...
+// Foo ::= SEQUENCE {
+// }
+//
+// using code like this:
+//
+// Result Foo(Reader& r) { /*...*/ }
+//
+// rv = der::NestedOf(input, der::SEQEUENCE, der::SEQUENCE, Foo);
+//
+// or:
+//
+// Result Bar(Reader& r, int value) { /*...*/ }
+//
+// int value = /*...*/;
+//
+// rv = der::NestedOf(input, der::SEQUENCE, [value](Reader& r) {
+// return Bar(r, value);
+// });
+//
+// In these examples the function will get called once for each element of
+// foos.
+//
+template <typename Decoder>
+inline Result NestedOf(Reader& input, uint8_t outerTag, uint8_t innerTag,
+ EmptyAllowed mayBeEmpty, Decoder decoder) {
+ Reader inner;
+ Result rv = ExpectTagAndGetValue(input, outerTag, inner);
+ if (rv != Success) {
+ return rv;
+ }
+
+ if (inner.AtEnd()) {
+ if (mayBeEmpty != EmptyAllowed::Yes) {
+ return Result::ERROR_BAD_DER;
+ }
+ return Success;
+ }
+
+ do {
+ rv = Nested(inner, innerTag, decoder);
+ if (rv != Success) {
+ return rv;
+ }
+ } while (!inner.AtEnd());
+
+ return Success;
+}
+
+// Often, a function will need to decode an Input or Reader that contains
+// DER-encoded data wrapped in a SEQUENCE (or similar) with nothing after it.
+// This function reduces the boilerplate necessary for stripping the outermost
+// SEQUENCE (or similar) and ensuring that nothing follows it.
+inline Result ExpectTagAndGetValueAtEnd(Reader& outer, uint8_t expectedTag,
+ /*out*/ Reader& inner) {
+ Result rv = der::ExpectTagAndGetValue(outer, expectedTag, inner);
+ if (rv != Success) {
+ return rv;
+ }
+ return der::End(outer);
+}
+
+// Similar to the above, but takes an Input instead of a Reader&.
+inline Result ExpectTagAndGetValueAtEnd(Input outer, uint8_t expectedTag,
+ /*out*/ Reader& inner) {
+ Reader outerReader(outer);
+ return ExpectTagAndGetValueAtEnd(outerReader, expectedTag, inner);
+}
+
+// Universal types
+
+namespace internal {
+
+enum class IntegralValueRestriction {
+ NoRestriction,
+ MustBePositive,
+ MustBe0To127,
+};
+
+Result IntegralBytes(
+ Reader& input, uint8_t tag, IntegralValueRestriction valueRestriction,
+ /*out*/ Input& value,
+ /*optional out*/ Input::size_type* significantBytes = nullptr);
+
+// This parser will only parse values between 0..127. If this range is
+// increased then callers will need to be changed.
+Result IntegralValue(Reader& input, uint8_t tag, /*out*/ uint8_t& value);
+
+} // namespace internal
+
+Result BitStringWithNoUnusedBits(Reader& input, /*out*/ Input& value);
+
+inline Result Boolean(Reader& input, /*out*/ bool& value) {
+ Reader valueReader;
+ Result rv = ExpectTagAndGetValue(input, BOOLEAN, valueReader);
+ if (rv != Success) {
+ return rv;
+ }
+
+ uint8_t intValue;
+ rv = valueReader.Read(intValue);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = End(valueReader);
+ if (rv != Success) {
+ return rv;
+ }
+ switch (intValue) {
+ case 0:
+ value = false;
+ return Success;
+ case 0xFF:
+ value = true;
+ return Success;
+ default:
+ return Result::ERROR_BAD_DER;
+ }
+}
+
+// This is for BOOLEAN DEFAULT FALSE.
+// The standard stipulates that "The encoding of a set value or sequence value
+// shall not include an encoding for any component value which is equal to its
+// default value." However, it appears to be common that other libraries
+// incorrectly include the value of a BOOLEAN even when it's equal to the
+// default value, so we allow invalid explicit encodings here.
+inline Result OptionalBoolean(Reader& input, /*out*/ bool& value) {
+ value = false;
+ if (input.Peek(BOOLEAN)) {
+ Result rv = Boolean(input, value);
+ if (rv != Success) {
+ return rv;
+ }
+ }
+ return Success;
+}
+
+// This parser will only parse values between 0..127. If this range is
+// increased then callers will need to be changed.
+inline Result Enumerated(Reader& input, uint8_t& value) {
+ return internal::IntegralValue(input, ENUMERATED | 0, value);
+}
+
+namespace internal {
+
+// internal::TimeChoice implements the shared functionality of GeneralizedTime
+// and TimeChoice. tag must be either UTCTime or GENERALIZED_TIME.
+//
+// Only times from 1970-01-01-00:00:00 onward are accepted, in order to
+// eliminate the chance for complications in converting times to traditional
+// time formats that start at 1970.
+Result TimeChoice(Reader& input, uint8_t tag, /*out*/ Time& time);
+
+} // namespace internal
+
+// Only times from 1970-01-01-00:00:00 onward are accepted, in order to
+// eliminate the chance for complications in converting times to traditional
+// time formats that start at 1970.
+inline Result GeneralizedTime(Reader& input, /*out*/ Time& time) {
+ return internal::TimeChoice(input, GENERALIZED_TIME, time);
+}
+
+// Only times from 1970-01-01-00:00:00 onward are accepted, in order to
+// eliminate the chance for complications in converting times to traditional
+// time formats that start at 1970.
+inline Result TimeChoice(Reader& input, /*out*/ Time& time) {
+ uint8_t expectedTag = input.Peek(UTCTime) ? UTCTime : GENERALIZED_TIME;
+ return internal::TimeChoice(input, expectedTag, time);
+}
+
+// Parse a DER integer value into value. Empty values, negative values, and
+// zero are rejected. If significantBytes is not null, then it will be set to
+// the number of significant bytes in the value (the length of the value, less
+// the length of any leading padding), which is useful for key size checks.
+inline Result PositiveInteger(
+ Reader& input, /*out*/ Input& value,
+ /*optional out*/ Input::size_type* significantBytes = nullptr) {
+ return internal::IntegralBytes(
+ input, INTEGER, internal::IntegralValueRestriction::MustBePositive, value,
+ significantBytes);
+}
+
+// This parser will only parse values between 0..127. If this range is
+// increased then callers will need to be changed.
+inline Result Integer(Reader& input, /*out*/ uint8_t& value) {
+ return internal::IntegralValue(input, INTEGER, value);
+}
+
+// This parser will only parse values between 0..127. If this range is
+// increased then callers will need to be changed. The default value must be
+// -1; defaultValue is only a parameter to make it clear in the calling code
+// what the default value is.
+inline Result OptionalInteger(Reader& input, long defaultValue,
+ /*out*/ long& value) {
+ // If we need to support a different default value in the future, we need to
+ // test that parsedValue != defaultValue.
+ if (defaultValue != -1) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+
+ if (!input.Peek(INTEGER)) {
+ value = defaultValue;
+ return Success;
+ }
+
+ uint8_t parsedValue;
+ Result rv = Integer(input, parsedValue);
+ if (rv != Success) {
+ return rv;
+ }
+ value = parsedValue;
+ return Success;
+}
+
+inline Result Null(Reader& input) {
+ return ExpectTagAndEmptyValue(input, NULLTag);
+}
+
+template <uint8_t Len>
+Result OID(Reader& input, const uint8_t (&expectedOid)[Len]) {
+ Reader value;
+ Result rv = ExpectTagAndGetValue(input, OIDTag, value);
+ if (rv != Success) {
+ return rv;
+ }
+ if (!value.MatchRest(expectedOid)) {
+ return Result::ERROR_BAD_DER;
+ }
+ return Success;
+}
+
+// PKI-specific types
+
+inline Result CertificateSerialNumber(Reader& input, /*out*/ Input& value) {
+ // http://tools.ietf.org/html/rfc5280#section-4.1.2.2:
+ //
+ // * "The serial number MUST be a positive integer assigned by the CA to
+ // each certificate."
+ // * "Certificate users MUST be able to handle serialNumber values up to 20
+ // octets. Conforming CAs MUST NOT use serialNumber values longer than 20
+ // octets."
+ // * "Note: Non-conforming CAs may issue certificates with serial numbers
+ // that are negative or zero. Certificate users SHOULD be prepared to
+ // gracefully handle such certificates."
+ return internal::IntegralBytes(
+ input, INTEGER, internal::IntegralValueRestriction::NoRestriction, value);
+}
+
+// x.509 and OCSP both use this same version numbering scheme, though OCSP
+// only supports v1.
+enum class Version { v1 = 0, v2 = 1, v3 = 2, v4 = 3, Uninitialized = 255 };
+
+// X.509 Certificate and OCSP ResponseData both use
+// "[0] EXPLICIT Version DEFAULT v1". Although an explicit encoding of v1 is
+// illegal, we support it because some real-world OCSP responses explicitly
+// encode it.
+Result OptionalVersion(Reader& input, /*out*/ Version& version);
+
+template <typename ExtensionHandler>
+inline Result OptionalExtensions(Reader& input, uint8_t tag,
+ ExtensionHandler extensionHandler) {
+ if (!input.Peek(tag)) {
+ return Success;
+ }
+
+ return Nested(input, tag, [extensionHandler](Reader& tagged) {
+ // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ //
+ // TODO(bug 997994): According to the specification, there should never be
+ // an empty sequence of extensions but we've found OCSP responses that have
+ // that (see bug 991898).
+ return NestedOf(
+ tagged, SEQUENCE, SEQUENCE, EmptyAllowed::Yes,
+ [extensionHandler](Reader& extension) -> Result {
+ // Extension ::= SEQUENCE {
+ // extnID OBJECT IDENTIFIER,
+ // critical BOOLEAN DEFAULT FALSE,
+ // extnValue OCTET STRING
+ // }
+ Reader extnID;
+ Result rv = ExpectTagAndGetValue(extension, OIDTag, extnID);
+ if (rv != Success) {
+ return rv;
+ }
+ bool critical;
+ rv = OptionalBoolean(extension, critical);
+ if (rv != Success) {
+ return rv;
+ }
+ Input extnValue;
+ rv = ExpectTagAndGetValue(extension, OCTET_STRING, extnValue);
+ if (rv != Success) {
+ return rv;
+ }
+ bool understood = false;
+ rv = extensionHandler(extnID, extnValue, critical, understood);
+ if (rv != Success) {
+ return rv;
+ }
+ if (critical && !understood) {
+ return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION;
+ }
+ return Success;
+ });
+ });
+}
+
+Result DigestAlgorithmIdentifier(Reader& input,
+ /*out*/ DigestAlgorithm& algorithm);
+
+enum class PublicKeyAlgorithm { RSA_PKCS1, ECDSA, Uninitialized };
+
+Result SignatureAlgorithmIdentifierValue(
+ Reader& input,
+ /*out*/ PublicKeyAlgorithm& publicKeyAlgorithm,
+ /*out*/ DigestAlgorithm& digestAlgorithm);
+
+struct SignedDataWithSignature final {
+ public:
+ Input data;
+ Input algorithm;
+ Input signature;
+
+ void operator=(const SignedDataWithSignature&) = delete;
+};
+
+// Parses a SEQUENCE into tbs and then parses an AlgorithmIdentifier followed
+// by a BIT STRING into signedData. This handles the commonality between
+// parsing the signed/signature fields of certificates and OCSP responses. In
+// the case of an OCSP response, the caller needs to parse the certs
+// separately.
+//
+// Note that signatureAlgorithm is NOT parsed or validated.
+//
+// Certificate ::= SEQUENCE {
+// tbsCertificate TBSCertificate,
+// signatureAlgorithm AlgorithmIdentifier,
+// signatureValue BIT STRING }
+//
+// BasicOCSPResponse ::= SEQUENCE {
+// tbsResponseData ResponseData,
+// signatureAlgorithm AlgorithmIdentifier,
+// signature BIT STRING,
+// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+Result SignedData(Reader& input, /*out*/ Reader& tbs,
+ /*out*/ SignedDataWithSignature& signedDataWithSignature);
+}
+}
+} // namespace mozilla::pkix::der
+
+#endif // mozilla_pkix_pkixder_h
diff --git a/security/nss/lib/mozpkix/include/pkix/pkixnss.h b/security/nss/lib/mozpkix/include/pkix/pkixnss.h
new file mode 100644
index 000000000..b181ca541
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/pkixnss.h
@@ -0,0 +1,106 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_pkixnss_h
+#define mozilla_pkix_pkixnss_h
+
+#include <seccomon.h>
+#include "mozpkix/pkixtypes.h"
+#include "prerror.h"
+
+namespace mozilla {
+namespace pkix {
+
+// Verifies the PKCS#1.5 signature on the given data using the given RSA public
+// key.
+Result VerifyRSAPKCS1SignedDigestNSS(const SignedDigest& sd,
+ Input subjectPublicKeyInfo,
+ void* pkcs11PinArg);
+
+// Verifies the ECDSA signature on the given data using the given ECC public
+// key.
+Result VerifyECDSASignedDigestNSS(const SignedDigest& sd,
+ Input subjectPublicKeyInfo,
+ void* pkcs11PinArg);
+
+// Computes the digest of the given data using the given digest algorithm.
+//
+// item contains the data to hash.
+// digestBuf must point to a buffer to where the digest will be written.
+// digestBufLen must be the size of the buffer, which must be exactly equal
+// to the size of the digest output (20 for SHA-1, 32 for SHA-256,
+// etc.)
+//
+// TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our
+// other, extensive, memory safety efforts in mozilla::pkix, and we should find
+// a way to provide a more-obviously-safe interface.
+Result DigestBufNSS(Input item, DigestAlgorithm digestAlg,
+ /*out*/ uint8_t* digestBuf, size_t digestBufLen);
+
+Result MapPRErrorCodeToResult(PRErrorCode errorCode);
+PRErrorCode MapResultToPRErrorCode(Result result);
+
+// The error codes within each module must fit in 16 bits. We want these
+// errors to fit in the same module as the NSS errors but not overlap with
+// any of them. Converting an NSS SEC, NSS SSL, or PSM error to an NS error
+// involves negating the value of the error and then synthesizing an error
+// in the NS_ERROR_MODULE_SECURITY module. Hence, PSM errors will start at
+// a negative value that both doesn't overlap with the current value
+// ranges for NSS errors and that will fit in 16 bits when negated.
+static const PRErrorCode ERROR_BASE = -0x4000;
+static const PRErrorCode ERROR_LIMIT = ERROR_BASE + 1000;
+
+enum ErrorCode {
+ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0,
+ MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = ERROR_BASE + 1,
+ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = ERROR_BASE + 2,
+ MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA = ERROR_BASE + 3,
+ MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH = ERROR_BASE + 4,
+ MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = ERROR_BASE + 5,
+ MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = ERROR_BASE + 6,
+ MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH = ERROR_BASE + 7,
+ MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING = ERROR_BASE + 8,
+ MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG = ERROR_BASE + 9,
+ MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING = ERROR_BASE + 10,
+ MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING = ERROR_BASE + 11,
+ MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME = ERROR_BASE + 12,
+ MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED = ERROR_BASE + 13,
+ MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT = ERROR_BASE + 14,
+ MOZILLA_PKIX_ERROR_MITM_DETECTED = ERROR_BASE + 15,
+ END_OF_LIST
+};
+
+void RegisterErrorTable();
+
+inline SECItem UnsafeMapInputToSECItem(Input input) {
+ SECItem result = {siBuffer, const_cast<uint8_t*>(input.UnsafeGetData()),
+ input.GetLength()};
+ static_assert(sizeof(decltype(input.GetLength())) <= sizeof(result.len),
+ "input.GetLength() must fit in a SECItem");
+ return result;
+}
+}
+} // namespace mozilla::pkix
+
+#endif // mozilla_pkix_pkixnss_h
diff --git a/security/nss/lib/mozpkix/include/pkix/pkixtypes.h b/security/nss/lib/mozpkix/include/pkix/pkixtypes.h
new file mode 100644
index 000000000..6b12edbb1
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/pkixtypes.h
@@ -0,0 +1,400 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_pkixtypes_h
+#define mozilla_pkix_pkixtypes_h
+
+#include <memory>
+
+#include "mozpkix/Input.h"
+#include "mozpkix/Time.h"
+#include "stdint.h"
+
+namespace mozilla {
+namespace pkix {
+
+enum class DigestAlgorithm {
+ sha512 = 1,
+ sha384 = 2,
+ sha256 = 3,
+ sha1 = 4,
+};
+
+enum class NamedCurve {
+ // secp521r1 (OID 1.3.132.0.35, RFC 5480)
+ secp521r1 = 1,
+
+ // secp384r1 (OID 1.3.132.0.34, RFC 5480)
+ secp384r1 = 2,
+
+ // secp256r1 (OID 1.2.840.10045.3.1.7, RFC 5480)
+ secp256r1 = 3,
+};
+
+struct SignedDigest final {
+ Input digest;
+ DigestAlgorithm digestAlgorithm;
+ Input signature;
+
+ void operator=(const SignedDigest&) = delete;
+};
+
+enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 };
+
+enum class KeyUsage : uint8_t {
+ digitalSignature = 0,
+ nonRepudiation = 1,
+ keyEncipherment = 2,
+ dataEncipherment = 3,
+ keyAgreement = 4,
+ keyCertSign = 5,
+ // cRLSign = 6,
+ // encipherOnly = 7,
+ // decipherOnly = 8,
+ noParticularKeyUsageRequired = 0xff,
+};
+
+enum class KeyPurposeId {
+ anyExtendedKeyUsage = 0,
+ id_kp_serverAuth = 1, // id-kp-serverAuth
+ id_kp_clientAuth = 2, // id-kp-clientAuth
+ id_kp_codeSigning = 3, // id-kp-codeSigning
+ id_kp_emailProtection = 4, // id-kp-emailProtection
+ id_kp_OCSPSigning = 9, // id-kp-OCSPSigning
+};
+
+struct CertPolicyId final {
+ uint16_t numBytes;
+ static const uint16_t MAX_BYTES = 24;
+ uint8_t bytes[MAX_BYTES];
+
+ bool IsAnyPolicy() const;
+ bool operator==(const CertPolicyId& other) const;
+
+ static const CertPolicyId anyPolicy;
+};
+
+enum class TrustLevel {
+ TrustAnchor = 1, // certificate is a trusted root CA certificate or
+ // equivalent *for the given policy*.
+ ActivelyDistrusted = 2, // certificate is known to be bad
+ InheritsTrust = 3 // certificate must chain to a trust anchor
+};
+
+// Extensions extracted during the verification flow.
+// See TrustDomain::NoteAuxiliaryExtension.
+enum class AuxiliaryExtension {
+ // Certificate Transparency data, specifically Signed Certificate
+ // Timestamps (SCTs). See RFC 6962.
+
+ // SCT list embedded in the end entity certificate. Called by BuildCertChain
+ // after the certificate containing the SCTs has passed the revocation checks.
+ EmbeddedSCTList = 1,
+ // SCT list from OCSP response. Called by VerifyEncodedOCSPResponse
+ // when its result is a success and the SCT list is present.
+ SCTListFromOCSPResponse = 2
+};
+
+// CertID references the information needed to do revocation checking for the
+// certificate issued by the given issuer with the given serial number.
+//
+// issuer must be the DER-encoded issuer field from the certificate for which
+// revocation checking is being done, **NOT** the subject field of the issuer
+// certificate. (Those two fields must be equal to each other, but they may not
+// be encoded exactly the same, and the encoding matters for OCSP.)
+// issuerSubjectPublicKeyInfo is the entire DER-encoded subjectPublicKeyInfo
+// field from the issuer's certificate. serialNumber is the entire DER-encoded
+// serial number from the subject certificate (the certificate for which we are
+// checking the revocation status).
+struct CertID final {
+ public:
+ CertID(Input aIssuer, Input aIssuerSubjectPublicKeyInfo, Input aSerialNumber)
+ : issuer(aIssuer),
+ issuerSubjectPublicKeyInfo(aIssuerSubjectPublicKeyInfo),
+ serialNumber(aSerialNumber) {}
+ const Input issuer;
+ const Input issuerSubjectPublicKeyInfo;
+ const Input serialNumber;
+
+ void operator=(const CertID&) = delete;
+};
+typedef std::unique_ptr<CertID> ScopedCertID;
+
+class DERArray {
+ public:
+ // Returns the number of DER-encoded items in the array.
+ virtual size_t GetLength() const = 0;
+
+ // Returns a weak (non-owning) pointer the ith DER-encoded item in the array
+ // (0-indexed). The result is guaranteed to be non-null if i < GetLength(),
+ // and the result is guaranteed to be nullptr if i >= GetLength().
+ virtual const Input* GetDER(size_t i) const = 0;
+
+ protected:
+ DERArray() {}
+ virtual ~DERArray() {}
+};
+
+// Applications control the behavior of path building and verification by
+// implementing the TrustDomain interface. The TrustDomain is used for all
+// cryptography and for determining which certificates are trusted or
+// distrusted.
+class TrustDomain {
+ public:
+ virtual ~TrustDomain() {}
+
+ // Determine the level of trust in the given certificate for the given role.
+ // This will be called for every certificate encountered during path
+ // building.
+ //
+ // When policy.IsAnyPolicy(), then no policy-related checking should be done.
+ // When !policy.IsAnyPolicy(), then GetCertTrust MUST NOT return with
+ // trustLevel == TrustAnchor unless the given cert is considered a trust
+ // anchor *for that policy*. In particular, if the user has marked an
+ // intermediate certificate as trusted, but that intermediate isn't in the
+ // list of EV roots, then GetCertTrust must result in
+ // trustLevel == InheritsTrust instead of trustLevel == TrustAnchor
+ // (assuming the candidate cert is not actively distrusted).
+ virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA,
+ const CertPolicyId& policy,
+ Input candidateCertDER,
+ /*out*/ TrustLevel& trustLevel) = 0;
+
+ class IssuerChecker {
+ public:
+ // potentialIssuerDER is the complete DER encoding of the certificate to
+ // be checked as a potential issuer.
+ //
+ // If additionalNameConstraints is not nullptr then it must point to an
+ // encoded NameConstraints extension value; in that case, those name
+ // constraints will be checked in addition to any any name constraints
+ // contained in potentialIssuerDER.
+ virtual Result Check(Input potentialIssuerDER,
+ /*optional*/ const Input* additionalNameConstraints,
+ /*out*/ bool& keepGoing) = 0;
+
+ protected:
+ IssuerChecker();
+ virtual ~IssuerChecker();
+
+ IssuerChecker(const IssuerChecker&) = delete;
+ void operator=(const IssuerChecker&) = delete;
+ };
+
+ // Search for a CA certificate with the given name. The implementation must
+ // call checker.Check with the DER encoding of the potential issuer
+ // certificate. The implementation must follow these rules:
+ //
+ // * The implementation must be reentrant and must limit the amount of stack
+ // space it uses; see the note on reentrancy and stack usage below.
+ // * When checker.Check does not return Success then immediately return its
+ // return value.
+ // * When checker.Check returns Success and sets keepGoing = false, then
+ // immediately return Success.
+ // * When checker.Check returns Success and sets keepGoing = true, then
+ // call checker.Check again with a different potential issuer certificate,
+ // if any more are available.
+ // * When no more potential issuer certificates are available, return
+ // Success.
+ // * Don't call checker.Check with the same potential issuer certificate more
+ // than once in a given call of FindIssuer.
+ // * The given time parameter may be used to filter out certificates that are
+ // not valid at the given time, or it may be ignored.
+ //
+ // Note on reentrancy and stack usage: checker.Check will attempt to
+ // recursively build a certificate path from the potential issuer it is given
+ // to a trusted root, as determined by this TrustDomain. That means that
+ // checker.Check may call any/all of the methods on this TrustDomain. In
+ // particular, there will be call stacks that look like this:
+ //
+ // BuildCertChain
+ // [...]
+ // TrustDomain::FindIssuer
+ // [...]
+ // IssuerChecker::Check
+ // [...]
+ // TrustDomain::FindIssuer
+ // [...]
+ // IssuerChecker::Check
+ // [...]
+ //
+ // checker.Check is responsible for limiting the recursion to a reasonable
+ // limit.
+ //
+ // checker.Check will verify that the subject's issuer field matches the
+ // potential issuer's subject field. It will also check that the potential
+ // issuer is valid at the given time. However, if the FindIssuer
+ // implementation has an efficient way of filtering potential issuers by name
+ // and/or validity period itself, then it is probably better for performance
+ // for it to do so.
+ virtual Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
+ Time time) = 0;
+
+ // Called as soon as we think we have a valid chain but before revocation
+ // checks are done. This function can be used to compute additional checks,
+ // especially checks that require the entire certificate chain. This callback
+ // can also be used to save a copy of the built certificate chain for later
+ // use.
+ //
+ // This function may be called multiple times, regardless of whether it
+ // returns success or failure. It is guaranteed that BuildCertChain will not
+ // return Success unless the last call to IsChainValid returns Success.
+ // Further,
+ // it is guaranteed that when BuildCertChain returns Success the last chain
+ // passed to IsChainValid is the valid chain that should be used for further
+ // operations that require the whole chain.
+ //
+ // Keep in mind, in particular, that if the application saves a copy of the
+ // certificate chain the last invocation of IsChainValid during a validation,
+ // it is still possible for BuildCertChain to fail, in which case the
+ // application must not assume anything about the validity of the last
+ // certificate chain passed to IsChainValid; especially, it would be very
+ // wrong to assume that the certificate chain is valid.
+ //
+ // certChain.GetDER(0) is the trust anchor.
+ virtual Result IsChainValid(const DERArray& certChain, Time time,
+ const CertPolicyId& requiredPolicy) = 0;
+
+ virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA,
+ const CertID& certID, Time time,
+ Duration validityDuration,
+ /*optional*/ const Input* stapledOCSPresponse,
+ /*optional*/ const Input* aiaExtension) = 0;
+
+ // Check that the given digest algorithm is acceptable for use in signatures.
+ //
+ // Return Success if the algorithm is acceptable,
+ // Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED if the algorithm is not
+ // acceptable, or another error code if another error occurred.
+ virtual Result CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg,
+ EndEntityOrCA endEntityOrCA,
+ Time notBefore) = 0;
+
+ // Check that the RSA public key size is acceptable.
+ //
+ // Return Success if the key size is acceptable,
+ // Result::ERROR_INADEQUATE_KEY_SIZE if the key size is not acceptable,
+ // or another error code if another error occurred.
+ virtual Result CheckRSAPublicKeyModulusSizeInBits(
+ EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits) = 0;
+
+ // Verify the given RSA PKCS#1.5 signature on the given digest using the
+ // given RSA public key.
+ //
+ // CheckRSAPublicKeyModulusSizeInBits will be called before calling this
+ // function, so it is not necessary to repeat those checks here. However,
+ // VerifyRSAPKCS1SignedDigest *is* responsible for doing the mathematical
+ // verification of the public key validity as specified in NIST SP 800-56A.
+ virtual Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
+ Input subjectPublicKeyInfo) = 0;
+
+ // Check that the given named ECC curve is acceptable for ECDSA signatures.
+ //
+ // Return Success if the curve is acceptable,
+ // Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE if the curve is not acceptable,
+ // or another error code if another error occurred.
+ virtual Result CheckECDSACurveIsAcceptable(EndEntityOrCA endEntityOrCA,
+ NamedCurve curve) = 0;
+
+ // Verify the given ECDSA signature on the given digest using the given ECC
+ // public key.
+ //
+ // CheckECDSACurveIsAcceptable will be called before calling this function,
+ // so it is not necessary to repeat that check here. However,
+ // VerifyECDSASignedDigest *is* responsible for doing the mathematical
+ // verification of the public key validity as specified in NIST SP 800-56A.
+ virtual Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
+ Input subjectPublicKeyInfo) = 0;
+
+ // Check that the validity duration is acceptable.
+ //
+ // Return Success if the validity duration is acceptable,
+ // Result::ERROR_VALIDITY_TOO_LONG if the validity duration is not acceptable,
+ // or another error code if another error occurred.
+ virtual Result CheckValidityIsAcceptable(Time notBefore, Time notAfter,
+ EndEntityOrCA endEntityOrCA,
+ KeyPurposeId keyPurpose) = 0;
+
+ // For compatibility, a CA certificate with an extended key usage that
+ // contains the id-Netscape-stepUp OID but does not contain the
+ // id-kp-serverAuth OID may be considered valid for issuing server auth
+ // certificates. This function allows TrustDomain implementations to control
+ // this setting based on the start of the validity period of the certificate
+ // in question.
+ virtual Result NetscapeStepUpMatchesServerAuth(Time notBefore,
+ /*out*/ bool& matches) = 0;
+
+ // Some certificate or OCSP response extensions do not directly participate
+ // in the verification flow, but might still be of interest to the clients
+ // (notably Certificate Transparency data, RFC 6962). Such extensions are
+ // extracted and passed to this function for further processing.
+ virtual void NoteAuxiliaryExtension(AuxiliaryExtension extension,
+ Input extensionData) = 0;
+
+ // Compute a digest of the data in item using the given digest algorithm.
+ //
+ // item contains the data to hash.
+ // digestBuf points to a buffer to where the digest will be written.
+ // digestBufLen will be the size of the digest output (20 for SHA-1,
+ // 32 for SHA-256, etc.).
+ //
+ // TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our
+ // other, extensive, memory safety efforts in mozilla::pkix, and we should
+ // find a way to provide a more-obviously-safe interface.
+ virtual Result DigestBuf(Input item, DigestAlgorithm digestAlg,
+ /*out*/ uint8_t* digestBuf, size_t digestBufLen) = 0;
+
+ protected:
+ TrustDomain() {}
+
+ TrustDomain(const TrustDomain&) = delete;
+ void operator=(const TrustDomain&) = delete;
+};
+
+enum class FallBackToSearchWithinSubject { No = 0, Yes = 1 };
+
+// Applications control the behavior of matching presented name information from
+// a certificate against a reference hostname by implementing the
+// NameMatchingPolicy interface. Used in concert with CheckCertHostname.
+class NameMatchingPolicy {
+ public:
+ virtual ~NameMatchingPolicy() {}
+
+ // Given that the certificate in question has a notBefore field with the given
+ // value, should name matching fall back to searching within the subject
+ // common name field?
+ virtual Result FallBackToCommonName(
+ Time notBefore,
+ /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) = 0;
+
+ protected:
+ NameMatchingPolicy() {}
+
+ NameMatchingPolicy(const NameMatchingPolicy&) = delete;
+ void operator=(const NameMatchingPolicy&) = delete;
+};
+}
+} // namespace mozilla::pkix
+
+#endif // mozilla_pkix_pkixtypes_h
diff --git a/security/nss/lib/mozpkix/include/pkix/pkixutil.h b/security/nss/lib/mozpkix/include/pkix/pkixutil.h
new file mode 100644
index 000000000..ca5b5a2d7
--- /dev/null
+++ b/security/nss/lib/mozpkix/include/pkix/pkixutil.h
@@ -0,0 +1,265 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix_pkixutil_h
+#define mozilla_pkix_pkixutil_h
+
+#include "mozpkix/pkixder.h"
+
+namespace mozilla {
+namespace pkix {
+
+// During path building and verification, we build a linked list of BackCerts
+// from the current cert toward the end-entity certificate. The linked list
+// is used to verify properties that aren't local to the current certificate
+// and/or the direct link between the current certificate and its issuer,
+// such as name constraints.
+//
+// Each BackCert contains pointers to all the given certificate's extensions
+// so that we can parse the extension block once and then process the
+// extensions in an order that may be different than they appear in the cert.
+class BackCert final {
+ public:
+ // certDER and childCert must be valid for the lifetime of BackCert.
+ BackCert(Input aCertDER, EndEntityOrCA aEndEntityOrCA,
+ const BackCert* aChildCert)
+ : der(aCertDER),
+ endEntityOrCA(aEndEntityOrCA),
+ childCert(aChildCert),
+ version(der::Version::Uninitialized) {}
+
+ Result Init();
+
+ const Input GetDER() const { return der; }
+ const der::SignedDataWithSignature& GetSignedData() const {
+ return signedData;
+ }
+
+ der::Version GetVersion() const { return version; }
+ const Input GetSerialNumber() const { return serialNumber; }
+ const Input GetSignature() const { return signature; }
+ const Input GetIssuer() const { return issuer; }
+ // XXX: "validity" is a horrible name for the structure that holds
+ // notBefore & notAfter, but that is the name used in RFC 5280 and we use the
+ // RFC 5280 names for everything.
+ const Input GetValidity() const { return validity; }
+ const Input GetSubject() const { return subject; }
+ const Input GetSubjectPublicKeyInfo() const { return subjectPublicKeyInfo; }
+ const Input* GetAuthorityInfoAccess() const {
+ return MaybeInput(authorityInfoAccess);
+ }
+ const Input* GetBasicConstraints() const {
+ return MaybeInput(basicConstraints);
+ }
+ const Input* GetCertificatePolicies() const {
+ return MaybeInput(certificatePolicies);
+ }
+ const Input* GetExtKeyUsage() const { return MaybeInput(extKeyUsage); }
+ const Input* GetKeyUsage() const { return MaybeInput(keyUsage); }
+ const Input* GetInhibitAnyPolicy() const {
+ return MaybeInput(inhibitAnyPolicy);
+ }
+ const Input* GetNameConstraints() const {
+ return MaybeInput(nameConstraints);
+ }
+ const Input* GetSubjectAltName() const { return MaybeInput(subjectAltName); }
+ const Input* GetRequiredTLSFeatures() const {
+ return MaybeInput(requiredTLSFeatures);
+ }
+ const Input* GetSignedCertificateTimestamps() const {
+ return MaybeInput(signedCertificateTimestamps);
+ }
+
+ private:
+ const Input der;
+
+ public:
+ const EndEntityOrCA endEntityOrCA;
+ BackCert const* const childCert;
+
+ private:
+ // When parsing certificates in BackCert::Init, we don't accept empty
+ // extensions. Consequently, we don't have to store a distinction between
+ // empty extensions and extensions that weren't included. However, when
+ // *processing* extensions, we distinguish between whether an extension was
+ // included or not based on whetehr the GetXXX function for the extension
+ // returns nullptr.
+ static inline const Input* MaybeInput(const Input& item) {
+ return item.GetLength() > 0 ? &item : nullptr;
+ }
+
+ der::SignedDataWithSignature signedData;
+
+ der::Version version;
+ Input serialNumber;
+ Input signature;
+ Input issuer;
+ // XXX: "validity" is a horrible name for the structure that holds
+ // notBefore & notAfter, but that is the name used in RFC 5280 and we use the
+ // RFC 5280 names for everything.
+ Input validity;
+ Input subject;
+ Input subjectPublicKeyInfo;
+
+ Input authorityInfoAccess;
+ Input basicConstraints;
+ Input certificatePolicies;
+ Input extKeyUsage;
+ Input inhibitAnyPolicy;
+ Input keyUsage;
+ Input nameConstraints;
+ Input subjectAltName;
+ Input criticalNetscapeCertificateType;
+ Input requiredTLSFeatures;
+ Input signedCertificateTimestamps; // RFC 6962 (Certificate Transparency)
+
+ Result RememberExtension(Reader& extnID, Input extnValue, bool critical,
+ /*out*/ bool& understood);
+
+ BackCert(const BackCert&) = delete;
+ void operator=(const BackCert&) = delete;
+};
+
+class NonOwningDERArray final : public DERArray {
+ public:
+ NonOwningDERArray() : numItems(0) {
+ // we don't need to initialize the items array because we always check
+ // numItems before accessing i.
+ }
+
+ size_t GetLength() const override { return numItems; }
+
+ const Input* GetDER(size_t i) const override {
+ return i < numItems ? &items[i] : nullptr;
+ }
+
+ Result Append(Input der) {
+ if (numItems >= MAX_LENGTH) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+ Result rv = items[numItems].Init(der); // structure assignment
+ if (rv != Success) {
+ return rv;
+ }
+ ++numItems;
+ return Success;
+ }
+
+ // Public so we can static_assert on this. Keep in sync with MAX_SUBCA_COUNT.
+ static const size_t MAX_LENGTH = 8;
+
+ private:
+ Input items[MAX_LENGTH]; // avoids any heap allocations
+ size_t numItems;
+
+ NonOwningDERArray(const NonOwningDERArray&) = delete;
+ void operator=(const NonOwningDERArray&) = delete;
+};
+
+// Extracts the SignedCertificateTimestampList structure which is encoded as an
+// OCTET STRING within the X.509v3 / OCSP extensions (see RFC 6962 section 3.3).
+Result ExtractSignedCertificateTimestampListFromExtension(Input extnValue,
+ Input& sctList);
+
+inline unsigned int DaysBeforeYear(unsigned int year) {
+ assert(year <= 9999);
+ return ((year - 1u) * 365u) +
+ ((year - 1u) / 4u) // leap years are every 4 years,
+ - ((year - 1u) / 100u) // except years divisible by 100,
+ + ((year - 1u) / 400u); // except years divisible by 400.
+}
+
+static const size_t MAX_DIGEST_SIZE_IN_BYTES = 512 / 8; // sha-512
+
+Result DigestSignedData(TrustDomain& trustDomain,
+ const der::SignedDataWithSignature& signedData,
+ /*out*/ uint8_t (&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES],
+ /*out*/ der::PublicKeyAlgorithm& publicKeyAlg,
+ /*out*/ SignedDigest& signedDigest);
+
+Result VerifySignedDigest(TrustDomain& trustDomain,
+ der::PublicKeyAlgorithm publicKeyAlg,
+ const SignedDigest& signedDigest,
+ Input signerSubjectPublicKeyInfo);
+
+// Combines DigestSignedData and VerifySignedDigest
+Result VerifySignedData(TrustDomain& trustDomain,
+ const der::SignedDataWithSignature& signedData,
+ Input signerSubjectPublicKeyInfo);
+
+// Extracts the key parameters from |subjectPublicKeyInfo|, invoking
+// the relevant methods of |trustDomain|.
+Result CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo,
+ TrustDomain& trustDomain,
+ EndEntityOrCA endEntityOrCA);
+
+// In a switch over an enum, sometimes some compilers are not satisfied that
+// all control flow paths have been considered unless there is a default case.
+// However, in our code, such a default case is almost always unreachable dead
+// code. That can be particularly problematic when the compiler wants the code
+// to choose a value, such as a return value, for the default case, but there's
+// no appropriate "impossible case" value to choose.
+//
+// MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM accounts for this. Example:
+//
+// // In xy.cpp
+// #include "xt.h"
+//
+// enum class XY { X, Y };
+//
+// int func(XY xy) {
+// switch (xy) {
+// case XY::X: return 1;
+// case XY::Y; return 2;
+// MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+// }
+// }
+#if defined(__clang__)
+// Clang will warn if not all cases are covered (-Wswitch-enum) AND it will
+// warn if a switch statement that covers every enum label has a default case
+// (-W-covered-switch-default). Versions prior to 3.5 warned about unreachable
+// code in such default cases (-Wunreachable-code) even when
+// -W-covered-switch-default was disabled, but that changed in Clang 3.5.
+#define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM // empty
+#elif defined(__GNUC__)
+// GCC will warn if not all cases are covered (-Wswitch-enum). It does not
+// assume that the default case is unreachable.
+#define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \
+ default: \
+ assert(false); \
+ __builtin_unreachable();
+#elif defined(_MSC_VER)
+// MSVC will warn if not all cases are covered (C4061, level 4). It does not
+// assume that the default case is unreachable.
+#define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \
+ default: \
+ assert(false); \
+ __assume(0);
+#else
+#error Unsupported compiler for MOZILLA_PKIX_UNREACHABLE_DEFAULT.
+#endif
+}
+} // namespace mozilla::pkix
+
+#endif // mozilla_pkix_pkixutil_h
diff --git a/security/nss/lib/mozpkix/lib/pkixbuild.cpp b/security/nss/lib/mozpkix/lib/pkixbuild.cpp
new file mode 100644
index 000000000..0ac2cb883
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixbuild.cpp
@@ -0,0 +1,418 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/pkix.h"
+
+#include "mozpkix/pkixcheck.h"
+#include "mozpkix/pkixutil.h"
+
+namespace mozilla { namespace pkix {
+
+static Result BuildForward(TrustDomain& trustDomain,
+ const BackCert& subject,
+ Time time,
+ KeyUsage requiredKeyUsageIfPresent,
+ KeyPurposeId requiredEKUIfPresent,
+ const CertPolicyId& requiredPolicy,
+ /*optional*/ const Input* stapledOCSPResponse,
+ unsigned int subCACount,
+ unsigned int& buildForwardCallBudget);
+
+TrustDomain::IssuerChecker::IssuerChecker() { }
+TrustDomain::IssuerChecker::~IssuerChecker() { }
+
+// The implementation of TrustDomain::IssuerTracker is in a subclass only to
+// hide the implementation from external users.
+class PathBuildingStep final : public TrustDomain::IssuerChecker
+{
+public:
+ PathBuildingStep(TrustDomain& aTrustDomain, const BackCert& aSubject,
+ Time aTime, KeyPurposeId aRequiredEKUIfPresent,
+ const CertPolicyId& aRequiredPolicy,
+ /*optional*/ const Input* aStapledOCSPResponse,
+ unsigned int aSubCACount, Result aDeferredSubjectError,
+ unsigned int& aBuildForwardCallBudget)
+ : trustDomain(aTrustDomain)
+ , subject(aSubject)
+ , time(aTime)
+ , requiredEKUIfPresent(aRequiredEKUIfPresent)
+ , requiredPolicy(aRequiredPolicy)
+ , stapledOCSPResponse(aStapledOCSPResponse)
+ , subCACount(aSubCACount)
+ , deferredSubjectError(aDeferredSubjectError)
+ , subjectSignaturePublicKeyAlg(der::PublicKeyAlgorithm::Uninitialized)
+ , result(Result::FATAL_ERROR_LIBRARY_FAILURE)
+ , resultWasSet(false)
+ , buildForwardCallBudget(aBuildForwardCallBudget)
+ {
+ }
+
+ Result Check(Input potentialIssuerDER,
+ /*optional*/ const Input* additionalNameConstraints,
+ /*out*/ bool& keepGoing) override;
+
+ Result CheckResult() const;
+
+private:
+ TrustDomain& trustDomain;
+ const BackCert& subject;
+ const Time time;
+ const KeyPurposeId requiredEKUIfPresent;
+ const CertPolicyId& requiredPolicy;
+ /*optional*/ Input const* const stapledOCSPResponse;
+ const unsigned int subCACount;
+ const Result deferredSubjectError;
+
+ // Initialized lazily.
+ uint8_t subjectSignatureDigestBuf[MAX_DIGEST_SIZE_IN_BYTES];
+ der::PublicKeyAlgorithm subjectSignaturePublicKeyAlg;
+ SignedDigest subjectSignature;
+
+ Result RecordResult(Result currentResult, /*out*/ bool& keepGoing);
+ Result result;
+ bool resultWasSet;
+ unsigned int& buildForwardCallBudget;
+
+ PathBuildingStep(const PathBuildingStep&) = delete;
+ void operator=(const PathBuildingStep&) = delete;
+};
+
+Result
+PathBuildingStep::RecordResult(Result newResult, /*out*/ bool& keepGoing)
+{
+ if (newResult == Result::ERROR_UNTRUSTED_CERT) {
+ newResult = Result::ERROR_UNTRUSTED_ISSUER;
+ } else if (newResult == Result::ERROR_EXPIRED_CERTIFICATE) {
+ newResult = Result::ERROR_EXPIRED_ISSUER_CERTIFICATE;
+ } else if (newResult == Result::ERROR_NOT_YET_VALID_CERTIFICATE) {
+ newResult = Result::ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE;
+ }
+
+ if (resultWasSet) {
+ if (result == Success) {
+ return NotReached("RecordResult called after finding a chain",
+ Result::FATAL_ERROR_INVALID_STATE);
+ }
+ // If every potential issuer has the same problem (e.g. expired) and/or if
+ // there is only one bad potential issuer, then return a more specific
+ // error. Otherwise, punt on trying to decide which error should be
+ // returned by returning the generic Result::ERROR_UNKNOWN_ISSUER error.
+ if (newResult != Success && newResult != result) {
+ newResult = Result::ERROR_UNKNOWN_ISSUER;
+ }
+ }
+
+ result = newResult;
+ resultWasSet = true;
+ keepGoing = result != Success;
+ return Success;
+}
+
+Result
+PathBuildingStep::CheckResult() const
+{
+ if (!resultWasSet) {
+ return Result::ERROR_UNKNOWN_ISSUER;
+ }
+ return result;
+}
+
+// The code that executes in the inner loop of BuildForward
+Result
+PathBuildingStep::Check(Input potentialIssuerDER,
+ /*optional*/ const Input* additionalNameConstraints,
+ /*out*/ bool& keepGoing)
+{
+ BackCert potentialIssuer(potentialIssuerDER, EndEntityOrCA::MustBeCA,
+ &subject);
+ Result rv = potentialIssuer.Init();
+ if (rv != Success) {
+ return RecordResult(rv, keepGoing);
+ }
+
+ // Simple TrustDomain::FindIssuers implementations may pass in all possible
+ // CA certificates without any filtering. Because of this, we don't consider
+ // a mismatched name to be an error. Instead, we just pretend that any
+ // certificate without a matching name was never passed to us. In particular,
+ // we treat the case where the TrustDomain only asks us to check CA
+ // certificates with mismatched names as equivalent to the case where the
+ // TrustDomain never called Check() at all.
+ if (!InputsAreEqual(potentialIssuer.GetSubject(), subject.GetIssuer())) {
+ keepGoing = true;
+ return Success;
+ }
+
+ // Loop prevention, done as recommended by RFC4158 Section 5.2
+ // TODO: this doesn't account for subjectAltNames!
+ // TODO(perf): This probably can and should be optimized in some way.
+ for (const BackCert* prev = potentialIssuer.childCert; prev;
+ prev = prev->childCert) {
+ if (InputsAreEqual(potentialIssuer.GetSubjectPublicKeyInfo(),
+ prev->GetSubjectPublicKeyInfo()) &&
+ InputsAreEqual(potentialIssuer.GetSubject(), prev->GetSubject())) {
+ // XXX: error code
+ return RecordResult(Result::ERROR_UNKNOWN_ISSUER, keepGoing);
+ }
+ }
+
+ if (potentialIssuer.GetNameConstraints()) {
+ rv = CheckNameConstraints(*potentialIssuer.GetNameConstraints(),
+ subject, requiredEKUIfPresent);
+ if (rv != Success) {
+ return RecordResult(rv, keepGoing);
+ }
+ }
+
+ if (additionalNameConstraints) {
+ rv = CheckNameConstraints(*additionalNameConstraints, subject,
+ requiredEKUIfPresent);
+ if (rv != Success) {
+ return RecordResult(rv, keepGoing);
+ }
+ }
+
+ rv = CheckTLSFeatures(subject, potentialIssuer);
+ if (rv != Success) {
+ return RecordResult(rv, keepGoing);
+ }
+
+ // If we've ran out of budget, stop searching.
+ if (buildForwardCallBudget == 0) {
+ Result savedRv = RecordResult(Result::ERROR_UNKNOWN_ISSUER, keepGoing);
+ keepGoing = false;
+ return savedRv;
+ }
+ buildForwardCallBudget--;
+
+ // RFC 5280, Section 4.2.1.3: "If the keyUsage extension is present, then the
+ // subject public key MUST NOT be used to verify signatures on certificates
+ // or CRLs unless the corresponding keyCertSign or cRLSign bit is set."
+ rv = BuildForward(trustDomain, potentialIssuer, time, KeyUsage::keyCertSign,
+ requiredEKUIfPresent, requiredPolicy, nullptr, subCACount,
+ buildForwardCallBudget);
+ if (rv != Success) {
+ return RecordResult(rv, keepGoing);
+ }
+
+ // Calculate the digest of the subject's signed data if we haven't already
+ // done so. We do this lazily to avoid doing it at all if we backtrack before
+ // getting to this point. We cache the result to avoid recalculating it if we
+ // backtrack after getting to this point.
+ if (subjectSignature.digest.GetLength() == 0) {
+ rv = DigestSignedData(trustDomain, subject.GetSignedData(),
+ subjectSignatureDigestBuf,
+ subjectSignaturePublicKeyAlg, subjectSignature);
+ if (rv != Success) {
+ return rv;
+ }
+ }
+
+ rv = VerifySignedDigest(trustDomain, subjectSignaturePublicKeyAlg,
+ subjectSignature,
+ potentialIssuer.GetSubjectPublicKeyInfo());
+ if (rv != Success) {
+ return RecordResult(rv, keepGoing);
+ }
+
+ // We avoid doing revocation checking for expired certificates because OCSP
+ // responders are allowed to forget about expired certificates, and many OCSP
+ // responders return an error when asked for the status of an expired
+ // certificate.
+ if (deferredSubjectError != Result::ERROR_EXPIRED_CERTIFICATE) {
+ CertID certID(subject.GetIssuer(), potentialIssuer.GetSubjectPublicKeyInfo(),
+ subject.GetSerialNumber());
+ Time notBefore(Time::uninitialized);
+ Time notAfter(Time::uninitialized);
+ // This should never fail. If we're here, we've already parsed the validity
+ // and checked that the given time is in the certificate's validity period.
+ rv = ParseValidity(subject.GetValidity(), &notBefore, &notAfter);
+ if (rv != Success) {
+ return rv;
+ }
+ Duration validityDuration(notAfter, notBefore);
+ rv = trustDomain.CheckRevocation(subject.endEntityOrCA, certID, time,
+ validityDuration, stapledOCSPResponse,
+ subject.GetAuthorityInfoAccess());
+ if (rv != Success) {
+ // Since this is actually a problem with the current subject certificate
+ // (rather than the issuer), it doesn't make sense to keep going; all
+ // paths through this certificate will fail.
+ Result savedRv = RecordResult(rv, keepGoing);
+ keepGoing = false;
+ return savedRv;
+ }
+
+ if (subject.endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
+ const Input* sctExtension = subject.GetSignedCertificateTimestamps();
+ if (sctExtension) {
+ Input sctList;
+ rv = ExtractSignedCertificateTimestampListFromExtension(*sctExtension,
+ sctList);
+ if (rv != Success) {
+ // Again, the problem is with this certificate, and all paths through
+ // it will fail.
+ Result savedRv = RecordResult(rv, keepGoing);
+ keepGoing = false;
+ return savedRv;
+ }
+ trustDomain.NoteAuxiliaryExtension(AuxiliaryExtension::EmbeddedSCTList,
+ sctList);
+ }
+ }
+ }
+
+ return RecordResult(Success, keepGoing);
+}
+
+// Recursively build the path from the given subject certificate to the root.
+//
+// Be very careful about changing the order of checks. The order is significant
+// because it affects which error we return when a certificate or certificate
+// chain has multiple problems. See the error ranking documentation in
+// pkix/pkix.h.
+static Result
+BuildForward(TrustDomain& trustDomain,
+ const BackCert& subject,
+ Time time,
+ KeyUsage requiredKeyUsageIfPresent,
+ KeyPurposeId requiredEKUIfPresent,
+ const CertPolicyId& requiredPolicy,
+ /*optional*/ const Input* stapledOCSPResponse,
+ unsigned int subCACount,
+ unsigned int& buildForwardCallBudget)
+{
+ Result rv;
+
+ TrustLevel trustLevel;
+ // If this is an end-entity and not a trust anchor, we defer reporting
+ // any error found here until after attempting to find a valid chain.
+ // See the explanation of error prioritization in pkix.h.
+ rv = CheckIssuerIndependentProperties(trustDomain, subject, time,
+ requiredKeyUsageIfPresent,
+ requiredEKUIfPresent, requiredPolicy,
+ subCACount, trustLevel);
+ Result deferredEndEntityError = Success;
+ if (rv != Success) {
+ if (subject.endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
+ trustLevel != TrustLevel::TrustAnchor) {
+ deferredEndEntityError = rv;
+ } else {
+ return rv;
+ }
+ }
+
+ if (trustLevel == TrustLevel::TrustAnchor) {
+ // End of the recursion.
+
+ NonOwningDERArray chain;
+ for (const BackCert* cert = &subject; cert; cert = cert->childCert) {
+ rv = chain.Append(cert->GetDER());
+ if (rv != Success) {
+ return NotReached("NonOwningDERArray::SetItem failed.", rv);
+ }
+ }
+
+ // This must be done here, after the chain is built but before any
+ // revocation checks have been done.
+ return trustDomain.IsChainValid(chain, time, requiredPolicy);
+ }
+
+ if (subject.endEntityOrCA == EndEntityOrCA::MustBeCA) {
+ // Avoid stack overflows and poor performance by limiting cert chain
+ // length.
+ static const unsigned int MAX_SUBCA_COUNT = 6;
+ static_assert(1/*end-entity*/ + MAX_SUBCA_COUNT + 1/*root*/ ==
+ NonOwningDERArray::MAX_LENGTH,
+ "MAX_SUBCA_COUNT and NonOwningDERArray::MAX_LENGTH mismatch.");
+ if (subCACount >= MAX_SUBCA_COUNT) {
+ return Result::ERROR_UNKNOWN_ISSUER;
+ }
+ ++subCACount;
+ } else {
+ assert(subCACount == 0);
+ }
+
+ // Find a trusted issuer.
+
+ PathBuildingStep pathBuilder(trustDomain, subject, time,
+ requiredEKUIfPresent, requiredPolicy,
+ stapledOCSPResponse, subCACount,
+ deferredEndEntityError, buildForwardCallBudget);
+
+ // TODO(bug 965136): Add SKI/AKI matching optimizations
+ rv = trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time);
+ if (rv != Success) {
+ return rv;
+ }
+
+ rv = pathBuilder.CheckResult();
+ if (rv != Success) {
+ return rv;
+ }
+
+ // If we found a valid chain but deferred reporting an error with the
+ // end-entity certificate, report it now.
+ if (deferredEndEntityError != Success) {
+ return deferredEndEntityError;
+ }
+
+ // We've built a valid chain from the subject cert up to a trusted root.
+ return Success;
+}
+
+Result
+BuildCertChain(TrustDomain& trustDomain, Input certDER,
+ Time time, EndEntityOrCA endEntityOrCA,
+ KeyUsage requiredKeyUsageIfPresent,
+ KeyPurposeId requiredEKUIfPresent,
+ const CertPolicyId& requiredPolicy,
+ /*optional*/ const Input* stapledOCSPResponse)
+{
+ // XXX: Support the legacy use of the subject CN field for indicating the
+ // domain name the certificate is valid for.
+ BackCert cert(certDER, endEntityOrCA, nullptr);
+ Result rv = cert.Init();
+ if (rv != Success) {
+ return rv;
+ }
+
+ // See bug 1056341 for context. If mozilla::pkix is being used in an
+ // environment where there are many certificates that all have the same
+ // distinguished name as their subject and issuer (but different SPKIs - see
+ // the loop prevention as per RFC4158 Section 5.2 in PathBuildingStep::Check),
+ // the space to search becomes exponential. Because it would be prohibitively
+ // expensive to explore the entire space, we introduce a budget here that,
+ // when exhausted, terminates the search with the result
+ // Result::ERROR_UNKNOWN_ISSUER. Essentially, we limit the total number of
+ // times `BuildForward` can be called. The current value appears to be a good
+ // balance between finding a path when one exists (when the space isn't too
+ // large) and timing out quickly enough when the space is too large or there
+ // is no valid path to a trust anchor.
+ unsigned int buildForwardCallBudget = 200000;
+ return BuildForward(trustDomain, cert, time, requiredKeyUsageIfPresent,
+ requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse,
+ 0/*subCACount*/, buildForwardCallBudget);
+}
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/lib/pkixcert.cpp b/security/nss/lib/mozpkix/lib/pkixcert.cpp
new file mode 100644
index 000000000..a30483738
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixcert.cpp
@@ -0,0 +1,323 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2014 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/pkixutil.h"
+
+namespace mozilla { namespace pkix {
+
+Result
+BackCert::Init()
+{
+ Result rv;
+
+ // Certificate ::= SEQUENCE {
+ // tbsCertificate TBSCertificate,
+ // signatureAlgorithm AlgorithmIdentifier,
+ // signatureValue BIT STRING }
+
+ Reader tbsCertificate;
+
+ // The scope of |input| and |certificate| are limited to this block so we
+ // don't accidentally confuse them for tbsCertificate later.
+ {
+ Reader certificate;
+ rv = der::ExpectTagAndGetValueAtEnd(der, der::SEQUENCE, certificate);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::SignedData(certificate, tbsCertificate, signedData);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::End(certificate);
+ if (rv != Success) {
+ return rv;
+ }
+ }
+
+ // TBSCertificate ::= SEQUENCE {
+ // version [0] EXPLICIT Version DEFAULT v1,
+ // serialNumber CertificateSerialNumber,
+ // signature AlgorithmIdentifier,
+ // issuer Name,
+ // validity Validity,
+ // subject Name,
+ // subjectPublicKeyInfo SubjectPublicKeyInfo,
+ // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
+ // -- If present, version MUST be v2 or v3
+ // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+ // -- If present, version MUST be v2 or v3
+ // extensions [3] EXPLICIT Extensions OPTIONAL
+ // -- If present, version MUST be v3
+ // }
+ rv = der::OptionalVersion(tbsCertificate, version);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::CertificateSerialNumber(tbsCertificate, serialNumber);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, signature);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, issuer);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, validity);
+ if (rv != Success) {
+ return rv;
+ }
+ // TODO(bug XXXXXXX): We rely on the the caller of mozilla::pkix to validate
+ // that the name is syntactically valid, if they care. In Gecko we do this
+ // implicitly by parsing the certificate into a CERTCertificate object.
+ // Instead of relying on the caller to do this, we should do it ourselves.
+ rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, subject);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE,
+ subjectPublicKeyInfo);
+ if (rv != Success) {
+ return rv;
+ }
+
+ static const uint8_t CSC = der::CONTEXT_SPECIFIC | der::CONSTRUCTED;
+
+ // According to RFC 5280, all fields below this line are forbidden for
+ // certificate versions less than v3. However, for compatibility reasons,
+ // we parse v1/v2 certificates in the same way as v3 certificates. So if
+ // these fields appear in a v1 certificate, they will be used.
+
+ // Ignore issuerUniqueID if present.
+ if (tbsCertificate.Peek(CSC | 1)) {
+ rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 1);
+ if (rv != Success) {
+ return rv;
+ }
+ }
+
+ // Ignore subjectUniqueID if present.
+ if (tbsCertificate.Peek(CSC | 2)) {
+ rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 2);
+ if (rv != Success) {
+ return rv;
+ }
+ }
+
+ rv = der::OptionalExtensions(
+ tbsCertificate, CSC | 3,
+ [this](Reader& extnID, const Input& extnValue, bool critical,
+ /*out*/ bool& understood) {
+ return RememberExtension(extnID, extnValue, critical, understood);
+ });
+ if (rv != Success) {
+ return rv;
+ }
+
+ // The Netscape Certificate Type extension is an obsolete
+ // Netscape-proprietary mechanism that we ignore in favor of the standard
+ // extensions. However, some CAs have issued certificates with the Netscape
+ // Cert Type extension marked critical. Thus, for compatibility reasons, we
+ // "understand" this extension by ignoring it when it is not critical, and
+ // by ensuring that the equivalent standardized extensions are present when
+ // it is marked critical, based on the assumption that the information in
+ // the Netscape Cert Type extension is consistent with the information in
+ // the standard extensions.
+ //
+ // Here is a mapping between the Netscape Cert Type extension and the
+ // standard extensions:
+ //
+ // Netscape Cert Type | BasicConstraints.cA | Extended Key Usage
+ // --------------------+-----------------------+----------------------
+ // SSL Server | false | id_kp_serverAuth
+ // SSL Client | false | id_kp_clientAuth
+ // S/MIME Client | false | id_kp_emailProtection
+ // Object Signing | false | id_kp_codeSigning
+ // SSL Server CA | true | id_kp_serverAuth
+ // SSL Client CA | true | id_kp_clientAuth
+ // S/MIME CA | true | id_kp_emailProtection
+ // Object Signing CA | true | id_kp_codeSigning
+ if (criticalNetscapeCertificateType.GetLength() > 0 &&
+ (basicConstraints.GetLength() == 0 || extKeyUsage.GetLength() == 0)) {
+ return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION;
+ }
+
+ return der::End(tbsCertificate);
+}
+
+Result
+BackCert::RememberExtension(Reader& extnID, Input extnValue,
+ bool critical, /*out*/ bool& understood)
+{
+ understood = false;
+
+ // python DottedOIDToCode.py id-ce-keyUsage 2.5.29.15
+ static const uint8_t id_ce_keyUsage[] = {
+ 0x55, 0x1d, 0x0f
+ };
+ // python DottedOIDToCode.py id-ce-subjectAltName 2.5.29.17
+ static const uint8_t id_ce_subjectAltName[] = {
+ 0x55, 0x1d, 0x11
+ };
+ // python DottedOIDToCode.py id-ce-basicConstraints 2.5.29.19
+ static const uint8_t id_ce_basicConstraints[] = {
+ 0x55, 0x1d, 0x13
+ };
+ // python DottedOIDToCode.py id-ce-nameConstraints 2.5.29.30
+ static const uint8_t id_ce_nameConstraints[] = {
+ 0x55, 0x1d, 0x1e
+ };
+ // python DottedOIDToCode.py id-ce-certificatePolicies 2.5.29.32
+ static const uint8_t id_ce_certificatePolicies[] = {
+ 0x55, 0x1d, 0x20
+ };
+ // python DottedOIDToCode.py id-ce-policyConstraints 2.5.29.36
+ static const uint8_t id_ce_policyConstraints[] = {
+ 0x55, 0x1d, 0x24
+ };
+ // python DottedOIDToCode.py id-ce-extKeyUsage 2.5.29.37
+ static const uint8_t id_ce_extKeyUsage[] = {
+ 0x55, 0x1d, 0x25
+ };
+ // python DottedOIDToCode.py id-ce-inhibitAnyPolicy 2.5.29.54
+ static const uint8_t id_ce_inhibitAnyPolicy[] = {
+ 0x55, 0x1d, 0x36
+ };
+ // python DottedOIDToCode.py id-pe-authorityInfoAccess 1.3.6.1.5.5.7.1.1
+ static const uint8_t id_pe_authorityInfoAccess[] = {
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
+ };
+ // python DottedOIDToCode.py id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
+ static const uint8_t id_pkix_ocsp_nocheck[] = {
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05
+ };
+ // python DottedOIDToCode.py Netscape-certificate-type 2.16.840.1.113730.1.1
+ static const uint8_t Netscape_certificate_type[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01
+ };
+ // python DottedOIDToCode.py id-pe-tlsfeature 1.3.6.1.5.5.7.1.24
+ static const uint8_t id_pe_tlsfeature[] = {
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x18
+ };
+ // python DottedOIDToCode.py id-embeddedSctList 1.3.6.1.4.1.11129.2.4.2
+ // See Section 3.3 of RFC 6962.
+ static const uint8_t id_embeddedSctList[] = {
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02
+ };
+
+ Input* out = nullptr;
+
+ // We already enforce the maximum possible constraints for policies so we
+ // can safely ignore even critical policy constraint extensions.
+ //
+ // XXX: Doing it this way won't allow us to detect duplicate
+ // policyConstraints extensions, but that's OK because (and only because) we
+ // ignore the extension.
+ Input dummyPolicyConstraints;
+
+ // We don't need to save the contents of this extension if it is present. We
+ // just need to handle its presence (it is essentially ignored right now).
+ Input dummyOCSPNocheck;
+
+ // For compatibility reasons, for some extensions we have to allow empty
+ // extension values. This would normally interfere with our duplicate
+ // extension checking code. However, as long as the extensions we allow to
+ // have empty values are also the ones we implicitly allow duplicates of,
+ // this will work fine.
+ bool emptyValueAllowed = false;
+
+ // RFC says "Conforming CAs MUST mark this extension as non-critical" for
+ // both authorityKeyIdentifier and subjectKeyIdentifier, and we do not use
+ // them for anything, so we totally ignore them here.
+
+ if (extnID.MatchRest(id_ce_keyUsage)) {
+ out = &keyUsage;
+ } else if (extnID.MatchRest(id_ce_subjectAltName)) {
+ out = &subjectAltName;
+ } else if (extnID.MatchRest(id_ce_basicConstraints)) {
+ out = &basicConstraints;
+ } else if (extnID.MatchRest(id_ce_nameConstraints)) {
+ out = &nameConstraints;
+ } else if (extnID.MatchRest(id_ce_certificatePolicies)) {
+ out = &certificatePolicies;
+ } else if (extnID.MatchRest(id_ce_policyConstraints)) {
+ out = &dummyPolicyConstraints;
+ } else if (extnID.MatchRest(id_ce_extKeyUsage)) {
+ out = &extKeyUsage;
+ } else if (extnID.MatchRest(id_ce_inhibitAnyPolicy)) {
+ out = &inhibitAnyPolicy;
+ } else if (extnID.MatchRest(id_pe_authorityInfoAccess)) {
+ out = &authorityInfoAccess;
+ } else if (extnID.MatchRest(id_pe_tlsfeature)) {
+ out = &requiredTLSFeatures;
+ } else if (extnID.MatchRest(id_embeddedSctList)) {
+ out = &signedCertificateTimestamps;
+ } else if (extnID.MatchRest(id_pkix_ocsp_nocheck) && critical) {
+ // We need to make sure we don't reject delegated OCSP response signing
+ // certificates that contain the id-pkix-ocsp-nocheck extension marked as
+ // critical when validating OCSP responses. Without this, an application
+ // that implements soft-fail OCSP might ignore a valid Revoked or Unknown
+ // response, and an application that implements hard-fail OCSP might fail
+ // to connect to a server given a valid Good response.
+ out = &dummyOCSPNocheck;
+ // We allow this extension to have an empty value.
+ // See http://comments.gmane.org/gmane.ietf.x509/30947
+ emptyValueAllowed = true;
+ } else if (extnID.MatchRest(Netscape_certificate_type) && critical) {
+ out = &criticalNetscapeCertificateType;
+ }
+
+ if (out) {
+ // Don't allow an empty value for any extension we understand. This way, we
+ // can test out->GetLength() != 0 or out->Init() to check for duplicates.
+ if (extnValue.GetLength() == 0 && !emptyValueAllowed) {
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
+ }
+ if (out->Init(extnValue) != Success) {
+ // Duplicate extension
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
+ }
+ understood = true;
+ }
+
+ return Success;
+}
+
+Result
+ExtractSignedCertificateTimestampListFromExtension(Input extnValue,
+ Input& sctList)
+{
+ Reader decodedValue;
+ Result rv = der::ExpectTagAndGetValueAtEnd(extnValue, der::OCTET_STRING,
+ decodedValue);
+ if (rv != Success) {
+ return rv;
+ }
+ return decodedValue.SkipToEnd(sctList);
+}
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/lib/pkixcheck.cpp b/security/nss/lib/mozpkix/lib/pkixcheck.cpp
new file mode 100644
index 000000000..317db01e2
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixcheck.cpp
@@ -0,0 +1,1100 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/pkixcheck.h"
+
+#include "mozpkix/pkixder.h"
+#include "mozpkix/pkixutil.h"
+
+namespace mozilla { namespace pkix {
+
+// 4.1.1.2 signatureAlgorithm
+// 4.1.2.3 signature
+
+Result
+CheckSignatureAlgorithm(TrustDomain& trustDomain,
+ EndEntityOrCA endEntityOrCA,
+ Time notBefore,
+ const der::SignedDataWithSignature& signedData,
+ Input signatureValue)
+{
+ // 4.1.1.2. signatureAlgorithm
+ der::PublicKeyAlgorithm publicKeyAlg;
+ DigestAlgorithm digestAlg;
+ Reader signatureAlgorithmReader(signedData.algorithm);
+ Result rv = der::SignatureAlgorithmIdentifierValue(signatureAlgorithmReader,
+ publicKeyAlg, digestAlg);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::End(signatureAlgorithmReader);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // 4.1.2.3. Signature
+ der::PublicKeyAlgorithm signedPublicKeyAlg;
+ DigestAlgorithm signedDigestAlg;
+ Reader signedSignatureAlgorithmReader(signatureValue);
+ rv = der::SignatureAlgorithmIdentifierValue(signedSignatureAlgorithmReader,
+ signedPublicKeyAlg,
+ signedDigestAlg);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::End(signedSignatureAlgorithmReader);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // "This field MUST contain the same algorithm identifier as the
+ // signatureAlgorithm field in the sequence Certificate." However, it may
+ // be encoded differently. In particular, one of the fields may have a NULL
+ // parameter while the other one may omit the parameter field altogether, and
+ // these are considered equivalent. Some certificates generation software
+ // actually generates certificates like that, so we compare the parsed values
+ // instead of comparing the encoded values byte-for-byte.
+ //
+ // Along the same lines, we accept two different OIDs for RSA-with-SHA1, and
+ // we consider those OIDs to be equivalent here.
+ if (publicKeyAlg != signedPublicKeyAlg || digestAlg != signedDigestAlg) {
+ return Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH;
+ }
+
+ // During the time of the deprecation of SHA-1 and the deprecation of RSA
+ // keys of less than 2048 bits, we will encounter many certs signed using
+ // SHA-1 and/or too-small RSA keys. With this in mind, we ask the trust
+ // domain early on if it knows it will reject the signature purely based on
+ // the digest algorithm and/or the RSA key size (if an RSA signature). This
+ // is a good optimization because it completely avoids calling
+ // trustDomain.FindIssuers (which may be slow) for such rejected certs, and
+ // more generally it short-circuits any path building with them (which, of
+ // course, is even slower).
+
+ rv = trustDomain.CheckSignatureDigestAlgorithm(digestAlg, endEntityOrCA,
+ notBefore);
+ if (rv != Success) {
+ return rv;
+ }
+
+ switch (publicKeyAlg) {
+ case der::PublicKeyAlgorithm::RSA_PKCS1:
+ {
+ // The RSA computation may give a result that requires fewer bytes to
+ // encode than the public key (since it is modular arithmetic). However,
+ // the last step of generating a PKCS#1.5 signature is the I2OSP
+ // procedure, which pads any such shorter result with zeros so that it
+ // is exactly the same length as the public key.
+ unsigned int signatureSizeInBits = signedData.signature.GetLength() * 8u;
+ return trustDomain.CheckRSAPublicKeyModulusSizeInBits(
+ endEntityOrCA, signatureSizeInBits);
+ }
+
+ case der::PublicKeyAlgorithm::ECDSA:
+ // In theory, we could implement a similar early-pruning optimization for
+ // ECDSA curves. However, since there has been no similar deprecation for
+ // for any curve that we support, the chances of us encountering a curve
+ // during path building is too low to be worth bothering with.
+ break;
+ case der::PublicKeyAlgorithm::Uninitialized:
+ {
+ assert(false);
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+
+ return Success;
+}
+
+// 4.1.2.4 Issuer
+
+Result
+CheckIssuer(Input encodedIssuer)
+{
+ // "The issuer field MUST contain a non-empty distinguished name (DN)."
+ Reader issuer(encodedIssuer);
+ Input encodedRDNs;
+ ExpectTagAndGetValue(issuer, der::SEQUENCE, encodedRDNs);
+ Reader rdns(encodedRDNs);
+ // Check that the issuer name contains at least one RDN
+ // (Note: this does not check related grammar rules, such as there being one
+ // or more AVAs in each RDN, or the values in AVAs not being empty strings)
+ if (rdns.AtEnd()) {
+ return Result::ERROR_EMPTY_ISSUER_NAME;
+ }
+ return Success;
+}
+
+// 4.1.2.5 Validity
+
+Result
+ParseValidity(Input encodedValidity,
+ /*optional out*/ Time* notBeforeOut,
+ /*optional out*/ Time* notAfterOut)
+{
+ Reader validity(encodedValidity);
+ Time notBefore(Time::uninitialized);
+ if (der::TimeChoice(validity, notBefore) != Success) {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+
+ Time notAfter(Time::uninitialized);
+ if (der::TimeChoice(validity, notAfter) != Success) {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+
+ if (der::End(validity) != Success) {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+
+ if (notBefore > notAfter) {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+
+ if (notBeforeOut) {
+ *notBeforeOut = notBefore;
+ }
+ if (notAfterOut) {
+ *notAfterOut = notAfter;
+ }
+
+ return Success;
+}
+
+Result
+CheckValidity(Time time, Time notBefore, Time notAfter)
+{
+ if (time < notBefore) {
+ return Result::ERROR_NOT_YET_VALID_CERTIFICATE;
+ }
+
+ if (time > notAfter) {
+ return Result::ERROR_EXPIRED_CERTIFICATE;
+ }
+
+ return Success;
+}
+
+// 4.1.2.7 Subject Public Key Info
+
+Result
+CheckSubjectPublicKeyInfoContents(Reader& input, TrustDomain& trustDomain,
+ EndEntityOrCA endEntityOrCA)
+{
+ // Here, we validate the syntax and do very basic semantic validation of the
+ // public key of the certificate. The intention here is to filter out the
+ // types of bad inputs that are most likely to trigger non-mathematical
+ // security vulnerabilities in the TrustDomain, like buffer overflows or the
+ // use of unsafe elliptic curves.
+ //
+ // We don't check (all of) the mathematical properties of the public key here
+ // because it is more efficient for the TrustDomain to do it during signature
+ // verification and/or other use of the public key. In particular, we
+ // delegate the arithmetic validation of the public key, as specified in
+ // NIST SP800-56A section 5.6.2, to the TrustDomain, at least for now.
+
+ Reader algorithm;
+ Input subjectPublicKey;
+ Result rv = der::ExpectTagAndGetValue(input, der::SEQUENCE, algorithm);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::BitStringWithNoUnusedBits(input, subjectPublicKey);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::End(input);
+ if (rv != Success) {
+ return rv;
+ }
+
+ Reader subjectPublicKeyReader(subjectPublicKey);
+
+ Reader algorithmOID;
+ rv = der::ExpectTagAndGetValue(algorithm, der::OIDTag, algorithmOID);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // RFC 3279 Section 2.3.1
+ // python DottedOIDToCode.py rsaEncryption 1.2.840.113549.1.1.1
+ static const uint8_t rsaEncryption[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01
+ };
+
+ // RFC 3279 Section 2.3.5 and RFC 5480 Section 2.1.1
+ // python DottedOIDToCode.py id-ecPublicKey 1.2.840.10045.2.1
+ static const uint8_t id_ecPublicKey[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01
+ };
+
+ if (algorithmOID.MatchRest(id_ecPublicKey)) {
+ // An id-ecPublicKey AlgorithmIdentifier has a parameter that identifes
+ // the curve being used. Although RFC 5480 specifies multiple forms, we
+ // only supported the NamedCurve form, where the curve is identified by an
+ // OID.
+
+ Reader namedCurveOIDValue;
+ rv = der::ExpectTagAndGetValue(algorithm, der::OIDTag,
+ namedCurveOIDValue);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // RFC 5480
+ // python DottedOIDToCode.py secp256r1 1.2.840.10045.3.1.7
+ static const uint8_t secp256r1[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
+ };
+
+ // RFC 5480
+ // python DottedOIDToCode.py secp384r1 1.3.132.0.34
+ static const uint8_t secp384r1[] = {
+ 0x2b, 0x81, 0x04, 0x00, 0x22
+ };
+
+ // RFC 5480
+ // python DottedOIDToCode.py secp521r1 1.3.132.0.35
+ static const uint8_t secp521r1[] = {
+ 0x2b, 0x81, 0x04, 0x00, 0x23
+ };
+
+ // Matching is attempted based on a rough estimate of the commonality of the
+ // elliptic curve, to minimize the number of MatchRest calls.
+ NamedCurve curve;
+ unsigned int bits;
+ if (namedCurveOIDValue.MatchRest(secp256r1)) {
+ curve = NamedCurve::secp256r1;
+ bits = 256;
+ } else if (namedCurveOIDValue.MatchRest(secp384r1)) {
+ curve = NamedCurve::secp384r1;
+ bits = 384;
+ } else if (namedCurveOIDValue.MatchRest(secp521r1)) {
+ curve = NamedCurve::secp521r1;
+ bits = 521;
+ } else {
+ return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
+ }
+
+ rv = trustDomain.CheckECDSACurveIsAcceptable(endEntityOrCA, curve);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // RFC 5480 Section 2.2 says that the first octet will be 0x04 to indicate
+ // an uncompressed point, which is the only encoding we support.
+ uint8_t compressedOrUncompressed;
+ rv = subjectPublicKeyReader.Read(compressedOrUncompressed);
+ if (rv != Success) {
+ return rv;
+ }
+ if (compressedOrUncompressed != 0x04) {
+ return Result::ERROR_UNSUPPORTED_EC_POINT_FORM;
+ }
+
+ // The point is encoded as two raw (not DER-encoded) integers, each padded
+ // to the bit length (rounded up to the nearest byte).
+ Input point;
+ rv = subjectPublicKeyReader.SkipToEnd(point);
+ if (rv != Success) {
+ return rv;
+ }
+ if (point.GetLength() != ((bits + 7) / 8u) * 2u) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ // XXX: We defer the mathematical verification of the validity of the point
+ // until signature verification. This means that if we never verify a
+ // signature, we'll never fully check whether the public key is valid.
+ } else if (algorithmOID.MatchRest(rsaEncryption)) {
+ // RFC 3279 Section 2.3.1 says "The parameters field MUST have ASN.1 type
+ // NULL for this algorithm identifier."
+ rv = der::ExpectTagAndEmptyValue(algorithm, der::NULLTag);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // RSAPublicKey :: = SEQUENCE{
+ // modulus INTEGER, --n
+ // publicExponent INTEGER } --e
+ rv = der::Nested(subjectPublicKeyReader, der::SEQUENCE,
+ [&trustDomain, endEntityOrCA](Reader& r) {
+ Input modulus;
+ Input::size_type modulusSignificantBytes;
+ Result nestedRv =
+ der::PositiveInteger(r, modulus, &modulusSignificantBytes);
+ if (nestedRv != Success) {
+ return nestedRv;
+ }
+ // XXX: Should we do additional checks of the modulus?
+ nestedRv = trustDomain.CheckRSAPublicKeyModulusSizeInBits(
+ endEntityOrCA, modulusSignificantBytes * 8u);
+ if (nestedRv != Success) {
+ return nestedRv;
+ }
+
+ // XXX: We don't allow the TrustDomain to validate the exponent.
+ // XXX: We don't do our own sanity checking of the exponent.
+ Input exponent;
+ return der::PositiveInteger(r, exponent);
+ });
+ if (rv != Success) {
+ return rv;
+ }
+ } else {
+ return Result::ERROR_UNSUPPORTED_KEYALG;
+ }
+
+ rv = der::End(algorithm);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::End(subjectPublicKeyReader);
+ if (rv != Success) {
+ return rv;
+ }
+
+ return Success;
+}
+
+Result
+CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo, TrustDomain& trustDomain,
+ EndEntityOrCA endEntityOrCA)
+{
+ Reader spkiReader(subjectPublicKeyInfo);
+ Result rv = der::Nested(spkiReader, der::SEQUENCE, [&](Reader& r) {
+ return CheckSubjectPublicKeyInfoContents(r, trustDomain, endEntityOrCA);
+ });
+ if (rv != Success) {
+ return rv;
+ }
+ return der::End(spkiReader);
+}
+
+// 4.2.1.3. Key Usage (id-ce-keyUsage)
+
+// As explained in the comment in CheckKeyUsage, bit 0 is the most significant
+// bit and bit 7 is the least significant bit.
+inline uint8_t KeyUsageToBitMask(KeyUsage keyUsage)
+{
+ assert(keyUsage != KeyUsage::noParticularKeyUsageRequired);
+ return 0x80u >> static_cast<uint8_t>(keyUsage);
+}
+
+Result
+CheckKeyUsage(EndEntityOrCA endEntityOrCA, const Input* encodedKeyUsage,
+ KeyUsage requiredKeyUsageIfPresent)
+{
+ if (!encodedKeyUsage) {
+ // TODO(bug 970196): Reject certificates that are being used to verify
+ // certificate signatures unless the certificate is a trust anchor, to
+ // reduce the chances of an end-entity certificate being abused as a CA
+ // certificate.
+ // if (endEntityOrCA == EndEntityOrCA::MustBeCA && !isTrustAnchor) {
+ // return Result::ERROR_INADEQUATE_KEY_USAGE;
+ // }
+ //
+ // TODO: Users may configure arbitrary certificates as trust anchors, not
+ // just roots. We should only allow a certificate without a key usage to be
+ // used as a CA when it is self-issued and self-signed.
+ return Success;
+ }
+
+ Reader input(*encodedKeyUsage);
+ Reader value;
+ if (der::ExpectTagAndGetValue(input, der::BIT_STRING, value) != Success) {
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
+ }
+
+ uint8_t numberOfPaddingBits;
+ if (value.Read(numberOfPaddingBits) != Success) {
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
+ }
+ if (numberOfPaddingBits > 7) {
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
+ }
+
+ uint8_t bits;
+ if (value.Read(bits) != Success) {
+ // Reject empty bit masks.
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
+ }
+
+ // The most significant bit is numbered 0 (digitalSignature) and the least
+ // significant bit is numbered 7 (encipherOnly), and the padding is in the
+ // least significant bits of the last byte. The numbering of bits in a byte
+ // is backwards from how we usually interpret them.
+ //
+ // For example, let's say bits is encoded in one byte with of value 0xB0 and
+ // numberOfPaddingBits == 4. Then, bits is 10110000 in binary:
+ //
+ // bit 0 bit 3
+ // | |
+ // v v
+ // 10110000
+ // ^^^^
+ // |
+ // 4 padding bits
+ //
+ // Since bits is the last byte, we have to consider the padding by ensuring
+ // that the least significant 4 bits are all zero, since DER rules require
+ // all padding bits to be zero. Then we have to look at the bit N bits to the
+ // right of the most significant bit, where N is a value from the KeyUsage
+ // enumeration.
+ //
+ // Let's say we're interested in the keyCertSign (5) bit. We'd need to look
+ // at bit 5, which is zero, so keyCertSign is not asserted. (Since we check
+ // that the padding is all zeros, it is OK to read from the padding bits.)
+ //
+ // Let's say we're interested in the digitalSignature (0) bit. We'd need to
+ // look at the bit 0 (the most significant bit), which is set, so that means
+ // digitalSignature is asserted. Similarly, keyEncipherment (2) and
+ // dataEncipherment (3) are asserted.
+ //
+ // Note that since the KeyUsage enumeration is limited to values 0-7, we
+ // only ever need to examine the first byte test for
+ // requiredKeyUsageIfPresent.
+
+ if (requiredKeyUsageIfPresent != KeyUsage::noParticularKeyUsageRequired) {
+ // Check that the required key usage bit is set.
+ if ((bits & KeyUsageToBitMask(requiredKeyUsageIfPresent)) == 0) {
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
+ }
+ }
+
+ // RFC 5280 says "The keyCertSign bit is asserted when the subject public
+ // key is used for verifying signatures on public key certificates. If the
+ // keyCertSign bit is asserted, then the cA bit in the basic constraints
+ // extension (Section 4.2.1.9) MUST also be asserted."
+ // However, we allow end-entity certificates (i.e. certificates without
+ // basicConstraints.cA set to TRUE) to claim keyCertSign for compatibility
+ // reasons. This does not compromise security because we only allow
+ // certificates with basicConstraints.cA set to TRUE to act as CAs.
+ if (requiredKeyUsageIfPresent == KeyUsage::keyCertSign &&
+ endEntityOrCA != EndEntityOrCA::MustBeCA) {
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
+ }
+
+ // The padding applies to the last byte, so skip to the last byte.
+ while (!value.AtEnd()) {
+ if (value.Read(bits) != Success) {
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
+ }
+ }
+
+ // All of the padding bits must be zero, according to DER rules.
+ uint8_t paddingMask = static_cast<uint8_t>((1 << numberOfPaddingBits) - 1);
+ if ((bits & paddingMask) != 0) {
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
+ }
+
+ return Success;
+}
+
+// RFC5820 4.2.1.4. Certificate Policies
+
+// "The user-initial-policy-set contains the special value any-policy if the
+// user is not concerned about certificate policy."
+//
+// python DottedOIDToCode.py anyPolicy 2.5.29.32.0
+
+static const uint8_t anyPolicy[] = {
+ 0x55, 0x1d, 0x20, 0x00
+};
+
+/*static*/ const CertPolicyId CertPolicyId::anyPolicy = {
+ 4, { 0x55, 0x1d, 0x20, 0x00 }
+};
+
+bool
+CertPolicyId::IsAnyPolicy() const {
+ if (this == &CertPolicyId::anyPolicy) {
+ return true;
+ }
+ return numBytes == sizeof(::mozilla::pkix::anyPolicy) &&
+ std::equal(bytes, bytes + numBytes, ::mozilla::pkix::anyPolicy);
+}
+
+bool
+CertPolicyId::operator==(const CertPolicyId& other) const
+{
+ return numBytes == other.numBytes &&
+ std::equal(bytes, bytes + numBytes, other.bytes);
+}
+
+// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+Result
+CheckCertificatePolicies(EndEntityOrCA endEntityOrCA,
+ const Input* encodedCertificatePolicies,
+ const Input* encodedInhibitAnyPolicy,
+ TrustLevel trustLevel,
+ const CertPolicyId& requiredPolicy)
+{
+ if (requiredPolicy.numBytes == 0 ||
+ requiredPolicy.numBytes > sizeof requiredPolicy.bytes) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+
+ bool requiredPolicyFound = requiredPolicy.IsAnyPolicy();
+ if (requiredPolicyFound) {
+ return Success;
+ }
+
+ // Bug 989051. Until we handle inhibitAnyPolicy we will fail close when
+ // inhibitAnyPolicy extension is present and we are validating for a policy.
+ if (!requiredPolicyFound && encodedInhibitAnyPolicy) {
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
+ }
+
+ // The root CA certificate may omit the policies that it has been
+ // trusted for, so we cannot require the policies to be present in those
+ // certificates. Instead, the determination of which roots are trusted for
+ // which policies is made by the TrustDomain's GetCertTrust method.
+ if (trustLevel == TrustLevel::TrustAnchor &&
+ endEntityOrCA == EndEntityOrCA::MustBeCA) {
+ requiredPolicyFound = true;
+ }
+
+ Input requiredPolicyDER;
+ if (requiredPolicyDER.Init(requiredPolicy.bytes, requiredPolicy.numBytes)
+ != Success) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+
+ if (encodedCertificatePolicies) {
+ Reader extension(*encodedCertificatePolicies);
+ Reader certificatePolicies;
+ Result rv = der::ExpectTagAndGetValue(extension, der::SEQUENCE,
+ certificatePolicies);
+ if (rv != Success) {
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
+ }
+ if (!extension.AtEnd()) {
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
+ }
+
+ do {
+ // PolicyInformation ::= SEQUENCE {
+ // policyIdentifier CertPolicyId,
+ // policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ // PolicyQualifierInfo OPTIONAL }
+ Reader policyInformation;
+ rv = der::ExpectTagAndGetValue(certificatePolicies, der::SEQUENCE,
+ policyInformation);
+ if (rv != Success) {
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
+ }
+
+ Reader policyIdentifier;
+ rv = der::ExpectTagAndGetValue(policyInformation, der::OIDTag,
+ policyIdentifier);
+ if (rv != Success) {
+ return rv;
+ }
+
+ if (policyIdentifier.MatchRest(requiredPolicyDER)) {
+ requiredPolicyFound = true;
+ } else if (endEntityOrCA == EndEntityOrCA::MustBeCA &&
+ policyIdentifier.MatchRest(anyPolicy)) {
+ requiredPolicyFound = true;
+ }
+
+ // RFC 5280 Section 4.2.1.4 says "Optional qualifiers, which MAY be
+ // present, are not expected to change the definition of the policy." Also,
+ // it seems that Section 6, which defines validation, does not require any
+ // matching of qualifiers. Thus, doing anything with the policy qualifiers
+ // would be a waste of time and a source of potential incompatibilities, so
+ // we just ignore them.
+ } while (!requiredPolicyFound && !certificatePolicies.AtEnd());
+ }
+
+ if (!requiredPolicyFound) {
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
+ }
+
+ return Success;
+}
+
+static const long UNLIMITED_PATH_LEN = -1; // must be less than zero
+
+// BasicConstraints ::= SEQUENCE {
+// cA BOOLEAN DEFAULT FALSE,
+// pathLenConstraint INTEGER (0..MAX) OPTIONAL }
+
+// RFC5280 4.2.1.9. Basic Constraints (id-ce-basicConstraints)
+Result
+CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
+ const Input* encodedBasicConstraints,
+ const der::Version version, TrustLevel trustLevel,
+ unsigned int subCACount)
+{
+ bool isCA = false;
+ long pathLenConstraint = UNLIMITED_PATH_LEN;
+
+ if (encodedBasicConstraints) {
+ Reader input(*encodedBasicConstraints);
+ Result rv = der::Nested(input, der::SEQUENCE,
+ [&isCA, &pathLenConstraint](Reader& r) {
+ Result nestedRv = der::OptionalBoolean(r, isCA);
+ if (nestedRv != Success) {
+ return nestedRv;
+ }
+ // TODO(bug 985025): If isCA is false, pathLenConstraint
+ // MUST NOT be included (as per RFC 5280 section
+ // 4.2.1.9), but for compatibility reasons, we don't
+ // check this.
+ return der::OptionalInteger(r, UNLIMITED_PATH_LEN, pathLenConstraint);
+ });
+ if (rv != Success) {
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
+ }
+ if (der::End(input) != Success) {
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
+ }
+ } else {
+ // "If the basic constraints extension is not present in a version 3
+ // certificate, or the extension is present but the cA boolean is not
+ // asserted, then the certified public key MUST NOT be used to verify
+ // certificate signatures."
+ //
+ // For compatibility, we must accept v1 trust anchors without basic
+ // constraints as CAs.
+ //
+ // There are devices with v1 certificates that are unlikely to be trust
+ // anchors. In order to allow applications to treat this case differently
+ // from other basic constraints violations (e.g. allowing certificate error
+ // overrides for only this case), we return a different error code.
+ //
+ // TODO: add check for self-signedness?
+ if (endEntityOrCA == EndEntityOrCA::MustBeCA && version == der::Version::v1) {
+ if (trustLevel == TrustLevel::TrustAnchor) {
+ isCA = true;
+ } else {
+ return Result::ERROR_V1_CERT_USED_AS_CA;
+ }
+ }
+ }
+
+ if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
+ // CA certificates are not trusted as EE certs.
+
+ if (isCA) {
+ // Note that this check prevents a delegated OCSP response signing
+ // certificate with the CA bit from successfully validating when we check
+ // it from pkixocsp.cpp, which is a good thing.
+ return Result::ERROR_CA_CERT_USED_AS_END_ENTITY;
+ }
+
+ return Success;
+ }
+
+ assert(endEntityOrCA == EndEntityOrCA::MustBeCA);
+
+ // End-entity certificates are not allowed to act as CA certs.
+ if (!isCA) {
+ return Result::ERROR_CA_CERT_INVALID;
+ }
+
+ if (pathLenConstraint >= 0 &&
+ static_cast<long>(subCACount) > pathLenConstraint) {
+ return Result::ERROR_PATH_LEN_CONSTRAINT_INVALID;
+ }
+
+ return Success;
+}
+
+// 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage)
+
+static Result
+MatchEKU(Reader& value, KeyPurposeId requiredEKU,
+ EndEntityOrCA endEntityOrCA, TrustDomain& trustDomain,
+ Time notBefore, /*in/out*/ bool& found,
+ /*in/out*/ bool& foundOCSPSigning)
+{
+ // See Section 5.9 of "A Layman's Guide to a Subset of ASN.1, BER, and DER"
+ // for a description of ASN.1 DER encoding of OIDs.
+
+ // id-pkix OBJECT IDENTIFIER ::=
+ // { iso(1) identified-organization(3) dod(6) internet(1)
+ // security(5) mechanisms(5) pkix(7) }
+ // id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+ // id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
+ // id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
+ // id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
+ // id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
+ // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
+ static const uint8_t server[] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 1 };
+ static const uint8_t client[] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 2 };
+ static const uint8_t code [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 3 };
+ static const uint8_t email [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 4 };
+ static const uint8_t ocsp [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 9 };
+
+ // id-Netscape OBJECT IDENTIFIER ::= { 2 16 840 1 113730 }
+ // id-Netscape-policy OBJECT IDENTIFIER ::= { id-Netscape 4 }
+ // id-Netscape-stepUp OBJECT IDENTIFIER ::= { id-Netscape-policy 1 }
+ static const uint8_t serverStepUp[] =
+ { (40*2)+16, 128+6,72, 1, 128+6,128+120,66, 4, 1 };
+
+ bool match = false;
+
+ if (!found) {
+ switch (requiredEKU) {
+ case KeyPurposeId::id_kp_serverAuth: {
+ if (value.MatchRest(server)) {
+ match = true;
+ break;
+ }
+ // Potentially treat CA certs with step-up OID as also having SSL server
+ // type. Comodo has issued certificates that require this behavior that
+ // don't expire until June 2020!
+ if (endEntityOrCA == EndEntityOrCA::MustBeCA &&
+ value.MatchRest(serverStepUp)) {
+ Result rv = trustDomain.NetscapeStepUpMatchesServerAuth(notBefore,
+ match);
+ if (rv != Success) {
+ return rv;
+ }
+ }
+ break;
+ }
+
+ case KeyPurposeId::id_kp_clientAuth:
+ match = value.MatchRest(client);
+ break;
+
+ case KeyPurposeId::id_kp_codeSigning:
+ match = value.MatchRest(code);
+ break;
+
+ case KeyPurposeId::id_kp_emailProtection:
+ match = value.MatchRest(email);
+ break;
+
+ case KeyPurposeId::id_kp_OCSPSigning:
+ match = value.MatchRest(ocsp);
+ break;
+
+ case KeyPurposeId::anyExtendedKeyUsage:
+ return NotReached("anyExtendedKeyUsage should start with found==true",
+ Result::FATAL_ERROR_LIBRARY_FAILURE);
+ }
+ }
+
+ if (match) {
+ found = true;
+ if (requiredEKU == KeyPurposeId::id_kp_OCSPSigning) {
+ foundOCSPSigning = true;
+ }
+ } else if (value.MatchRest(ocsp)) {
+ foundOCSPSigning = true;
+ }
+
+ value.SkipToEnd(); // ignore unmatched OIDs.
+
+ return Success;
+}
+
+Result
+CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
+ const Input* encodedExtendedKeyUsage,
+ KeyPurposeId requiredEKU, TrustDomain& trustDomain,
+ Time notBefore)
+{
+ // XXX: We're using Result::ERROR_INADEQUATE_CERT_TYPE here so that callers
+ // can distinguish EKU mismatch from KU mismatch from basic constraints
+ // mismatch. We should probably add a new error code that is more clear for
+ // this type of problem.
+
+ bool foundOCSPSigning = false;
+
+ if (encodedExtendedKeyUsage) {
+ bool found = requiredEKU == KeyPurposeId::anyExtendedKeyUsage;
+
+ Reader input(*encodedExtendedKeyUsage);
+ Result rv = der::NestedOf(input, der::SEQUENCE, der::OIDTag,
+ der::EmptyAllowed::No, [&](Reader& r) {
+ return MatchEKU(r, requiredEKU, endEntityOrCA, trustDomain, notBefore,
+ found, foundOCSPSigning);
+ });
+ if (rv != Success) {
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
+ }
+ if (der::End(input) != Success) {
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
+ }
+
+ // If the EKU extension was included, then the required EKU must be in the
+ // list.
+ if (!found) {
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
+ }
+ }
+
+ // pkixocsp.cpp depends on the following additional checks.
+
+ if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
+ // When validating anything other than an delegated OCSP signing cert,
+ // reject any cert that also claims to be an OCSP responder, because such
+ // a cert does not make sense. For example, if an SSL certificate were to
+ // assert id-kp-OCSPSigning then it could sign OCSP responses for itself,
+ // if not for this check.
+ // That said, we accept CA certificates with id-kp-OCSPSigning because
+ // some CAs in Mozilla's CA program have issued such intermediate
+ // certificates, and because some CAs have reported some Microsoft server
+ // software wrongly requires CA certificates to have id-kp-OCSPSigning.
+ // Allowing this exception does not cause any security issues because we
+ // require delegated OCSP response signing certificates to be end-entity
+ // certificates.
+ if (foundOCSPSigning && requiredEKU != KeyPurposeId::id_kp_OCSPSigning) {
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
+ }
+ // http://tools.ietf.org/html/rfc6960#section-4.2.2.2:
+ // "OCSP signing delegation SHALL be designated by the inclusion of
+ // id-kp-OCSPSigning in an extended key usage certificate extension
+ // included in the OCSP response signer's certificate."
+ //
+ // id-kp-OCSPSigning is the only EKU that isn't implicitly assumed when the
+ // EKU extension is missing from an end-entity certificate. However, any CA
+ // certificate can issue a delegated OCSP response signing certificate, so
+ // we can't require the EKU be explicitly included for CA certificates.
+ if (!foundOCSPSigning && requiredEKU == KeyPurposeId::id_kp_OCSPSigning) {
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
+ }
+ }
+
+ return Success;
+}
+
+Result
+CheckTLSFeatures(const BackCert& subject, BackCert& potentialIssuer)
+{
+ const Input* issuerTLSFeatures = potentialIssuer.GetRequiredTLSFeatures();
+ if (!issuerTLSFeatures) {
+ return Success;
+ }
+
+ const Input* subjectTLSFeatures = subject.GetRequiredTLSFeatures();
+ if (issuerTLSFeatures->GetLength() == 0 ||
+ !subjectTLSFeatures ||
+ !InputsAreEqual(*issuerTLSFeatures, *subjectTLSFeatures)) {
+ return Result::ERROR_REQUIRED_TLS_FEATURE_MISSING;
+ }
+
+ return Success;
+}
+
+Result
+TLSFeaturesSatisfiedInternal(const Input* requiredTLSFeatures,
+ const Input* stapledOCSPResponse)
+{
+ if (!requiredTLSFeatures) {
+ return Success;
+ }
+
+ // RFC 6066 10.2: ExtensionType status_request
+ const static uint8_t status_request = 5;
+ const static uint8_t status_request_bytes[] = { status_request };
+
+ Reader input(*requiredTLSFeatures);
+ return der::NestedOf(input, der::SEQUENCE, der::INTEGER,
+ der::EmptyAllowed::No, [&](Reader& r) {
+ if (!r.MatchRest(status_request_bytes)) {
+ return Result::ERROR_REQUIRED_TLS_FEATURE_MISSING;
+ }
+
+ if (!stapledOCSPResponse) {
+ return Result::ERROR_REQUIRED_TLS_FEATURE_MISSING;
+ }
+
+ return Result::Success;
+ });
+}
+
+Result
+CheckTLSFeaturesAreSatisfied(Input& cert,
+ const Input* stapledOCSPResponse)
+{
+ BackCert backCert(cert, EndEntityOrCA::MustBeEndEntity, nullptr);
+ Result rv = backCert.Init();
+ if (rv != Success) {
+ return rv;
+ }
+
+ return TLSFeaturesSatisfiedInternal(backCert.GetRequiredTLSFeatures(),
+ stapledOCSPResponse);
+}
+
+Result
+CheckIssuerIndependentProperties(TrustDomain& trustDomain,
+ const BackCert& cert,
+ Time time,
+ KeyUsage requiredKeyUsageIfPresent,
+ KeyPurposeId requiredEKUIfPresent,
+ const CertPolicyId& requiredPolicy,
+ unsigned int subCACount,
+ /*out*/ TrustLevel& trustLevel)
+{
+ Result rv;
+
+ const EndEntityOrCA endEntityOrCA = cert.endEntityOrCA;
+
+ // Check the cert's trust first, because we want to minimize the amount of
+ // processing we do on a distrusted cert, in case it is trying to exploit
+ // some bug in our processing.
+ rv = trustDomain.GetCertTrust(endEntityOrCA, requiredPolicy, cert.GetDER(),
+ trustLevel);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // IMPORTANT: We parse the validity interval here, so that we can use the
+ // notBefore and notAfter values in checks for things that might be deprecated
+ // over time. However, we must not fail for semantic errors until the end of
+ // this method, in order to preserve error ranking.
+ Time notBefore(Time::uninitialized);
+ Time notAfter(Time::uninitialized);
+ rv = ParseValidity(cert.GetValidity(), &notBefore, &notAfter);
+ if (rv != Success) {
+ return rv;
+ }
+
+ if (trustLevel == TrustLevel::TrustAnchor &&
+ endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
+ requiredEKUIfPresent == KeyPurposeId::id_kp_OCSPSigning) {
+ // OCSP signer certificates can never be trust anchors, especially
+ // since we don't support designated OCSP responders. All of the checks
+ // below that are dependent on trustLevel rely on this overriding of the
+ // trust level for OCSP signers.
+ trustLevel = TrustLevel::InheritsTrust;
+ }
+
+ switch (trustLevel) {
+ case TrustLevel::InheritsTrust:
+ rv = CheckSignatureAlgorithm(trustDomain, endEntityOrCA, notBefore,
+ cert.GetSignedData(), cert.GetSignature());
+ if (rv != Success) {
+ return rv;
+ }
+ break;
+
+ case TrustLevel::TrustAnchor:
+ // We don't even bother checking signatureAlgorithm or signature for
+ // syntactic validity for trust anchors, because we don't use those
+ // fields for anything, and because the trust anchor might be signed
+ // with a signature algorithm we don't actually support.
+ break;
+
+ case TrustLevel::ActivelyDistrusted:
+ return Result::ERROR_UNTRUSTED_CERT;
+ }
+
+ // Check the SPKI early, because it is one of the most selective properties
+ // of the certificate due to SHA-1 deprecation and the deprecation of
+ // certificates with keys weaker than RSA 2048.
+ rv = CheckSubjectPublicKeyInfo(cert.GetSubjectPublicKeyInfo(), trustDomain,
+ endEntityOrCA);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // 4.1.2.4. Issuer
+ rv = CheckIssuer(cert.GetIssuer());
+ if (rv != Success) {
+ return rv;
+ }
+
+ // 4.2.1.1. Authority Key Identifier is ignored (see bug 965136).
+
+ // 4.2.1.2. Subject Key Identifier is ignored (see bug 965136).
+
+ // 4.2.1.3. Key Usage
+ rv = CheckKeyUsage(endEntityOrCA, cert.GetKeyUsage(),
+ requiredKeyUsageIfPresent);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // 4.2.1.4. Certificate Policies
+ rv = CheckCertificatePolicies(endEntityOrCA, cert.GetCertificatePolicies(),
+ cert.GetInhibitAnyPolicy(), trustLevel,
+ requiredPolicy);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // 4.2.1.5. Policy Mappings are not supported; see the documentation about
+ // policy enforcement in pkix.h.
+
+ // 4.2.1.6. Subject Alternative Name dealt with during name constraint
+ // checking and during name verification (CERT_VerifyCertName).
+
+ // 4.2.1.7. Issuer Alternative Name is not something that needs checking.
+
+ // 4.2.1.8. Subject Directory Attributes is not something that needs
+ // checking.
+
+ // 4.2.1.9. Basic Constraints.
+ rv = CheckBasicConstraints(endEntityOrCA, cert.GetBasicConstraints(),
+ cert.GetVersion(), trustLevel, subCACount);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // 4.2.1.10. Name Constraints is dealt with in during path building.
+
+ // 4.2.1.11. Policy Constraints are implicitly supported; see the
+ // documentation about policy enforcement in pkix.h.
+
+ // 4.2.1.12. Extended Key Usage
+ rv = CheckExtendedKeyUsage(endEntityOrCA, cert.GetExtKeyUsage(),
+ requiredEKUIfPresent, trustDomain, notBefore);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // 4.2.1.13. CRL Distribution Points is not supported, though the
+ // TrustDomain's CheckRevocation method may parse it and process it
+ // on its own.
+
+ // 4.2.1.14. Inhibit anyPolicy is implicitly supported; see the documentation
+ // about policy enforcement in pkix.h.
+
+ // IMPORTANT: Even though we parse validity above, we wait until this point to
+ // check it, so that error ranking works correctly.
+ rv = CheckValidity(time, notBefore, notAfter);
+ if (rv != Success) {
+ return rv;
+ }
+
+ rv = trustDomain.CheckValidityIsAcceptable(notBefore, notAfter, endEntityOrCA,
+ requiredEKUIfPresent);
+ if (rv != Success) {
+ return rv;
+ }
+
+ return Success;
+}
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/lib/pkixder.cpp b/security/nss/lib/mozpkix/lib/pkixder.cpp
new file mode 100644
index 000000000..152d11a23
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixder.cpp
@@ -0,0 +1,611 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/pkixder.h"
+
+#include "mozpkix/pkixutil.h"
+
+namespace mozilla { namespace pkix { namespace der {
+
+// Too complicated to be inline
+Result
+ReadTagAndGetValue(Reader& input, /*out*/ uint8_t& tag, /*out*/ Input& value)
+{
+ Result rv;
+
+ rv = input.Read(tag);
+ if (rv != Success) {
+ return rv;
+ }
+ if ((tag & 0x1F) == 0x1F) {
+ return Result::ERROR_BAD_DER; // high tag number form not allowed
+ }
+
+ uint16_t length;
+
+ // The short form of length is a single byte with the high order bit set
+ // to zero. The long form of length is one byte with the high order bit
+ // set, followed by N bytes, where N is encoded in the lowest 7 bits of
+ // the first byte.
+ uint8_t length1;
+ rv = input.Read(length1);
+ if (rv != Success) {
+ return rv;
+ }
+ if (!(length1 & 0x80)) {
+ length = length1;
+ } else if (length1 == 0x81) {
+ uint8_t length2;
+ rv = input.Read(length2);
+ if (rv != Success) {
+ return rv;
+ }
+ if (length2 < 128) {
+ // Not shortest possible encoding
+ return Result::ERROR_BAD_DER;
+ }
+ length = length2;
+ } else if (length1 == 0x82) {
+ rv = input.Read(length);
+ if (rv != Success) {
+ return rv;
+ }
+ if (length < 256) {
+ // Not shortest possible encoding
+ return Result::ERROR_BAD_DER;
+ }
+ } else {
+ // We don't support lengths larger than 2^16 - 1.
+ return Result::ERROR_BAD_DER;
+ }
+
+ return input.Skip(length, value);
+}
+
+static Result
+OptionalNull(Reader& input)
+{
+ if (input.Peek(NULLTag)) {
+ return Null(input);
+ }
+ return Success;
+}
+
+namespace {
+
+Result
+AlgorithmIdentifierValue(Reader& input, /*out*/ Reader& algorithmOIDValue)
+{
+ Result rv = ExpectTagAndGetValue(input, der::OIDTag, algorithmOIDValue);
+ if (rv != Success) {
+ return rv;
+ }
+ return OptionalNull(input);
+}
+
+} // namespace
+
+Result
+SignatureAlgorithmIdentifierValue(Reader& input,
+ /*out*/ PublicKeyAlgorithm& publicKeyAlgorithm,
+ /*out*/ DigestAlgorithm& digestAlgorithm)
+{
+ // RFC 5758 Section 3.2 (ECDSA with SHA-2), and RFC 3279 Section 2.2.3
+ // (ECDSA with SHA-1) say that parameters must be omitted.
+ //
+ // RFC 4055 Section 5 and RFC 3279 Section 2.2.1 both say that parameters for
+ // RSA must be encoded as NULL; we relax that requirement by allowing the
+ // NULL to be omitted, to match all the other signature algorithms we support
+ // and for compatibility.
+ Reader algorithmID;
+ Result rv = AlgorithmIdentifierValue(input, algorithmID);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // RFC 5758 Section 3.2 (ecdsa-with-SHA224 is intentionally excluded)
+ // python DottedOIDToCode.py ecdsa-with-SHA256 1.2.840.10045.4.3.2
+ static const uint8_t ecdsa_with_SHA256[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02
+ };
+ // python DottedOIDToCode.py ecdsa-with-SHA384 1.2.840.10045.4.3.3
+ static const uint8_t ecdsa_with_SHA384[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03
+ };
+ // python DottedOIDToCode.py ecdsa-with-SHA512 1.2.840.10045.4.3.4
+ static const uint8_t ecdsa_with_SHA512[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
+ };
+
+ // RFC 4055 Section 5 (sha224WithRSAEncryption is intentionally excluded)
+ // python DottedOIDToCode.py sha256WithRSAEncryption 1.2.840.113549.1.1.11
+ static const uint8_t sha256WithRSAEncryption[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
+ };
+ // python DottedOIDToCode.py sha384WithRSAEncryption 1.2.840.113549.1.1.12
+ static const uint8_t sha384WithRSAEncryption[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c
+ };
+ // python DottedOIDToCode.py sha512WithRSAEncryption 1.2.840.113549.1.1.13
+ static const uint8_t sha512WithRSAEncryption[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d
+ };
+
+ // RFC 3279 Section 2.2.1
+ // python DottedOIDToCode.py sha-1WithRSAEncryption 1.2.840.113549.1.1.5
+ static const uint8_t sha_1WithRSAEncryption[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05
+ };
+
+ // NIST Open Systems Environment (OSE) Implementor's Workshop (OIW)
+ // http://www.oiw.org/agreements/stable/12s-9412.txt (no longer works).
+ // http://www.imc.org/ietf-pkix/old-archive-97/msg01166.html
+ // We need to support this this non-PKIX OID for compatibility.
+ // python DottedOIDToCode.py sha1WithRSASignature 1.3.14.3.2.29
+ static const uint8_t sha1WithRSASignature[] = {
+ 0x2b, 0x0e, 0x03, 0x02, 0x1d
+ };
+
+ // RFC 3279 Section 2.2.3
+ // python DottedOIDToCode.py ecdsa-with-SHA1 1.2.840.10045.4.1
+ static const uint8_t ecdsa_with_SHA1[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01
+ };
+
+ // Matching is attempted based on a rough estimate of the commonality of the
+ // algorithm, to minimize the number of MatchRest calls.
+ if (algorithmID.MatchRest(sha256WithRSAEncryption)) {
+ publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
+ digestAlgorithm = DigestAlgorithm::sha256;
+ } else if (algorithmID.MatchRest(ecdsa_with_SHA256)) {
+ publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
+ digestAlgorithm = DigestAlgorithm::sha256;
+ } else if (algorithmID.MatchRest(sha_1WithRSAEncryption)) {
+ publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
+ digestAlgorithm = DigestAlgorithm::sha1;
+ } else if (algorithmID.MatchRest(ecdsa_with_SHA1)) {
+ publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
+ digestAlgorithm = DigestAlgorithm::sha1;
+ } else if (algorithmID.MatchRest(ecdsa_with_SHA384)) {
+ publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
+ digestAlgorithm = DigestAlgorithm::sha384;
+ } else if (algorithmID.MatchRest(ecdsa_with_SHA512)) {
+ publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
+ digestAlgorithm = DigestAlgorithm::sha512;
+ } else if (algorithmID.MatchRest(sha384WithRSAEncryption)) {
+ publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
+ digestAlgorithm = DigestAlgorithm::sha384;
+ } else if (algorithmID.MatchRest(sha512WithRSAEncryption)) {
+ publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
+ digestAlgorithm = DigestAlgorithm::sha512;
+ } else if (algorithmID.MatchRest(sha1WithRSASignature)) {
+ // XXX(bug 1042479): recognize this old OID for compatibility.
+ publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
+ digestAlgorithm = DigestAlgorithm::sha1;
+ } else {
+ return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
+ }
+
+ return Success;
+}
+
+Result
+DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm)
+{
+ return der::Nested(input, SEQUENCE, [&algorithm](Reader& r) -> Result {
+ Reader algorithmID;
+ Result rv = AlgorithmIdentifierValue(r, algorithmID);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // RFC 4055 Section 2.1
+ // python DottedOIDToCode.py id-sha1 1.3.14.3.2.26
+ static const uint8_t id_sha1[] = {
+ 0x2b, 0x0e, 0x03, 0x02, 0x1a
+ };
+ // python DottedOIDToCode.py id-sha256 2.16.840.1.101.3.4.2.1
+ static const uint8_t id_sha256[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+ };
+ // python DottedOIDToCode.py id-sha384 2.16.840.1.101.3.4.2.2
+ static const uint8_t id_sha384[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+ };
+ // python DottedOIDToCode.py id-sha512 2.16.840.1.101.3.4.2.3
+ static const uint8_t id_sha512[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+ };
+
+ // Matching is attempted based on a rough estimate of the commonality of the
+ // algorithm, to minimize the number of MatchRest calls.
+ if (algorithmID.MatchRest(id_sha1)) {
+ algorithm = DigestAlgorithm::sha1;
+ } else if (algorithmID.MatchRest(id_sha256)) {
+ algorithm = DigestAlgorithm::sha256;
+ } else if (algorithmID.MatchRest(id_sha384)) {
+ algorithm = DigestAlgorithm::sha384;
+ } else if (algorithmID.MatchRest(id_sha512)) {
+ algorithm = DigestAlgorithm::sha512;
+ } else {
+ return Result::ERROR_INVALID_ALGORITHM;
+ }
+
+ return Success;
+ });
+}
+
+Result
+SignedData(Reader& input, /*out*/ Reader& tbs,
+ /*out*/ SignedDataWithSignature& signedData)
+{
+ Reader::Mark mark(input.GetMark());
+
+ Result rv;
+ rv = ExpectTagAndGetValue(input, SEQUENCE, tbs);
+ if (rv != Success) {
+ return rv;
+ }
+
+ rv = input.GetInput(mark, signedData.data);
+ if (rv != Success) {
+ return rv;
+ }
+
+ rv = ExpectTagAndGetValue(input, der::SEQUENCE, signedData.algorithm);
+ if (rv != Success) {
+ return rv;
+ }
+
+ rv = BitStringWithNoUnusedBits(input, signedData.signature);
+ if (rv == Result::ERROR_BAD_DER) {
+ rv = Result::ERROR_BAD_SIGNATURE;
+ }
+ return rv;
+}
+
+Result
+BitStringWithNoUnusedBits(Reader& input, /*out*/ Input& value)
+{
+ Reader valueWithUnusedBits;
+ Result rv = ExpectTagAndGetValue(input, BIT_STRING, valueWithUnusedBits);
+ if (rv != Success) {
+ return rv;
+ }
+
+ uint8_t unusedBitsAtEnd;
+ if (valueWithUnusedBits.Read(unusedBitsAtEnd) != Success) {
+ return Result::ERROR_BAD_DER;
+ }
+ // XXX: Really the constraint should be that unusedBitsAtEnd must be less
+ // than 7. But, we suspect there are no real-world values in OCSP responses
+ // or certificates with non-zero unused bits. It seems like NSS assumes this
+ // in various places, so we enforce it too in order to simplify this code. If
+ // we find compatibility issues, we'll know we're wrong and we'll have to
+ // figure out how to shift the bits around.
+ if (unusedBitsAtEnd != 0) {
+ return Result::ERROR_BAD_DER;
+ }
+ return valueWithUnusedBits.SkipToEnd(value);
+}
+
+static inline Result
+ReadDigit(Reader& input, /*out*/ unsigned int& value)
+{
+ uint8_t b;
+ if (input.Read(b) != Success) {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+ if (b < '0' || b > '9') {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+ value = static_cast<unsigned int>(b - static_cast<uint8_t>('0'));
+ return Success;
+}
+
+static inline Result
+ReadTwoDigits(Reader& input, unsigned int minValue, unsigned int maxValue,
+ /*out*/ unsigned int& value)
+{
+ unsigned int hi;
+ Result rv = ReadDigit(input, hi);
+ if (rv != Success) {
+ return rv;
+ }
+ unsigned int lo;
+ rv = ReadDigit(input, lo);
+ if (rv != Success) {
+ return rv;
+ }
+ value = (hi * 10) + lo;
+ if (value < minValue || value > maxValue) {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+ return Success;
+}
+
+namespace internal {
+
+// We parse GeneralizedTime and UTCTime according to RFC 5280 and we do not
+// accept all time formats allowed in the ASN.1 spec. That is,
+// GeneralizedTime must always be in the format YYYYMMDDHHMMSSZ and UTCTime
+// must always be in the format YYMMDDHHMMSSZ. Timezone formats of the form
+// +HH:MM or -HH:MM or NOT accepted.
+Result
+TimeChoice(Reader& tagged, uint8_t expectedTag, /*out*/ Time& time)
+{
+ unsigned int days;
+
+ Reader input;
+ Result rv = ExpectTagAndGetValue(tagged, expectedTag, input);
+ if (rv != Success) {
+ return rv;
+ }
+
+ unsigned int yearHi;
+ unsigned int yearLo;
+ if (expectedTag == GENERALIZED_TIME) {
+ rv = ReadTwoDigits(input, 0, 99, yearHi);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = ReadTwoDigits(input, 0, 99, yearLo);
+ if (rv != Success) {
+ return rv;
+ }
+ } else if (expectedTag == UTCTime) {
+ rv = ReadTwoDigits(input, 0, 99, yearLo);
+ if (rv != Success) {
+ return rv;
+ }
+ yearHi = yearLo >= 50u ? 19u : 20u;
+ } else {
+ return NotReached("invalid tag given to TimeChoice",
+ Result::ERROR_INVALID_DER_TIME);
+ }
+ unsigned int year = (yearHi * 100u) + yearLo;
+ if (year < 1970u) {
+ // We don't support dates before January 1, 1970 because that is the epoch.
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+ days = DaysBeforeYear(year);
+
+ unsigned int month;
+ rv = ReadTwoDigits(input, 1u, 12u, month);
+ if (rv != Success) {
+ return rv;
+ }
+ unsigned int daysInMonth;
+ static const unsigned int jan = 31u;
+ const unsigned int feb = ((year % 4u == 0u) &&
+ ((year % 100u != 0u) || (year % 400u == 0u)))
+ ? 29u
+ : 28u;
+ static const unsigned int mar = 31u;
+ static const unsigned int apr = 30u;
+ static const unsigned int may = 31u;
+ static const unsigned int jun = 30u;
+ static const unsigned int jul = 31u;
+ static const unsigned int aug = 31u;
+ static const unsigned int sep = 30u;
+ static const unsigned int oct = 31u;
+ static const unsigned int nov = 30u;
+ static const unsigned int dec = 31u;
+ switch (month) {
+ case 1: daysInMonth = jan; break;
+ case 2: daysInMonth = feb; days += jan; break;
+ case 3: daysInMonth = mar; days += jan + feb; break;
+ case 4: daysInMonth = apr; days += jan + feb + mar; break;
+ case 5: daysInMonth = may; days += jan + feb + mar + apr; break;
+ case 6: daysInMonth = jun; days += jan + feb + mar + apr + may; break;
+ case 7: daysInMonth = jul; days += jan + feb + mar + apr + may + jun;
+ break;
+ case 8: daysInMonth = aug; days += jan + feb + mar + apr + may + jun +
+ jul;
+ break;
+ case 9: daysInMonth = sep; days += jan + feb + mar + apr + may + jun +
+ jul + aug;
+ break;
+ case 10: daysInMonth = oct; days += jan + feb + mar + apr + may + jun +
+ jul + aug + sep;
+ break;
+ case 11: daysInMonth = nov; days += jan + feb + mar + apr + may + jun +
+ jul + aug + sep + oct;
+ break;
+ case 12: daysInMonth = dec; days += jan + feb + mar + apr + may + jun +
+ jul + aug + sep + oct + nov;
+ break;
+ default:
+ return NotReached("month already bounds-checked by ReadTwoDigits",
+ Result::FATAL_ERROR_INVALID_STATE);
+ }
+
+ unsigned int dayOfMonth;
+ rv = ReadTwoDigits(input, 1u, daysInMonth, dayOfMonth);
+ if (rv != Success) {
+ return rv;
+ }
+ days += dayOfMonth - 1;
+
+ unsigned int hours;
+ rv = ReadTwoDigits(input, 0u, 23u, hours);
+ if (rv != Success) {
+ return rv;
+ }
+ unsigned int minutes;
+ rv = ReadTwoDigits(input, 0u, 59u, minutes);
+ if (rv != Success) {
+ return rv;
+ }
+ unsigned int seconds;
+ rv = ReadTwoDigits(input, 0u, 59u, seconds);
+ if (rv != Success) {
+ return rv;
+ }
+
+ uint8_t b;
+ if (input.Read(b) != Success) {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+ if (b != 'Z') {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+ if (End(input) != Success) {
+ return Result::ERROR_INVALID_DER_TIME;
+ }
+
+ uint64_t totalSeconds = (static_cast<uint64_t>(days) * 24u * 60u * 60u) +
+ (static_cast<uint64_t>(hours) * 60u * 60u) +
+ (static_cast<uint64_t>(minutes) * 60u) +
+ seconds;
+
+ time = TimeFromElapsedSecondsAD(totalSeconds);
+ return Success;
+}
+
+Result
+IntegralBytes(Reader& input, uint8_t tag,
+ IntegralValueRestriction valueRestriction,
+ /*out*/ Input& value,
+ /*optional out*/ Input::size_type* significantBytes)
+{
+ Result rv = ExpectTagAndGetValue(input, tag, value);
+ if (rv != Success) {
+ return rv;
+ }
+ Reader reader(value);
+
+ // There must be at least one byte in the value. (Zero is encoded with a
+ // single 0x00 value byte.)
+ uint8_t firstByte;
+ rv = reader.Read(firstByte);
+ if (rv != Success) {
+ if (rv == Result::ERROR_BAD_DER) {
+ return Result::ERROR_INVALID_INTEGER_ENCODING;
+ }
+
+ return rv;
+ }
+
+ // If there is a byte after an initial 0x00/0xFF, then the initial byte
+ // indicates a positive/negative integer value with its high bit set/unset.
+ bool prefixed = !reader.AtEnd() && (firstByte == 0 || firstByte == 0xff);
+
+ if (prefixed) {
+ uint8_t nextByte;
+ if (reader.Read(nextByte) != Success) {
+ return NotReached("Read of one byte failed but not at end.",
+ Result::FATAL_ERROR_LIBRARY_FAILURE);
+ }
+ if ((firstByte & 0x80) == (nextByte & 0x80)) {
+ return Result::ERROR_INVALID_INTEGER_ENCODING;
+ }
+ }
+
+ switch (valueRestriction) {
+ case IntegralValueRestriction::MustBe0To127:
+ if (value.GetLength() != 1 || (firstByte & 0x80) != 0) {
+ return Result::ERROR_INVALID_INTEGER_ENCODING;
+ }
+ break;
+
+ case IntegralValueRestriction::MustBePositive:
+ if ((value.GetLength() == 1 && firstByte == 0) ||
+ (firstByte & 0x80) != 0) {
+ return Result::ERROR_INVALID_INTEGER_ENCODING;
+ }
+ break;
+
+ case IntegralValueRestriction::NoRestriction:
+ break;
+ }
+
+ if (significantBytes) {
+ *significantBytes = value.GetLength();
+ if (prefixed) {
+ assert(*significantBytes > 1);
+ --*significantBytes;
+ }
+
+ assert(*significantBytes > 0);
+ }
+
+ return Success;
+}
+
+// This parser will only parse values between 0..127. If this range is
+// increased then callers will need to be changed.
+Result
+IntegralValue(Reader& input, uint8_t tag, /*out*/ uint8_t& value)
+{
+ // Conveniently, all the Integers that we actually have to be able to parse
+ // are positive and very small. Consequently, this parser is *much* simpler
+ // than a general Integer parser would need to be.
+ Input valueBytes;
+ Result rv = IntegralBytes(input, tag, IntegralValueRestriction::MustBe0To127,
+ valueBytes, nullptr);
+ if (rv != Success) {
+ return rv;
+ }
+ Reader valueReader(valueBytes);
+ rv = valueReader.Read(value);
+ if (rv != Success) {
+ return NotReached("IntegralBytes already validated the value.", rv);
+ }
+ rv = End(valueReader);
+ assert(rv == Success); // guaranteed by IntegralBytes's range checks.
+ return rv;
+}
+
+} // namespace internal
+
+Result
+OptionalVersion(Reader& input, /*out*/ Version& version)
+{
+ static const uint8_t TAG = CONTEXT_SPECIFIC | CONSTRUCTED | 0;
+ if (!input.Peek(TAG)) {
+ version = Version::v1;
+ return Success;
+ }
+ return Nested(input, TAG, [&version](Reader& value) -> Result {
+ uint8_t integerValue;
+ Result rv = Integer(value, integerValue);
+ if (rv != Success) {
+ return rv;
+ }
+ // XXX(bug 1031093): We shouldn't accept an explicit encoding of v1,
+ // but we do here for compatibility reasons.
+ switch (integerValue) {
+ case static_cast<uint8_t>(Version::v3): version = Version::v3; break;
+ case static_cast<uint8_t>(Version::v2): version = Version::v2; break;
+ case static_cast<uint8_t>(Version::v1): version = Version::v1; break;
+ case static_cast<uint8_t>(Version::v4): version = Version::v4; break;
+ default:
+ return Result::ERROR_BAD_DER;
+ }
+ return Success;
+ });
+}
+
+} } } // namespace mozilla::pkix::der
diff --git a/security/nss/lib/mozpkix/lib/pkixnames.cpp b/security/nss/lib/mozpkix/lib/pkixnames.cpp
new file mode 100644
index 000000000..6f40800d7
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixnames.cpp
@@ -0,0 +1,2050 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2014 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This code implements RFC6125-ish name matching, RFC5280-ish name constraint
+// checking, and related things.
+//
+// In this code, identifiers are classified as either "presented" or
+// "reference" identifiers are defined in
+// http://tools.ietf.org/html/rfc6125#section-1.8. A "presented identifier" is
+// one in the subjectAltName of the certificate, or sometimes within a CN of
+// the certificate's subject. The "reference identifier" is the one we are
+// being asked to match the certificate against. When checking name
+// constraints, the reference identifier is the entire encoded name constraint
+// extension value.
+
+#include <algorithm>
+
+#include "mozpkix/pkixcheck.h"
+#include "mozpkix/pkixutil.h"
+
+namespace mozilla { namespace pkix {
+
+namespace {
+
+// GeneralName ::= CHOICE {
+// otherName [0] OtherName,
+// rfc822Name [1] IA5String,
+// dNSName [2] IA5String,
+// x400Address [3] ORAddress,
+// directoryName [4] Name,
+// ediPartyName [5] EDIPartyName,
+// uniformResourceIdentifier [6] IA5String,
+// iPAddress [7] OCTET STRING,
+// registeredID [8] OBJECT IDENTIFIER }
+enum class GeneralNameType : uint8_t
+{
+ // Note that these values are NOT contiguous. Some values have the
+ // der::CONSTRUCTED bit set while others do not.
+ // (The der::CONSTRUCTED bit is for types where the value is a SEQUENCE.)
+ otherName = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
+ rfc822Name = der::CONTEXT_SPECIFIC | 1,
+ dNSName = der::CONTEXT_SPECIFIC | 2,
+ x400Address = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 3,
+ directoryName = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 4,
+ ediPartyName = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 5,
+ uniformResourceIdentifier = der::CONTEXT_SPECIFIC | 6,
+ iPAddress = der::CONTEXT_SPECIFIC | 7,
+ registeredID = der::CONTEXT_SPECIFIC | 8,
+ // nameConstraints is a pseudo-GeneralName used to signify that a
+ // reference ID is actually the entire name constraint extension.
+ nameConstraints = 0xff
+};
+
+inline Result
+ReadGeneralName(Reader& reader,
+ /*out*/ GeneralNameType& generalNameType,
+ /*out*/ Input& value)
+{
+ uint8_t tag;
+ Result rv = der::ReadTagAndGetValue(reader, tag, value);
+ if (rv != Success) {
+ return rv;
+ }
+ switch (tag) {
+ case static_cast<uint8_t>(GeneralNameType::otherName):
+ generalNameType = GeneralNameType::otherName;
+ break;
+ case static_cast<uint8_t>(GeneralNameType::rfc822Name):
+ generalNameType = GeneralNameType::rfc822Name;
+ break;
+ case static_cast<uint8_t>(GeneralNameType::dNSName):
+ generalNameType = GeneralNameType::dNSName;
+ break;
+ case static_cast<uint8_t>(GeneralNameType::x400Address):
+ generalNameType = GeneralNameType::x400Address;
+ break;
+ case static_cast<uint8_t>(GeneralNameType::directoryName):
+ generalNameType = GeneralNameType::directoryName;
+ break;
+ case static_cast<uint8_t>(GeneralNameType::ediPartyName):
+ generalNameType = GeneralNameType::ediPartyName;
+ break;
+ case static_cast<uint8_t>(GeneralNameType::uniformResourceIdentifier):
+ generalNameType = GeneralNameType::uniformResourceIdentifier;
+ break;
+ case static_cast<uint8_t>(GeneralNameType::iPAddress):
+ generalNameType = GeneralNameType::iPAddress;
+ break;
+ case static_cast<uint8_t>(GeneralNameType::registeredID):
+ generalNameType = GeneralNameType::registeredID;
+ break;
+ default:
+ return Result::ERROR_BAD_DER;
+ }
+ return Success;
+}
+
+enum class MatchResult
+{
+ NoNamesOfGivenType = 0,
+ Mismatch = 1,
+ Match = 2
+};
+
+Result SearchNames(const Input* subjectAltName, Input subject,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ FallBackToSearchWithinSubject fallBackToCommonName,
+ /*out*/ MatchResult& match);
+Result SearchWithinRDN(Reader& rdn,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ FallBackToSearchWithinSubject fallBackToEmailAddress,
+ FallBackToSearchWithinSubject fallBackToCommonName,
+ /*in/out*/ MatchResult& match);
+Result MatchAVA(Input type,
+ uint8_t valueEncodingTag,
+ Input presentedID,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ FallBackToSearchWithinSubject fallBackToEmailAddress,
+ FallBackToSearchWithinSubject fallBackToCommonName,
+ /*in/out*/ MatchResult& match);
+Result ReadAVA(Reader& rdn,
+ /*out*/ Input& type,
+ /*out*/ uint8_t& valueTag,
+ /*out*/ Input& value);
+void MatchSubjectPresentedIDWithReferenceID(GeneralNameType presentedIDType,
+ Input presentedID,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ /*in/out*/ MatchResult& match);
+
+Result MatchPresentedIDWithReferenceID(GeneralNameType presentedIDType,
+ Input presentedID,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ /*in/out*/ MatchResult& matchResult);
+Result CheckPresentedIDConformsToConstraints(GeneralNameType referenceIDType,
+ Input presentedID,
+ Input nameConstraints);
+
+uint8_t LocaleInsensitveToLower(uint8_t a);
+bool StartsWithIDNALabel(Input id);
+
+enum class IDRole
+{
+ ReferenceID = 0,
+ PresentedID = 1,
+ NameConstraint = 2,
+};
+
+enum class AllowWildcards { No = 0, Yes = 1 };
+
+// DNSName constraints implicitly allow subdomain matching when there is no
+// leading dot ("foo.example.com" matches a constraint of "example.com"), but
+// RFC822Name constraints only allow subdomain matching when there is a leading
+// dot ("foo.example.com" does not match "example.com" but does match
+// ".example.com").
+enum class AllowDotlessSubdomainMatches { No = 0, Yes = 1 };
+
+bool IsValidDNSID(Input hostname, IDRole idRole,
+ AllowWildcards allowWildcards);
+
+Result MatchPresentedDNSIDWithReferenceDNSID(
+ Input presentedDNSID,
+ AllowWildcards allowWildcards,
+ AllowDotlessSubdomainMatches allowDotlessSubdomainMatches,
+ IDRole referenceDNSIDRole,
+ Input referenceDNSID,
+ /*out*/ bool& matches);
+
+Result MatchPresentedRFC822NameWithReferenceRFC822Name(
+ Input presentedRFC822Name, IDRole referenceRFC822NameRole,
+ Input referenceRFC822Name, /*out*/ bool& matches);
+
+} // namespace
+
+bool IsValidReferenceDNSID(Input hostname);
+bool IsValidPresentedDNSID(Input hostname);
+bool ParseIPv4Address(Input hostname, /*out*/ uint8_t (&out)[4]);
+bool ParseIPv6Address(Input hostname, /*out*/ uint8_t (&out)[16]);
+
+// This is used by the pkixnames_tests.cpp tests.
+Result
+MatchPresentedDNSIDWithReferenceDNSID(Input presentedDNSID,
+ Input referenceDNSID,
+ /*out*/ bool& matches)
+{
+ return MatchPresentedDNSIDWithReferenceDNSID(
+ presentedDNSID, AllowWildcards::Yes,
+ AllowDotlessSubdomainMatches::Yes, IDRole::ReferenceID,
+ referenceDNSID, matches);
+}
+
+// Verify that the given end-entity cert, which is assumed to have been already
+// validated with BuildCertChain, is valid for the given hostname. hostname is
+// assumed to be a string representation of an IPv4 address, an IPv6 addresss,
+// or a normalized ASCII (possibly punycode) DNS name.
+Result
+CheckCertHostname(Input endEntityCertDER, Input hostname,
+ NameMatchingPolicy& nameMatchingPolicy)
+{
+ BackCert cert(endEntityCertDER, EndEntityOrCA::MustBeEndEntity, nullptr);
+ Result rv = cert.Init();
+ if (rv != Success) {
+ return rv;
+ }
+
+ Time notBefore(Time::uninitialized);
+ rv = ParseValidity(cert.GetValidity(), &notBefore);
+ if (rv != Success) {
+ return rv;
+ }
+ FallBackToSearchWithinSubject fallBackToSearchWithinSubject;
+ rv = nameMatchingPolicy.FallBackToCommonName(notBefore,
+ fallBackToSearchWithinSubject);
+ if (rv != Success) {
+ return rv;
+ }
+
+ const Input* subjectAltName(cert.GetSubjectAltName());
+ Input subject(cert.GetSubject());
+
+ // For backward compatibility with legacy certificates, we may fall back to
+ // searching for a name match in the subject common name for DNS names and
+ // IPv4 addresses. We don't do so for IPv6 addresses because we do not think
+ // there are many certificates that would need such fallback, and because
+ // comparisons of string representations of IPv6 addresses are particularly
+ // error prone due to the syntactic flexibility that IPv6 addresses have.
+ //
+ // IPv4 and IPv6 addresses are represented using the same type of GeneralName
+ // (iPAddress); they are differentiated by the lengths of the values.
+ MatchResult match;
+ uint8_t ipv6[16];
+ uint8_t ipv4[4];
+ if (IsValidReferenceDNSID(hostname)) {
+ rv = SearchNames(subjectAltName, subject, GeneralNameType::dNSName,
+ hostname, fallBackToSearchWithinSubject, match);
+ } else if (ParseIPv6Address(hostname, ipv6)) {
+ rv = SearchNames(subjectAltName, subject, GeneralNameType::iPAddress,
+ Input(ipv6), FallBackToSearchWithinSubject::No, match);
+ } else if (ParseIPv4Address(hostname, ipv4)) {
+ rv = SearchNames(subjectAltName, subject, GeneralNameType::iPAddress,
+ Input(ipv4), fallBackToSearchWithinSubject, match);
+ } else {
+ return Result::ERROR_BAD_CERT_DOMAIN;
+ }
+ if (rv != Success) {
+ return rv;
+ }
+ switch (match) {
+ case MatchResult::NoNamesOfGivenType: // fall through
+ case MatchResult::Mismatch:
+ return Result::ERROR_BAD_CERT_DOMAIN;
+ case MatchResult::Match:
+ return Success;
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+}
+
+// 4.2.1.10. Name Constraints
+Result
+CheckNameConstraints(Input encodedNameConstraints,
+ const BackCert& firstChild,
+ KeyPurposeId requiredEKUIfPresent)
+{
+ for (const BackCert* child = &firstChild; child; child = child->childCert) {
+ FallBackToSearchWithinSubject fallBackToCommonName
+ = (child->endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
+ requiredEKUIfPresent == KeyPurposeId::id_kp_serverAuth)
+ ? FallBackToSearchWithinSubject::Yes
+ : FallBackToSearchWithinSubject::No;
+
+ MatchResult match;
+ Result rv = SearchNames(child->GetSubjectAltName(), child->GetSubject(),
+ GeneralNameType::nameConstraints,
+ encodedNameConstraints, fallBackToCommonName,
+ match);
+ if (rv != Success) {
+ return rv;
+ }
+ switch (match) {
+ case MatchResult::Match: // fall through
+ case MatchResult::NoNamesOfGivenType:
+ break;
+ case MatchResult::Mismatch:
+ return Result::ERROR_CERT_NOT_IN_NAME_SPACE;
+ }
+ }
+
+ return Success;
+}
+
+namespace {
+
+// SearchNames is used by CheckCertHostname and CheckNameConstraints.
+//
+// When called during name constraint checking, referenceIDType is
+// GeneralNameType::nameConstraints and referenceID is the entire encoded name
+// constraints extension value.
+//
+// The main benefit of using the exact same code paths for both is that we
+// ensure consistency between name validation and name constraint enforcement
+// regarding thing like "Which CN attributes should be considered as potential
+// CN-IDs" and "Which character sets are acceptable for CN-IDs?" If the name
+// matching and the name constraint enforcement logic were out of sync on these
+// issues (e.g. if name matching were to consider all subject CN attributes,
+// but name constraints were only enforced on the most specific subject CN),
+// trivial name constraint bypasses could result.
+
+Result
+SearchNames(/*optional*/ const Input* subjectAltName,
+ Input subject,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ FallBackToSearchWithinSubject fallBackToCommonName,
+ /*out*/ MatchResult& match)
+{
+ Result rv;
+
+ match = MatchResult::NoNamesOfGivenType;
+
+ // RFC 6125 says "A client MUST NOT seek a match for a reference identifier
+ // of CN-ID if the presented identifiers include a DNS-ID, SRV-ID, URI-ID, or
+ // any application-specific identifier types supported by the client."
+ // Accordingly, we only consider CN-IDs if there are no DNS-IDs in the
+ // subjectAltName.
+ //
+ // RFC 6125 says that IP addresses are out of scope, but for backward
+ // compatibility we accept them, by considering IP addresses to be an
+ // "application-specific identifier type supported by the client."
+ //
+ // TODO(bug XXXXXXX): Consider strengthening this check to "A client MUST NOT
+ // seek a match for a reference identifier of CN-ID if the certificate
+ // contains a subjectAltName extension."
+ //
+ // TODO(bug XXXXXXX): Consider dropping support for IP addresses as
+ // identifiers completely.
+
+ if (subjectAltName) {
+ Reader altNames;
+ rv = der::ExpectTagAndGetValueAtEnd(*subjectAltName, der::SEQUENCE,
+ altNames);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // According to RFC 5280, "If the subjectAltName extension is present, the
+ // sequence MUST contain at least one entry." For compatibility reasons, we
+ // do not enforce this. See bug 1143085.
+ while (!altNames.AtEnd()) {
+ GeneralNameType presentedIDType;
+ Input presentedID;
+ rv = ReadGeneralName(altNames, presentedIDType, presentedID);
+ if (rv != Success) {
+ return rv;
+ }
+
+ rv = MatchPresentedIDWithReferenceID(presentedIDType, presentedID,
+ referenceIDType, referenceID,
+ match);
+ if (rv != Success) {
+ return rv;
+ }
+ if (referenceIDType != GeneralNameType::nameConstraints &&
+ match == MatchResult::Match) {
+ return Success;
+ }
+ if (presentedIDType == GeneralNameType::dNSName ||
+ presentedIDType == GeneralNameType::iPAddress) {
+ fallBackToCommonName = FallBackToSearchWithinSubject::No;
+ }
+ }
+ }
+
+ if (referenceIDType == GeneralNameType::nameConstraints) {
+ rv = CheckPresentedIDConformsToConstraints(GeneralNameType::directoryName,
+ subject, referenceID);
+ if (rv != Success) {
+ return rv;
+ }
+ }
+
+ FallBackToSearchWithinSubject fallBackToEmailAddress;
+ if (!subjectAltName &&
+ (referenceIDType == GeneralNameType::rfc822Name ||
+ referenceIDType == GeneralNameType::nameConstraints)) {
+ fallBackToEmailAddress = FallBackToSearchWithinSubject::Yes;
+ } else {
+ fallBackToEmailAddress = FallBackToSearchWithinSubject::No;
+ }
+
+ // Short-circuit the parsing of the subject name if we're not going to match
+ // any names in it
+ if (fallBackToEmailAddress == FallBackToSearchWithinSubject::No &&
+ fallBackToCommonName == FallBackToSearchWithinSubject::No) {
+ return Success;
+ }
+
+ // Attempt to match the reference ID against the CN-ID, which we consider to
+ // be the most-specific CN AVA in the subject field.
+ //
+ // https://tools.ietf.org/html/rfc6125#section-2.3.1 says:
+ //
+ // To reduce confusion, in this specification we avoid such terms and
+ // instead use the terms provided under Section 1.8; in particular, we
+ // do not use the term "(most specific) Common Name field in the subject
+ // field" from [HTTP-TLS] and instead state that a CN-ID is a Relative
+ // Distinguished Name (RDN) in the certificate subject containing one
+ // and only one attribute-type-and-value pair of type Common Name (thus
+ // removing the possibility that an RDN might contain multiple AVAs
+ // (Attribute Value Assertions) of type CN, one of which could be
+ // considered "most specific").
+ //
+ // https://tools.ietf.org/html/rfc6125#section-7.4 says:
+ //
+ // [...] Although it would be preferable to
+ // forbid multiple CN-IDs entirely, there are several reasons at this
+ // time why this specification states that they SHOULD NOT (instead of
+ // MUST NOT) be included [...]
+ //
+ // Consequently, it is unclear what to do when there are multiple CNs in the
+ // subject, regardless of whether there "SHOULD NOT" be.
+ //
+ // NSS's CERT_VerifyCertName mostly follows RFC2818 in this instance, which
+ // says:
+ //
+ // If a subjectAltName extension of type dNSName is present, that MUST
+ // be used as the identity. Otherwise, the (most specific) Common Name
+ // field in the Subject field of the certificate MUST be used.
+ //
+ // [...]
+ //
+ // In some cases, the URI is specified as an IP address rather than a
+ // hostname. In this case, the iPAddress subjectAltName must be present
+ // in the certificate and must exactly match the IP in the URI.
+ //
+ // (The main difference from RFC2818 is that NSS's CERT_VerifyCertName also
+ // matches IP addresses in the most-specific CN.)
+ //
+ // NSS's CERT_VerifyCertName finds the most specific CN via
+ // CERT_GetCommoName, which uses CERT_GetLastNameElement. Note that many
+ // NSS-based applications, including Gecko, also use CERT_GetCommonName. It
+ // is likely that other, non-NSS-based, applications also expect only the
+ // most specific CN to be matched against the reference ID.
+ //
+ // "A Layman's Guide to a Subset of ASN.1, BER, and DER" and other sources
+ // agree that an RDNSequence is ordered from most significant (least
+ // specific) to least significant (most specific), as do other references.
+ //
+ // However, Chromium appears to use the least-specific (first) CN instead of
+ // the most-specific; see https://crbug.com/366957. Also, MSIE and some other
+ // popular implementations apparently attempt to match the reference ID
+ // against any/all CNs in the subject. Since we're trying to phase out the
+ // use of CN-IDs, we intentionally avoid trying to match MSIE's more liberal
+ // behavior.
+
+ // Name ::= CHOICE { -- only one possibility for now --
+ // rdnSequence RDNSequence }
+ //
+ // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ //
+ // RelativeDistinguishedName ::=
+ // SET SIZE (1..MAX) OF AttributeTypeAndValue
+ Reader subjectReader(subject);
+ return der::NestedOf(subjectReader, der::SEQUENCE, der::SET,
+ der::EmptyAllowed::Yes, [&](Reader& r) {
+ return SearchWithinRDN(r, referenceIDType, referenceID,
+ fallBackToEmailAddress, fallBackToCommonName, match);
+ });
+}
+
+// RelativeDistinguishedName ::=
+// SET SIZE (1..MAX) OF AttributeTypeAndValue
+//
+// AttributeTypeAndValue ::= SEQUENCE {
+// type AttributeType,
+// value AttributeValue }
+Result
+SearchWithinRDN(Reader& rdn,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ FallBackToSearchWithinSubject fallBackToEmailAddress,
+ FallBackToSearchWithinSubject fallBackToCommonName,
+ /*in/out*/ MatchResult& match)
+{
+ do {
+ Input type;
+ uint8_t valueTag;
+ Input value;
+ Result rv = ReadAVA(rdn, type, valueTag, value);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = MatchAVA(type, valueTag, value, referenceIDType, referenceID,
+ fallBackToEmailAddress, fallBackToCommonName, match);
+ if (rv != Success) {
+ return rv;
+ }
+ } while (!rdn.AtEnd());
+
+ return Success;
+}
+
+// AttributeTypeAndValue ::= SEQUENCE {
+// type AttributeType,
+// value AttributeValue }
+//
+// AttributeType ::= OBJECT IDENTIFIER
+//
+// AttributeValue ::= ANY -- DEFINED BY AttributeType
+//
+// DirectoryString ::= CHOICE {
+// teletexString TeletexString (SIZE (1..MAX)),
+// printableString PrintableString (SIZE (1..MAX)),
+// universalString UniversalString (SIZE (1..MAX)),
+// utf8String UTF8String (SIZE (1..MAX)),
+// bmpString BMPString (SIZE (1..MAX)) }
+Result
+MatchAVA(Input type, uint8_t valueEncodingTag, Input presentedID,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ FallBackToSearchWithinSubject fallBackToEmailAddress,
+ FallBackToSearchWithinSubject fallBackToCommonName,
+ /*in/out*/ MatchResult& match)
+{
+ // Try to match the CN as a DNSName or an IPAddress.
+ //
+ // id-at-commonName AttributeType ::= { id-at 3 }
+ //
+ // -- Naming attributes of type X520CommonName:
+ // -- X520CommonName ::= DirectoryName (SIZE (1..ub-common-name))
+ // --
+ // -- Expanded to avoid parameterized type:
+ // X520CommonName ::= CHOICE {
+ // teletexString TeletexString (SIZE (1..ub-common-name)),
+ // printableString PrintableString (SIZE (1..ub-common-name)),
+ // universalString UniversalString (SIZE (1..ub-common-name)),
+ // utf8String UTF8String (SIZE (1..ub-common-name)),
+ // bmpString BMPString (SIZE (1..ub-common-name)) }
+ //
+ // python DottedOIDToCode.py id-at-commonName 2.5.4.3
+ static const uint8_t id_at_commonName[] = {
+ 0x55, 0x04, 0x03
+ };
+ if (fallBackToCommonName == FallBackToSearchWithinSubject::Yes &&
+ InputsAreEqual(type, Input(id_at_commonName))) {
+ // We might have previously found a match. Now that we've found another CN,
+ // we no longer consider that previous match to be a match, so "forget" about
+ // it.
+ match = MatchResult::NoNamesOfGivenType;
+
+ // PrintableString is a subset of ASCII that contains all the characters
+ // allowed in CN-IDs except '*'. Although '*' is illegal, there are many
+ // real-world certificates that are encoded this way, so we accept it.
+ //
+ // In the case of UTF8String, we rely on the fact that in UTF-8 the octets in
+ // a multi-byte encoding of a code point are always distinct from ASCII. Any
+ // non-ASCII byte in a UTF-8 string causes us to fail to match. We make no
+ // attempt to detect or report malformed UTF-8 (e.g. incomplete or overlong
+ // encodings of code points, or encodings of invalid code points).
+ //
+ // TeletexString is supported as long as it does not contain any escape
+ // sequences, which are not supported. We'll reject escape sequences as
+ // invalid characters in names, which means we only accept strings that are
+ // in the default character set, which is a superset of ASCII. Note that NSS
+ // actually treats TeletexString as ISO-8859-1. Many certificates that have
+ // wildcard CN-IDs (e.g. "*.example.com") use TeletexString because
+ // PrintableString is defined to not allow '*' and because, at one point in
+ // history, UTF8String was too new to use for compatibility reasons.
+ //
+ // UniversalString and BMPString are also deprecated, and they are a little
+ // harder to support because they are not single-byte ASCII superset
+ // encodings, so we don't bother.
+ if (valueEncodingTag != der::PrintableString &&
+ valueEncodingTag != der::UTF8String &&
+ valueEncodingTag != der::TeletexString) {
+ return Success;
+ }
+
+ if (IsValidPresentedDNSID(presentedID)) {
+ MatchSubjectPresentedIDWithReferenceID(GeneralNameType::dNSName,
+ presentedID, referenceIDType,
+ referenceID, match);
+ } else {
+ // We don't match CN-IDs for IPv6 addresses.
+ // MatchSubjectPresentedIDWithReferenceID ensures that it won't match an
+ // IPv4 address with an IPv6 address, so we don't need to check that
+ // referenceID is an IPv4 address here.
+ uint8_t ipv4[4];
+ if (ParseIPv4Address(presentedID, ipv4)) {
+ MatchSubjectPresentedIDWithReferenceID(GeneralNameType::iPAddress,
+ Input(ipv4), referenceIDType,
+ referenceID, match);
+ }
+ }
+
+ // Regardless of whether there was a match, we keep going in case we find
+ // another CN later. If we do find another one, then this match/mismatch
+ // will be ignored, because we only care about the most specific CN.
+
+ return Success;
+ }
+
+ // Match an email address against an emailAddress attribute in the
+ // subject.
+ //
+ // id-emailAddress AttributeType ::= { pkcs-9 1 }
+ //
+ // EmailAddress ::= IA5String (SIZE (1..ub-emailaddress-length))
+ //
+ // python DottedOIDToCode.py id-emailAddress 1.2.840.113549.1.9.1
+ static const uint8_t id_emailAddress[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01
+ };
+ if (fallBackToEmailAddress == FallBackToSearchWithinSubject::Yes &&
+ InputsAreEqual(type, Input(id_emailAddress))) {
+ if (referenceIDType == GeneralNameType::rfc822Name &&
+ match == MatchResult::Match) {
+ // We already found a match; we don't need to match another one
+ return Success;
+ }
+ if (valueEncodingTag != der::IA5String) {
+ return Result::ERROR_BAD_DER;
+ }
+ return MatchPresentedIDWithReferenceID(GeneralNameType::rfc822Name,
+ presentedID, referenceIDType,
+ referenceID, match);
+ }
+
+ return Success;
+}
+
+void
+MatchSubjectPresentedIDWithReferenceID(GeneralNameType presentedIDType,
+ Input presentedID,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ /*in/out*/ MatchResult& match)
+{
+ Result rv = MatchPresentedIDWithReferenceID(presentedIDType, presentedID,
+ referenceIDType, referenceID,
+ match);
+ if (rv != Success) {
+ match = MatchResult::Mismatch;
+ }
+}
+
+Result
+MatchPresentedIDWithReferenceID(GeneralNameType presentedIDType,
+ Input presentedID,
+ GeneralNameType referenceIDType,
+ Input referenceID,
+ /*out*/ MatchResult& matchResult)
+{
+ if (referenceIDType == GeneralNameType::nameConstraints) {
+ // matchResult is irrelevant when checking name constraints; only the
+ // pass/fail result of CheckPresentedIDConformsToConstraints matters.
+ return CheckPresentedIDConformsToConstraints(presentedIDType, presentedID,
+ referenceID);
+ }
+
+ if (presentedIDType != referenceIDType) {
+ matchResult = MatchResult::Mismatch;
+ return Success;
+ }
+
+ Result rv;
+ bool foundMatch;
+
+ switch (referenceIDType) {
+ case GeneralNameType::dNSName:
+ rv = MatchPresentedDNSIDWithReferenceDNSID(
+ presentedID, AllowWildcards::Yes,
+ AllowDotlessSubdomainMatches::Yes, IDRole::ReferenceID,
+ referenceID, foundMatch);
+ break;
+
+ case GeneralNameType::iPAddress:
+ foundMatch = InputsAreEqual(presentedID, referenceID);
+ rv = Success;
+ break;
+
+ case GeneralNameType::rfc822Name:
+ rv = MatchPresentedRFC822NameWithReferenceRFC822Name(
+ presentedID, IDRole::ReferenceID, referenceID, foundMatch);
+ break;
+
+ case GeneralNameType::directoryName:
+ // TODO: At some point, we may add APIs for matching DirectoryNames.
+ // fall through
+
+ case GeneralNameType::otherName: // fall through
+ case GeneralNameType::x400Address: // fall through
+ case GeneralNameType::ediPartyName: // fall through
+ case GeneralNameType::uniformResourceIdentifier: // fall through
+ case GeneralNameType::registeredID: // fall through
+ case GeneralNameType::nameConstraints:
+ return NotReached("unexpected nameType for SearchType::Match",
+ Result::FATAL_ERROR_INVALID_ARGS);
+
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+
+ if (rv != Success) {
+ return rv;
+ }
+ matchResult = foundMatch ? MatchResult::Match : MatchResult::Mismatch;
+ return Success;
+}
+
+enum class NameConstraintsSubtrees : uint8_t
+{
+ permittedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
+ excludedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1
+};
+
+Result CheckPresentedIDConformsToNameConstraintsSubtrees(
+ GeneralNameType presentedIDType,
+ Input presentedID,
+ Reader& nameConstraints,
+ NameConstraintsSubtrees subtreesType);
+Result MatchPresentedIPAddressWithConstraint(Input presentedID,
+ Input iPAddressConstraint,
+ /*out*/ bool& foundMatch);
+Result MatchPresentedDirectoryNameWithConstraint(
+ NameConstraintsSubtrees subtreesType, Input presentedID,
+ Input directoryNameConstraint, /*out*/ bool& matches);
+
+Result
+CheckPresentedIDConformsToConstraints(
+ GeneralNameType presentedIDType,
+ Input presentedID,
+ Input encodedNameConstraints)
+{
+ // NameConstraints ::= SEQUENCE {
+ // permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ // excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ Reader nameConstraints;
+ Result rv = der::ExpectTagAndGetValueAtEnd(encodedNameConstraints,
+ der::SEQUENCE, nameConstraints);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // RFC 5280 says "Conforming CAs MUST NOT issue certificates where name
+ // constraints is an empty sequence. That is, either the permittedSubtrees
+ // field or the excludedSubtrees MUST be present."
+ if (nameConstraints.AtEnd()) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ rv = CheckPresentedIDConformsToNameConstraintsSubtrees(
+ presentedIDType, presentedID, nameConstraints,
+ NameConstraintsSubtrees::permittedSubtrees);
+ if (rv != Success) {
+ return rv;
+ }
+
+ rv = CheckPresentedIDConformsToNameConstraintsSubtrees(
+ presentedIDType, presentedID, nameConstraints,
+ NameConstraintsSubtrees::excludedSubtrees);
+ if (rv != Success) {
+ return rv;
+ }
+
+ return der::End(nameConstraints);
+}
+
+Result
+CheckPresentedIDConformsToNameConstraintsSubtrees(
+ GeneralNameType presentedIDType,
+ Input presentedID,
+ Reader& nameConstraints,
+ NameConstraintsSubtrees subtreesType)
+{
+ if (!nameConstraints.Peek(static_cast<uint8_t>(subtreesType))) {
+ return Success;
+ }
+
+ Reader subtrees;
+ Result rv = der::ExpectTagAndGetValue(nameConstraints,
+ static_cast<uint8_t>(subtreesType),
+ subtrees);
+ if (rv != Success) {
+ return rv;
+ }
+
+ bool hasPermittedSubtreesMatch = false;
+ bool hasPermittedSubtreesMismatch = false;
+
+ // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ //
+ // do { ... } while(...) because subtrees isn't allowed to be empty.
+ do {
+ // GeneralSubtree ::= SEQUENCE {
+ // base GeneralName,
+ // minimum [0] BaseDistance DEFAULT 0,
+ // maximum [1] BaseDistance OPTIONAL }
+ Reader subtree;
+ rv = ExpectTagAndGetValue(subtrees, der::SEQUENCE, subtree);
+ if (rv != Success) {
+ return rv;
+ }
+ GeneralNameType nameConstraintType;
+ Input base;
+ rv = ReadGeneralName(subtree, nameConstraintType, base);
+ if (rv != Success) {
+ return rv;
+ }
+ // http://tools.ietf.org/html/rfc5280#section-4.2.1.10: "Within this
+ // profile, the minimum and maximum fields are not used with any name
+ // forms, thus, the minimum MUST be zero, and maximum MUST be absent."
+ //
+ // Since the default value isn't allowed to be encoded according to the DER
+ // encoding rules for DEFAULT, this is equivalent to saying that neither
+ // minimum or maximum must be encoded.
+ rv = der::End(subtree);
+ if (rv != Success) {
+ return rv;
+ }
+
+ if (presentedIDType == nameConstraintType) {
+ bool matches;
+
+ switch (presentedIDType) {
+ case GeneralNameType::dNSName:
+ rv = MatchPresentedDNSIDWithReferenceDNSID(
+ presentedID, AllowWildcards::Yes,
+ AllowDotlessSubdomainMatches::Yes, IDRole::NameConstraint,
+ base, matches);
+ if (rv != Success) {
+ return rv;
+ }
+ break;
+
+ case GeneralNameType::iPAddress:
+ rv = MatchPresentedIPAddressWithConstraint(presentedID, base,
+ matches);
+ if (rv != Success) {
+ return rv;
+ }
+ break;
+
+ case GeneralNameType::directoryName:
+ rv = MatchPresentedDirectoryNameWithConstraint(subtreesType,
+ presentedID, base,
+ matches);
+ if (rv != Success) {
+ return rv;
+ }
+ break;
+
+ case GeneralNameType::rfc822Name:
+ rv = MatchPresentedRFC822NameWithReferenceRFC822Name(
+ presentedID, IDRole::NameConstraint, base, matches);
+ if (rv != Success) {
+ return rv;
+ }
+ break;
+
+ // RFC 5280 says "Conforming CAs [...] SHOULD NOT impose name
+ // constraints on the x400Address, ediPartyName, or registeredID
+ // name forms. It also says "Applications conforming to this profile
+ // [...] SHOULD be able to process name constraints that are imposed
+ // on [...] uniformResourceIdentifier [...]", but we don't bother.
+ //
+ // TODO: Ask to have spec updated to say ""Conforming CAs [...] SHOULD
+ // NOT impose name constraints on the otherName, x400Address,
+ // ediPartyName, uniformResourceIdentifier, or registeredID name
+ // forms."
+ case GeneralNameType::otherName: // fall through
+ case GeneralNameType::x400Address: // fall through
+ case GeneralNameType::ediPartyName: // fall through
+ case GeneralNameType::uniformResourceIdentifier: // fall through
+ case GeneralNameType::registeredID: // fall through
+ return Result::ERROR_CERT_NOT_IN_NAME_SPACE;
+
+ case GeneralNameType::nameConstraints:
+ return NotReached("invalid presentedIDType",
+ Result::FATAL_ERROR_LIBRARY_FAILURE);
+
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+
+ switch (subtreesType) {
+ case NameConstraintsSubtrees::permittedSubtrees:
+ if (matches) {
+ hasPermittedSubtreesMatch = true;
+ } else {
+ hasPermittedSubtreesMismatch = true;
+ }
+ break;
+ case NameConstraintsSubtrees::excludedSubtrees:
+ if (matches) {
+ return Result::ERROR_CERT_NOT_IN_NAME_SPACE;
+ }
+ break;
+ }
+ }
+ } while (!subtrees.AtEnd());
+
+ if (hasPermittedSubtreesMismatch && !hasPermittedSubtreesMatch) {
+ // If there was any entry of the given type in permittedSubtrees, then it
+ // required that at least one of them must match. Since none of them did,
+ // we have a failure.
+ return Result::ERROR_CERT_NOT_IN_NAME_SPACE;
+ }
+
+ return Success;
+}
+
+// We do not distinguish between a syntactically-invalid presentedDNSID and one
+// that is syntactically valid but does not match referenceDNSID; in both
+// cases, the result is false.
+//
+// We assume that both presentedDNSID and referenceDNSID are encoded in such a
+// way that US-ASCII (7-bit) characters are encoded in one byte and no encoding
+// of a non-US-ASCII character contains a code point in the range 0-127. For
+// example, UTF-8 is OK but UTF-16 is not.
+//
+// RFC6125 says that a wildcard label may be of the form <x>*<y>.<DNSID>, where
+// <x> and/or <y> may be empty. However, NSS requires <y> to be empty, and we
+// follow NSS's stricter policy by accepting wildcards only of the form
+// <x>*.<DNSID>, where <x> may be empty.
+//
+// An relative presented DNS ID matches both an absolute reference ID and a
+// relative reference ID. Absolute presented DNS IDs are not supported:
+//
+// Presented ID Reference ID Result
+// -------------------------------------
+// example.com example.com Match
+// example.com. example.com Mismatch
+// example.com example.com. Match
+// example.com. example.com. Mismatch
+//
+// There are more subtleties documented inline in the code.
+//
+// Name constraints ///////////////////////////////////////////////////////////
+//
+// This is all RFC 5280 has to say about DNSName constraints:
+//
+// DNS name restrictions are expressed as host.example.com. Any DNS
+// name that can be constructed by simply adding zero or more labels to
+// the left-hand side of the name satisfies the name constraint. For
+// example, www.host.example.com would satisfy the constraint but
+// host1.example.com would not.
+//
+// This lack of specificity has lead to a lot of uncertainty regarding
+// subdomain matching. In particular, the following questions have been
+// raised and answered:
+//
+// Q: Does a presented identifier equal (case insensitive) to the name
+// constraint match the constraint? For example, does the presented
+// ID "host.example.com" match a "host.example.com" constraint?
+// A: Yes. RFC5280 says "by simply adding zero or more labels" and this
+// is the case of adding zero labels.
+//
+// Q: When the name constraint does not start with ".", do subdomain
+// presented identifiers match it? For example, does the presented
+// ID "www.host.example.com" match a "host.example.com" constraint?
+// A: Yes. RFC5280 says "by simply adding zero or more labels" and this
+// is the case of adding more than zero labels. The example is the
+// one from RFC 5280.
+//
+// Q: When the name constraint does not start with ".", does a
+// non-subdomain prefix match it? For example, does "bigfoo.bar.com"
+// match "foo.bar.com"? [4]
+// A: No. We interpret RFC 5280's language of "adding zero or more labels"
+// to mean that whole labels must be prefixed.
+//
+// (Note that the above three scenarios are the same as the RFC 6265
+// domain matching rules [0].)
+//
+// Q: Is a name constraint that starts with "." valid, and if so, what
+// semantics does it have? For example, does a presented ID of
+// "www.example.com" match a constraint of ".example.com"? Does a
+// presented ID of "example.com" match a constraint of ".example.com"?
+// A: This implementation, NSS[1], and SChannel[2] all support a
+// leading ".", but OpenSSL[3] does not yet. Amongst the
+// implementations that support it, a leading "." is legal and means
+// the same thing as when the "." is omitted, EXCEPT that a
+// presented identifier equal (case insensitive) to the name
+// constraint is not matched; i.e. presented DNSName identifiers
+// must be subdomains. Some CAs in Mozilla's CA program (e.g. HARICA)
+// have name constraints with the leading "." in their root
+// certificates. The name constraints imposed on DCISS by Mozilla also
+// have the it, so supporting this is a requirement for backward
+// compatibility, even if it is not yet standardized. So, for example, a
+// presented ID of "www.example.com" matches a constraint of
+// ".example.com" but a presented ID of "example.com" does not.
+//
+// Q: Is there a way to prevent subdomain matches?
+// A: Yes.
+//
+// Some people have proposed that dNSName constraints that do not
+// start with a "." should be restricted to exact (case insensitive)
+// matches. However, such a change of semantics from what RFC5280
+// specifies would be a non-backward-compatible change in the case of
+// permittedSubtrees constraints, and it would be a security issue for
+// excludedSubtrees constraints.
+//
+// However, it can be done with a combination of permittedSubtrees and
+// excludedSubtrees, e.g. "example.com" in permittedSubtrees and
+// ".example.com" in excudedSubtrees.
+//
+// Q: Are name constraints allowed to be specified as absolute names?
+// For example, does a presented ID of "example.com" match a name
+// constraint of "example.com." and vice versa.
+// A: Absolute names are not supported as presented IDs or name
+// constraints. Only reference IDs may be absolute.
+//
+// Q: Is "" a valid DNSName constraints? If so, what does it mean?
+// A: Yes. Any valid presented DNSName can be formed "by simply adding zero
+// or more labels to the left-hand side" of "". In particular, an
+// excludedSubtrees DNSName constraint of "" forbids all DNSNames.
+//
+// Q: Is "." a valid DNSName constraints? If so, what does it mean?
+// A: No, because absolute names are not allowed (see above).
+//
+// [0] RFC 6265 (Cookies) Domain Matching rules:
+// http://tools.ietf.org/html/rfc6265#section-5.1.3
+// [1] NSS source code:
+// https://mxr.mozilla.org/nss/source/lib/certdb/genname.c?rev=2a7348f013cb#1209
+// [2] Description of SChannel's behavior from Microsoft:
+// http://www.imc.org/ietf-pkix/mail-archive/msg04668.html
+// [3] Proposal to add such support to OpenSSL:
+// http://www.mail-archive.com/openssl-dev%40openssl.org/msg36204.html
+// https://rt.openssl.org/Ticket/Display.html?id=3562
+// [4] Feedback on the lack of clarify in the definition that never got
+// incorporated into the spec:
+// https://www.ietf.org/mail-archive/web/pkix/current/msg21192.html
+Result
+MatchPresentedDNSIDWithReferenceDNSID(
+ Input presentedDNSID,
+ AllowWildcards allowWildcards,
+ AllowDotlessSubdomainMatches allowDotlessSubdomainMatches,
+ IDRole referenceDNSIDRole,
+ Input referenceDNSID,
+ /*out*/ bool& matches)
+{
+ if (!IsValidDNSID(presentedDNSID, IDRole::PresentedID, allowWildcards)) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ if (!IsValidDNSID(referenceDNSID, referenceDNSIDRole, AllowWildcards::No)) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ Reader presented(presentedDNSID);
+ Reader reference(referenceDNSID);
+
+ switch (referenceDNSIDRole)
+ {
+ case IDRole::ReferenceID:
+ break;
+
+ case IDRole::NameConstraint:
+ {
+ if (presentedDNSID.GetLength() > referenceDNSID.GetLength()) {
+ if (referenceDNSID.GetLength() == 0) {
+ // An empty constraint matches everything.
+ matches = true;
+ return Success;
+ }
+ // If the reference ID starts with a dot then skip the prefix of
+ // of the presented ID and start the comparison at the position of that
+ // dot. Examples:
+ //
+ // Matches Doesn't Match
+ // -----------------------------------------------------------
+ // original presented ID: www.example.com badexample.com
+ // skipped: www ba
+ // presented ID w/o prefix: .example.com dexample.com
+ // reference ID: .example.com .example.com
+ //
+ // If the reference ID does not start with a dot then we skip the
+ // prefix of the presented ID but also verify that the prefix ends with
+ // a dot. Examples:
+ //
+ // Matches Doesn't Match
+ // -----------------------------------------------------------
+ // original presented ID: www.example.com badexample.com
+ // skipped: www ba
+ // must be '.': . d
+ // presented ID w/o prefix: example.com example.com
+ // reference ID: example.com example.com
+ //
+ if (reference.Peek('.')) {
+ if (presented.Skip(static_cast<Input::size_type>(
+ presentedDNSID.GetLength() -
+ referenceDNSID.GetLength())) != Success) {
+ return NotReached("skipping subdomain failed",
+ Result::FATAL_ERROR_LIBRARY_FAILURE);
+ }
+ } else if (allowDotlessSubdomainMatches ==
+ AllowDotlessSubdomainMatches::Yes) {
+ if (presented.Skip(static_cast<Input::size_type>(
+ presentedDNSID.GetLength() -
+ referenceDNSID.GetLength() - 1)) != Success) {
+ return NotReached("skipping subdomains failed",
+ Result::FATAL_ERROR_LIBRARY_FAILURE);
+ }
+ uint8_t b;
+ if (presented.Read(b) != Success) {
+ return NotReached("reading from presentedDNSID failed",
+ Result::FATAL_ERROR_LIBRARY_FAILURE);
+ }
+ if (b != '.') {
+ matches = false;
+ return Success;
+ }
+ }
+ }
+ break;
+ }
+
+ case IDRole::PresentedID: // fall through
+ return NotReached("IDRole::PresentedID is not a valid referenceDNSIDRole",
+ Result::FATAL_ERROR_INVALID_ARGS);
+ }
+
+ // We only allow wildcard labels that consist only of '*'.
+ if (presented.Peek('*')) {
+ if (presented.Skip(1) != Success) {
+ return NotReached("Skipping '*' failed",
+ Result::FATAL_ERROR_LIBRARY_FAILURE);
+ }
+ do {
+ // This will happen if reference is a single, relative label
+ if (reference.AtEnd()) {
+ matches = false;
+ return Success;
+ }
+ uint8_t referenceByte;
+ if (reference.Read(referenceByte) != Success) {
+ return NotReached("invalid reference ID",
+ Result::FATAL_ERROR_INVALID_ARGS);
+ }
+ } while (!reference.Peek('.'));
+ }
+
+ for (;;) {
+ uint8_t presentedByte;
+ if (presented.Read(presentedByte) != Success) {
+ matches = false;
+ return Success;
+ }
+ uint8_t referenceByte;
+ if (reference.Read(referenceByte) != Success) {
+ matches = false;
+ return Success;
+ }
+ if (LocaleInsensitveToLower(presentedByte) !=
+ LocaleInsensitveToLower(referenceByte)) {
+ matches = false;
+ return Success;
+ }
+ if (presented.AtEnd()) {
+ // Don't allow presented IDs to be absolute.
+ if (presentedByte == '.') {
+ return Result::ERROR_BAD_DER;
+ }
+ break;
+ }
+ }
+
+ // Allow a relative presented DNS ID to match an absolute reference DNS ID,
+ // unless we're matching a name constraint.
+ if (!reference.AtEnd()) {
+ if (referenceDNSIDRole != IDRole::NameConstraint) {
+ uint8_t referenceByte;
+ if (reference.Read(referenceByte) != Success) {
+ return NotReached("read failed but not at end",
+ Result::FATAL_ERROR_LIBRARY_FAILURE);
+ }
+ if (referenceByte != '.') {
+ matches = false;
+ return Success;
+ }
+ }
+ if (!reference.AtEnd()) {
+ matches = false;
+ return Success;
+ }
+ }
+
+ matches = true;
+ return Success;
+}
+
+// https://tools.ietf.org/html/rfc5280#section-4.2.1.10 says:
+//
+// For IPv4 addresses, the iPAddress field of GeneralName MUST contain
+// eight (8) octets, encoded in the style of RFC 4632 (CIDR) to represent
+// an address range [RFC4632]. For IPv6 addresses, the iPAddress field
+// MUST contain 32 octets similarly encoded. For example, a name
+// constraint for "class C" subnet 192.0.2.0 is represented as the
+// octets C0 00 02 00 FF FF FF 00, representing the CIDR notation
+// 192.0.2.0/24 (mask 255.255.255.0).
+Result
+MatchPresentedIPAddressWithConstraint(Input presentedID,
+ Input iPAddressConstraint,
+ /*out*/ bool& foundMatch)
+{
+ if (presentedID.GetLength() != 4 && presentedID.GetLength() != 16) {
+ return Result::ERROR_BAD_DER;
+ }
+ if (iPAddressConstraint.GetLength() != 8 &&
+ iPAddressConstraint.GetLength() != 32) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ // an IPv4 address never matches an IPv6 constraint, and vice versa.
+ if (presentedID.GetLength() * 2 != iPAddressConstraint.GetLength()) {
+ foundMatch = false;
+ return Success;
+ }
+
+ Reader constraint(iPAddressConstraint);
+ Reader constraintAddress;
+ Result rv = constraint.Skip(iPAddressConstraint.GetLength() / 2u,
+ constraintAddress);
+ if (rv != Success) {
+ return rv;
+ }
+ Reader constraintMask;
+ rv = constraint.Skip(iPAddressConstraint.GetLength() / 2u, constraintMask);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::End(constraint);
+ if (rv != Success) {
+ return rv;
+ }
+
+ Reader presented(presentedID);
+ do {
+ uint8_t presentedByte;
+ rv = presented.Read(presentedByte);
+ if (rv != Success) {
+ return rv;
+ }
+ uint8_t constraintAddressByte;
+ rv = constraintAddress.Read(constraintAddressByte);
+ if (rv != Success) {
+ return rv;
+ }
+ uint8_t constraintMaskByte;
+ rv = constraintMask.Read(constraintMaskByte);
+ if (rv != Success) {
+ return rv;
+ }
+ foundMatch =
+ ((presentedByte ^ constraintAddressByte) & constraintMaskByte) == 0;
+ } while (foundMatch && !presented.AtEnd());
+
+ return Success;
+}
+
+// AttributeTypeAndValue ::= SEQUENCE {
+// type AttributeType,
+// value AttributeValue }
+//
+// AttributeType ::= OBJECT IDENTIFIER
+//
+// AttributeValue ::= ANY -- DEFINED BY AttributeType
+Result
+ReadAVA(Reader& rdn,
+ /*out*/ Input& type,
+ /*out*/ uint8_t& valueTag,
+ /*out*/ Input& value)
+{
+ return der::Nested(rdn, der::SEQUENCE, [&](Reader& ava) -> Result {
+ Result rv = der::ExpectTagAndGetValue(ava, der::OIDTag, type);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::ReadTagAndGetValue(ava, valueTag, value);
+ if (rv != Success) {
+ return rv;
+ }
+ return Success;
+ });
+}
+
+// Names are sequences of RDNs. RDNS are sets of AVAs. That means that RDNs are
+// unordered, so in theory we should match RDNs with equivalent AVAs that are
+// in different orders. Within the AVAs are DirectoryNames that are supposed to
+// be compared according to LDAP stringprep normalization rules (e.g.
+// normalizing whitespace), consideration of different character encodings,
+// etc. Indeed, RFC 5280 says we MUST deal with all of that.
+//
+// In practice, many implementations, including NSS, only match Names in a way
+// that only meets a subset of the requirements of RFC 5280. Those
+// normalization and character encoding conversion steps appear to be
+// unnecessary for processing real-world certificates, based on experience from
+// having used NSS in Firefox for many years.
+//
+// RFC 5280 also says "CAs issuing certificates with a restriction of the form
+// directoryName SHOULD NOT rely on implementation of the full
+// ISO DN name comparison algorithm. This implies name restrictions MUST
+// be stated identically to the encoding used in the subject field or
+// subjectAltName extension." It goes on to say, in the security
+// considerations:
+//
+// In addition, name constraints for distinguished names MUST be stated
+// identically to the encoding used in the subject field or
+// subjectAltName extension. If not, then name constraints stated as
+// excludedSubtrees will not match and invalid paths will be accepted
+// and name constraints expressed as permittedSubtrees will not match
+// and valid paths will be rejected. To avoid acceptance of invalid
+// paths, CAs SHOULD state name constraints for distinguished names as
+// permittedSubtrees wherever possible.
+//
+// For permittedSubtrees, the MUST-level requirement is relaxed for
+// compatibility in the case of PrintableString and UTF8String. That is, if a
+// name constraint has been encoded using UTF8String and the presented ID has
+// been encoded with a PrintableString (or vice-versa), they are considered to
+// match if they are equal everywhere except for the tag identifying the
+// encoding. See bug 1150114.
+//
+// For excludedSubtrees, we simply prohibit any non-empty directoryName
+// constraint to ensure we are not being too lenient. We support empty
+// DirectoryName constraints in excludedSubtrees so that a CA can say "Do not
+// allow any DirectoryNames in issued certificates."
+Result
+MatchPresentedDirectoryNameWithConstraint(NameConstraintsSubtrees subtreesType,
+ Input presentedID,
+ Input directoryNameConstraint,
+ /*out*/ bool& matches)
+{
+ Reader constraintRDNs;
+ Result rv = der::ExpectTagAndGetValueAtEnd(directoryNameConstraint,
+ der::SEQUENCE, constraintRDNs);
+ if (rv != Success) {
+ return rv;
+ }
+ Reader presentedRDNs;
+ rv = der::ExpectTagAndGetValueAtEnd(presentedID, der::SEQUENCE,
+ presentedRDNs);
+ if (rv != Success) {
+ return rv;
+ }
+
+ switch (subtreesType) {
+ case NameConstraintsSubtrees::permittedSubtrees:
+ break; // dealt with below
+ case NameConstraintsSubtrees::excludedSubtrees:
+ if (!constraintRDNs.AtEnd() || !presentedRDNs.AtEnd()) {
+ return Result::ERROR_CERT_NOT_IN_NAME_SPACE;
+ }
+ matches = true;
+ return Success;
+ }
+
+ for (;;) {
+ // The AVAs have to be fully equal, but the constraint RDNs just need to be
+ // a prefix of the presented RDNs.
+ if (constraintRDNs.AtEnd()) {
+ matches = true;
+ return Success;
+ }
+ if (presentedRDNs.AtEnd()) {
+ matches = false;
+ return Success;
+ }
+ Reader constraintRDN;
+ rv = der::ExpectTagAndGetValue(constraintRDNs, der::SET, constraintRDN);
+ if (rv != Success) {
+ return rv;
+ }
+ Reader presentedRDN;
+ rv = der::ExpectTagAndGetValue(presentedRDNs, der::SET, presentedRDN);
+ if (rv != Success) {
+ return rv;
+ }
+ while (!constraintRDN.AtEnd() && !presentedRDN.AtEnd()) {
+ Input constraintType;
+ uint8_t constraintValueTag;
+ Input constraintValue;
+ rv = ReadAVA(constraintRDN, constraintType, constraintValueTag,
+ constraintValue);
+ if (rv != Success) {
+ return rv;
+ }
+ Input presentedType;
+ uint8_t presentedValueTag;
+ Input presentedValue;
+ rv = ReadAVA(presentedRDN, presentedType, presentedValueTag,
+ presentedValue);
+ if (rv != Success) {
+ return rv;
+ }
+ // TODO (bug 1155767): verify that if an AVA is a PrintableString it
+ // consists only of characters valid for PrintableStrings.
+ bool avasMatch =
+ InputsAreEqual(constraintType, presentedType) &&
+ InputsAreEqual(constraintValue, presentedValue) &&
+ (constraintValueTag == presentedValueTag ||
+ (constraintValueTag == der::Tag::UTF8String &&
+ presentedValueTag == der::Tag::PrintableString) ||
+ (constraintValueTag == der::Tag::PrintableString &&
+ presentedValueTag == der::Tag::UTF8String));
+ if (!avasMatch) {
+ matches = false;
+ return Success;
+ }
+ }
+ if (!constraintRDN.AtEnd() || !presentedRDN.AtEnd()) {
+ matches = false;
+ return Success;
+ }
+ }
+}
+
+// RFC 5280 says:
+//
+// The format of an rfc822Name is a "Mailbox" as defined in Section 4.1.2
+// of [RFC2821]. A Mailbox has the form "Local-part@Domain". Note that a
+// Mailbox has no phrase (such as a common name) before it, has no comment
+// (text surrounded in parentheses) after it, and is not surrounded by "<"
+// and ">". Rules for encoding Internet mail addresses that include
+// internationalized domain names are specified in Section 7.5.
+//
+// and:
+//
+// A name constraint for Internet mail addresses MAY specify a
+// particular mailbox, all addresses at a particular host, or all
+// mailboxes in a domain. To indicate a particular mailbox, the
+// constraint is the complete mail address. For example,
+// "root@example.com" indicates the root mailbox on the host
+// "example.com". To indicate all Internet mail addresses on a
+// particular host, the constraint is specified as the host name. For
+// example, the constraint "example.com" is satisfied by any mail
+// address at the host "example.com". To specify any address within a
+// domain, the constraint is specified with a leading period (as with
+// URIs). For example, ".example.com" indicates all the Internet mail
+// addresses in the domain "example.com", but not Internet mail
+// addresses on the host "example.com".
+
+bool
+IsValidRFC822Name(Input input)
+{
+ Reader reader(input);
+
+ // Local-part@.
+ bool startOfAtom = true;
+ for (;;) {
+ uint8_t presentedByte;
+ if (reader.Read(presentedByte) != Success) {
+ return false;
+ }
+ switch (presentedByte) {
+ // atext is defined in https://tools.ietf.org/html/rfc2822#section-3.2.4
+ case 'A': case 'a': case 'N': case 'n': case '0': case '!': case '#':
+ case 'B': case 'b': case 'O': case 'o': case '1': case '$': case '%':
+ case 'C': case 'c': case 'P': case 'p': case '2': case '&': case '\'':
+ case 'D': case 'd': case 'Q': case 'q': case '3': case '*': case '+':
+ case 'E': case 'e': case 'R': case 'r': case '4': case '-': case '/':
+ case 'F': case 'f': case 'S': case 's': case '5': case '=': case '?':
+ case 'G': case 'g': case 'T': case 't': case '6': case '^': case '_':
+ case 'H': case 'h': case 'U': case 'u': case '7': case '`': case '{':
+ case 'I': case 'i': case 'V': case 'v': case '8': case '|': case '}':
+ case 'J': case 'j': case 'W': case 'w': case '9': case '~':
+ case 'K': case 'k': case 'X': case 'x':
+ case 'L': case 'l': case 'Y': case 'y':
+ case 'M': case 'm': case 'Z': case 'z':
+ startOfAtom = false;
+ break;
+
+ case '.':
+ if (startOfAtom) {
+ return false;
+ }
+ startOfAtom = true;
+ break;
+
+ case '@':
+ {
+ if (startOfAtom) {
+ return false;
+ }
+ Input domain;
+ if (reader.SkipToEnd(domain) != Success) {
+ return false;
+ }
+ return IsValidDNSID(domain, IDRole::PresentedID, AllowWildcards::No);
+ }
+
+ default:
+ return false;
+ }
+ }
+}
+
+Result
+MatchPresentedRFC822NameWithReferenceRFC822Name(Input presentedRFC822Name,
+ IDRole referenceRFC822NameRole,
+ Input referenceRFC822Name,
+ /*out*/ bool& matches)
+{
+ if (!IsValidRFC822Name(presentedRFC822Name)) {
+ return Result::ERROR_BAD_DER;
+ }
+ Reader presented(presentedRFC822Name);
+
+ switch (referenceRFC822NameRole)
+ {
+ case IDRole::PresentedID:
+ return Result::FATAL_ERROR_INVALID_ARGS;
+
+ case IDRole::ReferenceID:
+ break;
+
+ case IDRole::NameConstraint:
+ {
+ if (InputContains(referenceRFC822Name, '@')) {
+ // The constraint is of the form "Local-part@Domain".
+ break;
+ }
+
+ // The constraint is of the form "example.com" or ".example.com".
+
+ // Skip past the '@' in the presented ID.
+ for (;;) {
+ uint8_t presentedByte;
+ if (presented.Read(presentedByte) != Success) {
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+ if (presentedByte == '@') {
+ break;
+ }
+ }
+
+ Input presentedDNSID;
+ if (presented.SkipToEnd(presentedDNSID) != Success) {
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+
+ return MatchPresentedDNSIDWithReferenceDNSID(
+ presentedDNSID, AllowWildcards::No,
+ AllowDotlessSubdomainMatches::No, IDRole::NameConstraint,
+ referenceRFC822Name, matches);
+ }
+ }
+
+ if (!IsValidRFC822Name(referenceRFC822Name)) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ Reader reference(referenceRFC822Name);
+
+ for (;;) {
+ uint8_t presentedByte;
+ if (presented.Read(presentedByte) != Success) {
+ matches = reference.AtEnd();
+ return Success;
+ }
+ uint8_t referenceByte;
+ if (reference.Read(referenceByte) != Success) {
+ matches = false;
+ return Success;
+ }
+ if (LocaleInsensitveToLower(presentedByte) !=
+ LocaleInsensitveToLower(referenceByte)) {
+ matches = false;
+ return Success;
+ }
+ }
+}
+
+// We avoid isdigit because it is locale-sensitive. See
+// http://pubs.opengroup.org/onlinepubs/009695399/functions/tolower.html.
+inline uint8_t
+LocaleInsensitveToLower(uint8_t a)
+{
+ if (a >= 'A' && a <= 'Z') { // unlikely
+ return static_cast<uint8_t>(
+ static_cast<uint8_t>(a - static_cast<uint8_t>('A')) +
+ static_cast<uint8_t>('a'));
+ }
+ return a;
+}
+
+bool
+StartsWithIDNALabel(Input id)
+{
+ static const uint8_t IDN_ALABEL_PREFIX[4] = { 'x', 'n', '-', '-' };
+ Reader input(id);
+ for (const uint8_t prefixByte : IDN_ALABEL_PREFIX) {
+ uint8_t b;
+ if (input.Read(b) != Success) {
+ return false;
+ }
+ if (b != prefixByte) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+ReadIPv4AddressComponent(Reader& input, bool lastComponent,
+ /*out*/ uint8_t& valueOut)
+{
+ size_t length = 0;
+ unsigned int value = 0; // Must be larger than uint8_t.
+
+ for (;;) {
+ if (input.AtEnd() && lastComponent) {
+ break;
+ }
+
+ uint8_t b;
+ if (input.Read(b) != Success) {
+ return false;
+ }
+
+ if (b >= '0' && b <= '9') {
+ if (value == 0 && length > 0) {
+ return false; // Leading zeros are not allowed.
+ }
+ value = (value * 10) + (b - '0');
+ if (value > 255) {
+ return false; // Component's value is too large.
+ }
+ ++length;
+ } else if (!lastComponent && b == '.') {
+ break;
+ } else {
+ return false; // Invalid character.
+ }
+ }
+
+ if (length == 0) {
+ return false; // empty components not allowed
+ }
+
+ valueOut = static_cast<uint8_t>(value);
+ return true;
+}
+
+} // namespace
+
+// On Windows and maybe other platforms, OS-provided IP address parsing
+// functions might fail if the protocol (IPv4 or IPv6) has been disabled, so we
+// can't rely on them.
+bool
+ParseIPv4Address(Input hostname, /*out*/ uint8_t (&out)[4])
+{
+ Reader input(hostname);
+ return ReadIPv4AddressComponent(input, false, out[0]) &&
+ ReadIPv4AddressComponent(input, false, out[1]) &&
+ ReadIPv4AddressComponent(input, false, out[2]) &&
+ ReadIPv4AddressComponent(input, true, out[3]);
+}
+
+namespace {
+
+bool
+FinishIPv6Address(/*in/out*/ uint8_t (&address)[16], int numComponents,
+ int contractionIndex)
+{
+ assert(numComponents >= 0);
+ assert(numComponents <= 8);
+ assert(contractionIndex >= -1);
+ assert(contractionIndex <= 8);
+ assert(contractionIndex <= numComponents);
+ if (!(numComponents >= 0 &&
+ numComponents <= 8 &&
+ contractionIndex >= -1 &&
+ contractionIndex <= 8 &&
+ contractionIndex <= numComponents)) {
+ return false;
+ }
+
+ if (contractionIndex == -1) {
+ // no contraction
+ return numComponents == 8;
+ }
+
+ if (numComponents >= 8) {
+ return false; // no room left to expand the contraction.
+ }
+
+ // Shift components that occur after the contraction over.
+ std::copy_backward(address + (2u * static_cast<size_t>(contractionIndex)),
+ address + (2u * static_cast<size_t>(numComponents)),
+ address + (2u * 8u));
+ // Fill in the contracted area with zeros.
+ std::fill_n(address + 2u * static_cast<size_t>(contractionIndex),
+ (8u - static_cast<size_t>(numComponents)) * 2u, static_cast<uint8_t>(0u));
+
+ return true;
+}
+
+} // namespace
+
+// On Windows and maybe other platforms, OS-provided IP address parsing
+// functions might fail if the protocol (IPv4 or IPv6) has been disabled, so we
+// can't rely on them.
+bool
+ParseIPv6Address(Input hostname, /*out*/ uint8_t (&out)[16])
+{
+ Reader input(hostname);
+
+ int currentComponentIndex = 0;
+ int contractionIndex = -1;
+
+ if (input.Peek(':')) {
+ // A valid input can only start with ':' if there is a contraction at the
+ // beginning.
+ uint8_t b;
+ if (input.Read(b) != Success || b != ':') {
+ assert(false);
+ return false;
+ }
+ if (input.Read(b) != Success) {
+ return false;
+ }
+ if (b != ':') {
+ return false;
+ }
+ contractionIndex = 0;
+ }
+
+ for (;;) {
+ // If we encounter a '.' then we'll have to backtrack to parse the input
+ // from startOfComponent to the end of the input as an IPv4 address.
+ Reader::Mark startOfComponent(input.GetMark());
+ uint16_t componentValue = 0;
+ size_t componentLength = 0;
+ while (!input.AtEnd() && !input.Peek(':')) {
+ uint8_t value;
+ uint8_t b;
+ if (input.Read(b) != Success) {
+ assert(false);
+ return false;
+ }
+ switch (b) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ value = static_cast<uint8_t>(b - static_cast<uint8_t>('0'));
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ value = static_cast<uint8_t>(b - static_cast<uint8_t>('a') +
+ UINT8_C(10));
+ break;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ value = static_cast<uint8_t>(b - static_cast<uint8_t>('A') +
+ UINT8_C(10));
+ break;
+ case '.':
+ {
+ // A dot indicates we hit a IPv4-syntax component. Backtrack, parsing
+ // the input from startOfComponent to the end of the input as an IPv4
+ // address, and then combine it with the other components.
+
+ if (currentComponentIndex > 6) {
+ return false; // Too many components before the IPv4 component
+ }
+
+ input.SkipToEnd();
+ Input ipv4Component;
+ if (input.GetInput(startOfComponent, ipv4Component) != Success) {
+ return false;
+ }
+ uint8_t (*ipv4)[4] =
+ reinterpret_cast<uint8_t(*)[4]>(&out[2 * currentComponentIndex]);
+ if (!ParseIPv4Address(ipv4Component, *ipv4)) {
+ return false;
+ }
+ assert(input.AtEnd());
+ currentComponentIndex += 2;
+
+ return FinishIPv6Address(out, currentComponentIndex,
+ contractionIndex);
+ }
+ default:
+ return false;
+ }
+ if (componentLength >= 4) {
+ // component too long
+ return false;
+ }
+ ++componentLength;
+ componentValue = (componentValue * 0x10u) + value;
+ }
+
+ if (currentComponentIndex >= 8) {
+ return false; // too many components
+ }
+
+ if (componentLength == 0) {
+ if (input.AtEnd() && currentComponentIndex == contractionIndex) {
+ if (contractionIndex == 0) {
+ // don't accept "::"
+ return false;
+ }
+ return FinishIPv6Address(out, currentComponentIndex,
+ contractionIndex);
+ }
+ return false;
+ }
+
+ out[2 * currentComponentIndex] =
+ static_cast<uint8_t>(componentValue / 0x100);
+ out[(2 * currentComponentIndex) + 1] =
+ static_cast<uint8_t>(componentValue % 0x100);
+
+ ++currentComponentIndex;
+
+ if (input.AtEnd()) {
+ return FinishIPv6Address(out, currentComponentIndex,
+ contractionIndex);
+ }
+
+ uint8_t b;
+ if (input.Read(b) != Success || b != ':') {
+ assert(false);
+ return false;
+ }
+
+ if (input.Peek(':')) {
+ // Contraction
+ if (contractionIndex != -1) {
+ return false; // multiple contractions are not allowed.
+ }
+ if (input.Read(b) != Success || b != ':') {
+ assert(false);
+ return false;
+ }
+ contractionIndex = currentComponentIndex;
+ if (input.AtEnd()) {
+ // "::" at the end of the input.
+ return FinishIPv6Address(out, currentComponentIndex,
+ contractionIndex);
+ }
+ }
+ }
+}
+
+bool
+IsValidReferenceDNSID(Input hostname)
+{
+ return IsValidDNSID(hostname, IDRole::ReferenceID, AllowWildcards::No);
+}
+
+bool
+IsValidPresentedDNSID(Input hostname)
+{
+ return IsValidDNSID(hostname, IDRole::PresentedID, AllowWildcards::Yes);
+}
+
+namespace {
+
+// RFC 5280 Section 4.2.1.6 says that a dNSName "MUST be in the 'preferred name
+// syntax', as specified by Section 3.5 of [RFC1034] and as modified by Section
+// 2.1 of [RFC1123]" except "a dNSName of ' ' MUST NOT be used." Additionally,
+// we allow underscores for compatibility with existing practice.
+bool
+IsValidDNSID(Input hostname, IDRole idRole, AllowWildcards allowWildcards)
+{
+ if (hostname.GetLength() > 253) {
+ return false;
+ }
+
+ Reader input(hostname);
+
+ if (idRole == IDRole::NameConstraint && input.AtEnd()) {
+ return true;
+ }
+
+ size_t dotCount = 0;
+ size_t labelLength = 0;
+ bool labelIsAllNumeric = false;
+ bool labelEndsWithHyphen = false;
+
+ // Only presented IDs are allowed to have wildcard labels. And, like
+ // Chromium, be stricter than RFC 6125 requires by insisting that a
+ // wildcard label consist only of '*'.
+ bool isWildcard = allowWildcards == AllowWildcards::Yes && input.Peek('*');
+ bool isFirstByte = !isWildcard;
+ if (isWildcard) {
+ Result rv = input.Skip(1);
+ if (rv != Success) {
+ assert(false);
+ return false;
+ }
+
+ uint8_t b;
+ rv = input.Read(b);
+ if (rv != Success) {
+ return false;
+ }
+ if (b != '.') {
+ return false;
+ }
+ ++dotCount;
+ }
+
+ do {
+ static const size_t MAX_LABEL_LENGTH = 63;
+
+ uint8_t b;
+ if (input.Read(b) != Success) {
+ return false;
+ }
+ switch (b) {
+ case '-':
+ if (labelLength == 0) {
+ return false; // Labels must not start with a hyphen.
+ }
+ labelIsAllNumeric = false;
+ labelEndsWithHyphen = true;
+ ++labelLength;
+ if (labelLength > MAX_LABEL_LENGTH) {
+ return false;
+ }
+ break;
+
+ // We avoid isdigit because it is locale-sensitive. See
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/isdigit.html
+ case '0': case '5':
+ case '1': case '6':
+ case '2': case '7':
+ case '3': case '8':
+ case '4': case '9':
+ if (labelLength == 0) {
+ labelIsAllNumeric = true;
+ }
+ labelEndsWithHyphen = false;
+ ++labelLength;
+ if (labelLength > MAX_LABEL_LENGTH) {
+ return false;
+ }
+ break;
+
+ // We avoid using islower/isupper/tolower/toupper or similar things, to
+ // avoid any possibility of this code being locale-sensitive. See
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/isupper.html
+ case 'a': case 'A': case 'n': case 'N':
+ case 'b': case 'B': case 'o': case 'O':
+ case 'c': case 'C': case 'p': case 'P':
+ case 'd': case 'D': case 'q': case 'Q':
+ case 'e': case 'E': case 'r': case 'R':
+ case 'f': case 'F': case 's': case 'S':
+ case 'g': case 'G': case 't': case 'T':
+ case 'h': case 'H': case 'u': case 'U':
+ case 'i': case 'I': case 'v': case 'V':
+ case 'j': case 'J': case 'w': case 'W':
+ case 'k': case 'K': case 'x': case 'X':
+ case 'l': case 'L': case 'y': case 'Y':
+ case 'm': case 'M': case 'z': case 'Z':
+ // We allow underscores for compatibility with existing practices.
+ // See bug 1136616.
+ case '_':
+ labelIsAllNumeric = false;
+ labelEndsWithHyphen = false;
+ ++labelLength;
+ if (labelLength > MAX_LABEL_LENGTH) {
+ return false;
+ }
+ break;
+
+ case '.':
+ ++dotCount;
+ if (labelLength == 0 &&
+ (idRole != IDRole::NameConstraint || !isFirstByte)) {
+ return false;
+ }
+ if (labelEndsWithHyphen) {
+ return false; // Labels must not end with a hyphen.
+ }
+ labelLength = 0;
+ break;
+
+ default:
+ return false; // Invalid character.
+ }
+ isFirstByte = false;
+ } while (!input.AtEnd());
+
+ // Only reference IDs, not presented IDs or name constraints, may be
+ // absolute.
+ if (labelLength == 0 && idRole != IDRole::ReferenceID) {
+ return false;
+ }
+
+ if (labelEndsWithHyphen) {
+ return false; // Labels must not end with a hyphen.
+ }
+
+ if (labelIsAllNumeric) {
+ return false; // Last label must not be all numeric.
+ }
+
+ if (isWildcard) {
+ // If the DNS ID ends with a dot, the last dot signifies an absolute ID.
+ size_t labelCount = (labelLength == 0) ? dotCount : (dotCount + 1);
+
+ // Like NSS, require at least two labels to follow the wildcard label.
+ //
+ // TODO(bug XXXXXXX): Allow the TrustDomain to control this on a
+ // per-eTLD+1 basis, similar to Chromium. Even then, it might be better to
+ // still enforce that there are at least two labels after the wildcard.
+ if (labelCount < 3) {
+ return false;
+ }
+ // XXX: RFC6125 says that we shouldn't accept wildcards within an IDN
+ // A-Label. The consequence of this is that we effectively discriminate
+ // against users of languages that cannot be encoded with ASCII.
+ if (StartsWithIDNALabel(hostname)) {
+ return false;
+ }
+
+ // TODO(bug XXXXXXX): Wildcards are not allowed for EV certificates.
+ // Provide an option to indicate whether wildcards should be matched, for
+ // the purpose of helping the application enforce this.
+ }
+
+ return true;
+}
+
+} // namespace
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/lib/pkixnss.cpp b/security/nss/lib/mozpkix/lib/pkixnss.cpp
new file mode 100644
index 000000000..9b293d5fd
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixnss.cpp
@@ -0,0 +1,236 @@
+/*- *- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/pkixnss.h"
+
+#include <limits>
+
+#include "cryptohi.h"
+#include "keyhi.h"
+#include "pk11pub.h"
+#include "mozpkix/nss_scoped_ptrs.h"
+#include "mozpkix/pkix.h"
+#include "mozpkix/pkixutil.h"
+#include "secerr.h"
+#include "sslerr.h"
+
+namespace mozilla { namespace pkix {
+
+namespace {
+
+Result
+VerifySignedDigest(const SignedDigest& sd,
+ Input subjectPublicKeyInfo,
+ SECOidTag pubKeyAlg,
+ void* pkcs11PinArg)
+{
+ SECOidTag digestAlg;
+ switch (sd.digestAlgorithm) {
+ case DigestAlgorithm::sha512: digestAlg = SEC_OID_SHA512; break;
+ case DigestAlgorithm::sha384: digestAlg = SEC_OID_SHA384; break;
+ case DigestAlgorithm::sha256: digestAlg = SEC_OID_SHA256; break;
+ case DigestAlgorithm::sha1: digestAlg = SEC_OID_SHA1; break;
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+
+ SECItem subjectPublicKeyInfoSECItem =
+ UnsafeMapInputToSECItem(subjectPublicKeyInfo);
+ ScopedCERTSubjectPublicKeyInfo
+ spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem));
+ if (!spki) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ ScopedSECKEYPublicKey
+ pubKey(SECKEY_ExtractPublicKey(spki.get()));
+ if (!pubKey) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+
+ SECItem digestSECItem(UnsafeMapInputToSECItem(sd.digest));
+ SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature));
+ SECStatus srv = VFY_VerifyDigestDirect(&digestSECItem, pubKey.get(),
+ &signatureSECItem, pubKeyAlg,
+ digestAlg, pkcs11PinArg);
+ if (srv != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+
+ return Success;
+}
+
+} // namespace
+
+Result
+VerifyRSAPKCS1SignedDigestNSS(const SignedDigest& sd,
+ Input subjectPublicKeyInfo,
+ void* pkcs11PinArg)
+{
+ return VerifySignedDigest(sd, subjectPublicKeyInfo,
+ SEC_OID_PKCS1_RSA_ENCRYPTION, pkcs11PinArg);
+}
+
+Result
+VerifyECDSASignedDigestNSS(const SignedDigest& sd,
+ Input subjectPublicKeyInfo,
+ void* pkcs11PinArg)
+{
+ return VerifySignedDigest(sd, subjectPublicKeyInfo,
+ SEC_OID_ANSIX962_EC_PUBLIC_KEY, pkcs11PinArg);
+}
+
+Result
+DigestBufNSS(Input item,
+ DigestAlgorithm digestAlg,
+ /*out*/ uint8_t* digestBuf,
+ size_t digestBufLen)
+{
+ SECOidTag oid;
+ size_t bits;
+ switch (digestAlg) {
+ case DigestAlgorithm::sha512: oid = SEC_OID_SHA512; bits = 512; break;
+ case DigestAlgorithm::sha384: oid = SEC_OID_SHA384; bits = 384; break;
+ case DigestAlgorithm::sha256: oid = SEC_OID_SHA256; bits = 256; break;
+ case DigestAlgorithm::sha1: oid = SEC_OID_SHA1; bits = 160; break;
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+ if (digestBufLen != bits / 8) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+
+ SECItem itemSECItem = UnsafeMapInputToSECItem(item);
+ if (itemSECItem.len >
+ static_cast<decltype(itemSECItem.len)>(
+ std::numeric_limits<int32_t>::max())) {
+ PR_NOT_REACHED("large items should not be possible here");
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+ SECStatus srv = PK11_HashBuf(oid, digestBuf, itemSECItem.data,
+ static_cast<int32_t>(itemSECItem.len));
+ if (srv != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ return Success;
+}
+
+Result
+MapPRErrorCodeToResult(PRErrorCode error)
+{
+ switch (error)
+ {
+#define MOZILLA_PKIX_MAP(mozilla_pkix_result, value, nss_result) \
+ case nss_result: return Result::mozilla_pkix_result;
+
+ MOZILLA_PKIX_MAP_LIST
+
+#undef MOZILLA_PKIX_MAP
+
+ default:
+ return Result::ERROR_UNKNOWN_ERROR;
+ }
+}
+
+PRErrorCode
+MapResultToPRErrorCode(Result result)
+{
+ switch (result)
+ {
+#define MOZILLA_PKIX_MAP(mozilla_pkix_result, value, nss_result) \
+ case Result::mozilla_pkix_result: return nss_result;
+
+ MOZILLA_PKIX_MAP_LIST
+
+#undef MOZILLA_PKIX_MAP
+
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+}
+
+void
+RegisterErrorTable()
+{
+ // Note that these error strings are not localizable.
+ // When these strings change, update the localization information too.
+ static const PRErrorMessage ErrorTableText[] = {
+ { "MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE",
+ "The server uses key pinning (HPKP) but no trusted certificate chain "
+ "could be constructed that matches the pinset. Key pinning violations "
+ "cannot be overridden." },
+ { "MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY",
+ "The server uses a certificate with a basic constraints extension "
+ "identifying it as a certificate authority. For a properly-issued "
+ "certificate, this should not be the case." },
+ { "MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE",
+ "The server presented a certificate with a key size that is too small "
+ "to establish a secure connection." },
+ { "MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA",
+ "An X.509 version 1 certificate that is not a trust anchor was used to "
+ "issue the server's certificate. X.509 version 1 certificates are "
+ "deprecated and should not be used to sign other certificates." },
+ { "MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH",
+ "The certificate is not valid for the given email address." },
+ { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE",
+ "The server presented a certificate that is not yet valid." },
+ { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE",
+ "A certificate that is not yet valid was used to issue the server's "
+ "certificate." },
+ { "MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH",
+ "The signature algorithm in the signature field of the certificate does "
+ "not match the algorithm in its signatureAlgorithm field." },
+ { "MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING",
+ "The OCSP response does not include a status for the certificate being "
+ "verified." },
+ { "MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG",
+ "The server presented a certificate that is valid for too long." },
+ { "MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING",
+ "A required TLS feature is missing." },
+ { "MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING",
+ "The server presented a certificate that contains an invalid encoding of "
+ "an integer. Common causes include negative serial numbers, negative RSA "
+ "moduli, and encodings that are longer than necessary." },
+ { "MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME",
+ "The server presented a certificate with an empty issuer distinguished "
+ "name." },
+ { "MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED",
+ "An additional policy constraint failed when validating this "
+ "certificate." },
+ { "MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT",
+ "The certificate is not trusted because it is self-signed." },
+ { "MOZILLA_PKIX_ERROR_MITM_DETECTED",
+ "Your connection is being intercepted by a TLS proxy. Uninstall it if "
+ "possible or configure your device to trust its root certificate." },
+ };
+ // Note that these error strings are not localizable.
+ // When these strings change, update the localization information too.
+
+ static const PRErrorTable ErrorTable = {
+ ErrorTableText,
+ "pkixerrors",
+ ERROR_BASE,
+ PR_ARRAY_SIZE(ErrorTableText)
+ };
+
+ (void) PR_ErrorInstallTable(&ErrorTable);
+}
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/lib/pkixocsp.cpp b/security/nss/lib/mozpkix/lib/pkixocsp.cpp
new file mode 100644
index 000000000..a81154417
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixocsp.cpp
@@ -0,0 +1,1012 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits>
+
+#include "mozpkix/pkix.h"
+#include "mozpkix/pkixcheck.h"
+#include "mozpkix/pkixutil.h"
+
+namespace {
+
+const size_t SHA1_DIGEST_LENGTH = 160 / 8;
+
+} // namespace
+
+namespace mozilla { namespace pkix {
+
+// These values correspond to the tag values in the ASN.1 CertStatus
+enum class CertStatus : uint8_t {
+ Good = der::CONTEXT_SPECIFIC | 0,
+ Revoked = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
+ Unknown = der::CONTEXT_SPECIFIC | 2
+};
+
+class Context final
+{
+public:
+ Context(TrustDomain& aTrustDomain, const CertID& aCertID, Time aTime,
+ uint16_t aMaxLifetimeInDays, /*optional out*/ Time* aThisUpdate,
+ /*optional out*/ Time* aValidThrough)
+ : trustDomain(aTrustDomain)
+ , certID(aCertID)
+ , time(aTime)
+ , maxLifetimeInDays(aMaxLifetimeInDays)
+ , certStatus(CertStatus::Unknown)
+ , thisUpdate(aThisUpdate)
+ , validThrough(aValidThrough)
+ , expired(false)
+ , matchFound(false)
+ {
+ if (thisUpdate) {
+ *thisUpdate = TimeFromElapsedSecondsAD(0);
+ }
+ if (validThrough) {
+ *validThrough = TimeFromElapsedSecondsAD(0);
+ }
+ }
+
+ TrustDomain& trustDomain;
+ const CertID& certID;
+ const Time time;
+ const uint16_t maxLifetimeInDays;
+ CertStatus certStatus;
+ Time* thisUpdate;
+ Time* validThrough;
+ bool expired;
+
+ Input signedCertificateTimestamps;
+
+ // Keep track of whether the OCSP response contains the status of the
+ // certificate we're interested in. Responders might reply without
+ // including the status of any of the requested certs, we should
+ // indicate a server failure in those cases.
+ bool matchFound;
+
+ Context(const Context&) = delete;
+ void operator=(const Context&) = delete;
+};
+
+// Verify that potentialSigner is a valid delegated OCSP response signing cert
+// according to RFC 6960 section 4.2.2.2.
+static Result
+CheckOCSPResponseSignerCert(TrustDomain& trustDomain,
+ BackCert& potentialSigner,
+ Input issuerSubject,
+ Input issuerSubjectPublicKeyInfo,
+ Time time)
+{
+ Result rv;
+
+ // We don't need to do a complete verification of the signer (i.e. we don't
+ // have to call BuildCertChain to verify the entire chain) because we
+ // already know that the issuer is valid, since revocation checking is done
+ // from the root to the parent after we've built a complete chain that we
+ // know is otherwise valid. Rather, we just need to do a one-step validation
+ // from potentialSigner to the issuer.
+ //
+ // It seems reasonable to require the KU_DIGITAL_SIGNATURE key usage on the
+ // OCSP responder certificate if the OCSP responder certificate has a
+ // key usage extension. However, according to bug 240456, some OCSP responder
+ // certificates may have only the nonRepudiation bit set. Also, the OCSP
+ // specification (RFC 6960) does not mandate any particular key usage to be
+ // asserted for OCSP responde signers. Oddly, the CABForum Baseline
+ // Requirements v.1.1.5 do say "If the Root CA Private Key is used for
+ // signing OCSP responses, then the digitalSignature bit MUST be set."
+ //
+ // Note that CheckIssuerIndependentProperties processes
+ // SEC_OID_OCSP_RESPONDER in the way that the OCSP specification requires us
+ // to--in particular, it doesn't allow SEC_OID_OCSP_RESPONDER to be implied
+ // by a missing EKU extension, unlike other EKUs.
+ //
+ // TODO(bug 926261): If we're validating for a policy then the policy OID we
+ // are validating for should be passed to CheckIssuerIndependentProperties.
+ TrustLevel unusedTrustLevel;
+ rv = CheckIssuerIndependentProperties(trustDomain, potentialSigner, time,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::id_kp_OCSPSigning,
+ CertPolicyId::anyPolicy, 0,
+ unusedTrustLevel);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // It is possible that there exists a certificate with the same key as the
+ // issuer but with a different name, so we need to compare names
+ // XXX(bug 926270) XXX(bug 1008133) XXX(bug 980163): Improve name
+ // comparison.
+ // TODO: needs test
+ if (!InputsAreEqual(potentialSigner.GetIssuer(), issuerSubject)) {
+ return Result::ERROR_OCSP_RESPONDER_CERT_INVALID;
+ }
+
+ // TODO(bug 926260): check name constraints
+
+ rv = VerifySignedData(trustDomain, potentialSigner.GetSignedData(),
+ issuerSubjectPublicKeyInfo);
+
+ // TODO: check for revocation of the OCSP responder certificate unless no-check
+ // or the caller forcing no-check. To properly support the no-check policy, we'd
+ // need to enforce policy constraints from the issuerChain.
+
+ return rv;
+}
+
+enum class ResponderIDType : uint8_t
+{
+ byName = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
+ byKey = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 2
+};
+
+static inline Result OCSPResponse(Reader&, Context&);
+static inline Result ResponseBytes(Reader&, Context&);
+static inline Result BasicResponse(Reader&, Context&);
+static inline Result ResponseData(
+ Reader& tbsResponseData,
+ Context& context,
+ const der::SignedDataWithSignature& signedResponseData,
+ const DERArray& certs);
+static inline Result SingleResponse(Reader& input, Context& context);
+static Result ExtensionNotUnderstood(Reader& extnID, Input extnValue,
+ bool critical, /*out*/ bool& understood);
+static Result RememberSingleExtension(Context& context, Reader& extnID,
+ Input extnValue, bool critical,
+ /*out*/ bool& understood);
+// It is convention to name the function after the part of the data structure
+// we're parsing from the RFC (e.g. OCSPResponse, ResponseBytes).
+// But since we also have a C++ type called CertID, this function doesn't
+// follow the convention to prevent shadowing.
+static inline Result MatchCertID(Reader& input,
+ const Context& context,
+ /*out*/ bool& match);
+static Result MatchKeyHash(TrustDomain& trustDomain,
+ Input issuerKeyHash,
+ Input issuerSubjectPublicKeyInfo,
+ /*out*/ bool& match);
+static Result KeyHash(TrustDomain& trustDomain,
+ Input subjectPublicKeyInfo,
+ /*out*/ uint8_t* hashBuf, size_t hashBufSize);
+
+static Result
+MatchResponderID(TrustDomain& trustDomain,
+ ResponderIDType responderIDType,
+ Input responderID,
+ Input potentialSignerSubject,
+ Input potentialSignerSubjectPublicKeyInfo,
+ /*out*/ bool& match)
+{
+ match = false;
+
+ switch (responderIDType) {
+ case ResponderIDType::byName:
+ // XXX(bug 926270) XXX(bug 1008133) XXX(bug 980163): Improve name
+ // comparison.
+ match = InputsAreEqual(responderID, potentialSignerSubject);
+ return Success;
+
+ case ResponderIDType::byKey:
+ {
+ Reader input(responderID);
+ Input keyHash;
+ Result rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, keyHash);
+ if (rv != Success) {
+ return rv;
+ }
+ return MatchKeyHash(trustDomain, keyHash,
+ potentialSignerSubjectPublicKeyInfo, match);
+ }
+
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+}
+
+static Result
+VerifyOCSPSignedData(TrustDomain& trustDomain,
+ const der::SignedDataWithSignature& signedResponseData,
+ Input spki)
+{
+ Result rv = VerifySignedData(trustDomain, signedResponseData, spki);
+ if (rv == Result::ERROR_BAD_SIGNATURE) {
+ rv = Result::ERROR_OCSP_BAD_SIGNATURE;
+ }
+ return rv;
+}
+
+// RFC 6960 section 4.2.2.2: The OCSP responder must either be the issuer of
+// the cert or it must be a delegated OCSP response signing cert directly
+// issued by the issuer. If the OCSP responder is a delegated OCSP response
+// signer, then its certificate is (probably) embedded within the OCSP
+// response and we'll need to verify that it is a valid certificate that chains
+// *directly* to issuerCert.
+static Result
+VerifySignature(Context& context, ResponderIDType responderIDType,
+ Input responderID, const DERArray& certs,
+ const der::SignedDataWithSignature& signedResponseData)
+{
+ bool match;
+ Result rv = MatchResponderID(context.trustDomain, responderIDType,
+ responderID, context.certID.issuer,
+ context.certID.issuerSubjectPublicKeyInfo,
+ match);
+ if (rv != Success) {
+ return rv;
+ }
+ if (match) {
+ return VerifyOCSPSignedData(context.trustDomain, signedResponseData,
+ context.certID.issuerSubjectPublicKeyInfo);
+ }
+
+ size_t numCerts = certs.GetLength();
+ for (size_t i = 0; i < numCerts; ++i) {
+ BackCert cert(*certs.GetDER(i), EndEntityOrCA::MustBeEndEntity, nullptr);
+ rv = cert.Init();
+ if (rv != Success) {
+ return rv;
+ }
+ rv = MatchResponderID(context.trustDomain, responderIDType, responderID,
+ cert.GetSubject(), cert.GetSubjectPublicKeyInfo(),
+ match);
+ if (rv != Success) {
+ if (IsFatalError(rv)) {
+ return rv;
+ }
+ continue;
+ }
+
+ if (match) {
+ rv = CheckOCSPResponseSignerCert(context.trustDomain, cert,
+ context.certID.issuer,
+ context.certID.issuerSubjectPublicKeyInfo,
+ context.time);
+ if (rv != Success) {
+ if (IsFatalError(rv)) {
+ return rv;
+ }
+ continue;
+ }
+
+ return VerifyOCSPSignedData(context.trustDomain, signedResponseData,
+ cert.GetSubjectPublicKeyInfo());
+ }
+ }
+
+ return Result::ERROR_OCSP_INVALID_SIGNING_CERT;
+}
+
+static inline Result
+MapBadDERToMalformedOCSPResponse(Result rv)
+{
+ if (rv == Result::ERROR_BAD_DER) {
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
+ }
+ return rv;
+}
+
+Result
+VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
+ Time time, uint16_t maxOCSPLifetimeInDays,
+ Input encodedResponse,
+ /*out*/ bool& expired,
+ /*optional out*/ Time* thisUpdate,
+ /*optional out*/ Time* validThrough)
+{
+ // Always initialize this to something reasonable.
+ expired = false;
+
+ Context context(trustDomain, certID, time, maxOCSPLifetimeInDays,
+ thisUpdate, validThrough);
+
+ Reader input(encodedResponse);
+ Result rv = der::Nested(input, der::SEQUENCE, [&context](Reader& r) {
+ return OCSPResponse(r, context);
+ });
+ if (rv != Success) {
+ return MapBadDERToMalformedOCSPResponse(rv);
+ }
+ rv = der::End(input);
+ if (rv != Success) {
+ return MapBadDERToMalformedOCSPResponse(rv);
+ }
+ if (!context.matchFound) {
+ return Result::ERROR_OCSP_RESPONSE_FOR_CERT_MISSING;
+ }
+
+ expired = context.expired;
+
+ switch (context.certStatus) {
+ case CertStatus::Good:
+ if (expired) {
+ return Result::ERROR_OCSP_OLD_RESPONSE;
+ }
+ if (context.signedCertificateTimestamps.GetLength()) {
+ Input sctList;
+ rv = ExtractSignedCertificateTimestampListFromExtension(
+ context.signedCertificateTimestamps, sctList);
+ if (rv != Success) {
+ return MapBadDERToMalformedOCSPResponse(rv);
+ }
+ context.trustDomain.NoteAuxiliaryExtension(
+ AuxiliaryExtension::SCTListFromOCSPResponse, sctList);
+ }
+ return Success;
+ case CertStatus::Revoked:
+ return Result::ERROR_REVOKED_CERTIFICATE;
+ case CertStatus::Unknown:
+ return Result::ERROR_OCSP_UNKNOWN_CERT;
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+}
+
+// OCSPResponse ::= SEQUENCE {
+// responseStatus OCSPResponseStatus,
+// responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+//
+static inline Result
+OCSPResponse(Reader& input, Context& context)
+{
+ // OCSPResponseStatus ::= ENUMERATED {
+ // successful (0), -- Response has valid confirmations
+ // malformedRequest (1), -- Illegal confirmation request
+ // internalError (2), -- Internal error in issuer
+ // tryLater (3), -- Try again later
+ // -- (4) is not used
+ // sigRequired (5), -- Must sign the request
+ // unauthorized (6) -- Request unauthorized
+ // }
+ uint8_t responseStatus;
+
+ Result rv = der::Enumerated(input, responseStatus);
+ if (rv != Success) {
+ return rv;
+ }
+ switch (responseStatus) {
+ case 0: break; // successful
+ case 1: return Result::ERROR_OCSP_MALFORMED_REQUEST;
+ case 2: return Result::ERROR_OCSP_SERVER_ERROR;
+ case 3: return Result::ERROR_OCSP_TRY_SERVER_LATER;
+ case 5: return Result::ERROR_OCSP_REQUEST_NEEDS_SIG;
+ case 6: return Result::ERROR_OCSP_UNAUTHORIZED_REQUEST;
+ default: return Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS;
+ }
+
+ return der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
+ der::SEQUENCE, [&context](Reader& r) {
+ return ResponseBytes(r, context);
+ });
+}
+
+// ResponseBytes ::= SEQUENCE {
+// responseType OBJECT IDENTIFIER,
+// response OCTET STRING }
+static inline Result
+ResponseBytes(Reader& input, Context& context)
+{
+ static const uint8_t id_pkix_ocsp_basic[] = {
+ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+ };
+
+ Result rv = der::OID(input, id_pkix_ocsp_basic);
+ if (rv != Success) {
+ return rv;
+ }
+
+ return der::Nested(input, der::OCTET_STRING, der::SEQUENCE,
+ [&context](Reader& r) {
+ return BasicResponse(r, context);
+ });
+}
+
+// BasicOCSPResponse ::= SEQUENCE {
+// tbsResponseData ResponseData,
+// signatureAlgorithm AlgorithmIdentifier,
+// signature BIT STRING,
+// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+Result
+BasicResponse(Reader& input, Context& context)
+{
+ Reader tbsResponseData;
+ der::SignedDataWithSignature signedData;
+ Result rv = der::SignedData(input, tbsResponseData, signedData);
+ if (rv != Success) {
+ if (rv == Result::ERROR_BAD_SIGNATURE) {
+ return Result::ERROR_OCSP_BAD_SIGNATURE;
+ }
+ return rv;
+ }
+
+ // Parse certificates, if any
+ NonOwningDERArray certs;
+ if (!input.AtEnd()) {
+ rv = der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
+ der::SEQUENCE, [&certs](Reader& certsDER) -> Result {
+ while (!certsDER.AtEnd()) {
+ Input cert;
+ Result nestedRv =
+ der::ExpectTagAndGetTLV(certsDER, der::SEQUENCE, cert);
+ if (nestedRv != Success) {
+ return nestedRv;
+ }
+ nestedRv = certs.Append(cert);
+ if (nestedRv != Success) {
+ return Result::ERROR_BAD_DER; // Too many certs
+ }
+ }
+ return Success;
+ });
+ if (rv != Success) {
+ return rv;
+ }
+ }
+
+ return ResponseData(tbsResponseData, context, signedData, certs);
+}
+
+// ResponseData ::= SEQUENCE {
+// version [0] EXPLICIT Version DEFAULT v1,
+// responderID ResponderID,
+// producedAt GeneralizedTime,
+// responses SEQUENCE OF SingleResponse,
+// responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+static inline Result
+ResponseData(Reader& input, Context& context,
+ const der::SignedDataWithSignature& signedResponseData,
+ const DERArray& certs)
+{
+ der::Version version;
+ Result rv = der::OptionalVersion(input, version);
+ if (rv != Success) {
+ return rv;
+ }
+ if (version != der::Version::v1) {
+ // TODO: more specific error code for bad version?
+ return Result::ERROR_BAD_DER;
+ }
+
+ // ResponderID ::= CHOICE {
+ // byName [1] Name,
+ // byKey [2] KeyHash }
+ Input responderID;
+ ResponderIDType responderIDType
+ = input.Peek(static_cast<uint8_t>(ResponderIDType::byName))
+ ? ResponderIDType::byName
+ : ResponderIDType::byKey;
+ rv = der::ExpectTagAndGetValue(input, static_cast<uint8_t>(responderIDType),
+ responderID);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // This is the soonest we can verify the signature. We verify the signature
+ // right away to follow the principal of minimizing the processing of data
+ // before verifying its signature.
+ rv = VerifySignature(context, responderIDType, responderID, certs,
+ signedResponseData);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // TODO: Do we even need to parse this? Should we just skip it?
+ Time producedAt(Time::uninitialized);
+ rv = der::GeneralizedTime(input, producedAt);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // We don't accept an empty sequence of responses. In practice, a legit OCSP
+ // responder will never return an empty response, and handling the case of an
+ // empty response makes things unnecessarily complicated.
+ rv = der::NestedOf(input, der::SEQUENCE, der::SEQUENCE,
+ der::EmptyAllowed::No, [&context](Reader& r) {
+ return SingleResponse(r, context);
+ });
+ if (rv != Success) {
+ return rv;
+ }
+
+ return der::OptionalExtensions(input,
+ der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
+ ExtensionNotUnderstood);
+}
+
+// SingleResponse ::= SEQUENCE {
+// certID CertID,
+// certStatus CertStatus,
+// thisUpdate GeneralizedTime,
+// nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+// singleExtensions [1] EXPLICIT Extensions{{re-ocsp-crl |
+// re-ocsp-archive-cutoff |
+// CrlEntryExtensions, ...}
+// } OPTIONAL }
+static inline Result
+SingleResponse(Reader& input, Context& context)
+{
+ bool match = false;
+ Result rv = der::Nested(input, der::SEQUENCE, [&context, &match](Reader& r) {
+ return MatchCertID(r, context, match);
+ });
+ if (rv != Success) {
+ return rv;
+ }
+
+ if (!match) {
+ // This response does not reference the certificate we're interested in.
+ // By consuming the rest of our input and returning successfully, we can
+ // continue processing and examine another response that might have what
+ // we want.
+ input.SkipToEnd();
+ return Success;
+ }
+
+ // We found a response for the cert we're interested in.
+ context.matchFound = true;
+
+ // CertStatus ::= CHOICE {
+ // good [0] IMPLICIT NULL,
+ // revoked [1] IMPLICIT RevokedInfo,
+ // unknown [2] IMPLICIT UnknownInfo }
+ //
+ // In the event of multiple SingleResponses for a cert that have conflicting
+ // statuses, we use the following precedence rules:
+ //
+ // * revoked overrides good and unknown
+ // * good overrides unknown
+ if (input.Peek(static_cast<uint8_t>(CertStatus::Good))) {
+ rv = der::ExpectTagAndEmptyValue(input,
+ static_cast<uint8_t>(CertStatus::Good));
+ if (rv != Success) {
+ return rv;
+ }
+ if (context.certStatus != CertStatus::Revoked) {
+ context.certStatus = CertStatus::Good;
+ }
+ } else if (input.Peek(static_cast<uint8_t>(CertStatus::Revoked))) {
+ // We don't need any info from the RevokedInfo structure, so we don't even
+ // parse it. TODO: We should mention issues like this in the explanation of
+ // why we treat invalid OCSP responses equivalently to revoked for OCSP
+ // stapling.
+ rv = der::ExpectTagAndSkipValue(input,
+ static_cast<uint8_t>(CertStatus::Revoked));
+ if (rv != Success) {
+ return rv;
+ }
+ context.certStatus = CertStatus::Revoked;
+ } else {
+ rv = der::ExpectTagAndEmptyValue(input,
+ static_cast<uint8_t>(CertStatus::Unknown));
+ if (rv != Success) {
+ return rv;
+ }
+ }
+
+ // http://tools.ietf.org/html/rfc6960#section-3.2
+ // 5. The time at which the status being indicated is known to be
+ // correct (thisUpdate) is sufficiently recent;
+ // 6. When available, the time at or before which newer information will
+ // be available about the status of the certificate (nextUpdate) is
+ // greater than the current time.
+
+ Time thisUpdate(Time::uninitialized);
+ rv = der::GeneralizedTime(input, thisUpdate);
+ if (rv != Success) {
+ return rv;
+ }
+
+ static const uint64_t SLOP_SECONDS = Time::ONE_DAY_IN_SECONDS;
+
+ Time timePlusSlop(context.time);
+ rv = timePlusSlop.AddSeconds(SLOP_SECONDS);
+ if (rv != Success) {
+ return rv;
+ }
+ if (thisUpdate > timePlusSlop) {
+ return Result::ERROR_OCSP_FUTURE_RESPONSE;
+ }
+
+ Time notAfter(Time::uninitialized);
+ static const uint8_t NEXT_UPDATE_TAG =
+ der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0;
+ if (input.Peek(NEXT_UPDATE_TAG)) {
+ Time nextUpdate(Time::uninitialized);
+ rv = der::Nested(input, NEXT_UPDATE_TAG, [&nextUpdate](Reader& r) {
+ return der::GeneralizedTime(r, nextUpdate);
+ });
+ if (rv != Success) {
+ return rv;
+ }
+
+ if (nextUpdate < thisUpdate) {
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
+ }
+ notAfter = thisUpdate;
+ if (notAfter.AddSeconds(context.maxLifetimeInDays *
+ Time::ONE_DAY_IN_SECONDS) != Success) {
+ // This could only happen if we're dealing with times beyond the year
+ // 10,000AD.
+ return Result::ERROR_OCSP_FUTURE_RESPONSE;
+ }
+ if (nextUpdate <= notAfter) {
+ notAfter = nextUpdate;
+ }
+ } else {
+ // NSS requires all OCSP responses without a nextUpdate to be recent.
+ // Match that stricter behavior.
+ notAfter = thisUpdate;
+ if (notAfter.AddSeconds(Time::ONE_DAY_IN_SECONDS) != Success) {
+ // This could only happen if we're dealing with times beyond the year
+ // 10,000AD.
+ return Result::ERROR_OCSP_FUTURE_RESPONSE;
+ }
+ }
+
+ // Add some slop to hopefully handle clock-skew.
+ Time notAfterPlusSlop(notAfter);
+ rv = notAfterPlusSlop.AddSeconds(SLOP_SECONDS);
+ if (rv != Success) {
+ // This could only happen if we're dealing with times beyond the year
+ // 10,000AD.
+ return Result::ERROR_OCSP_FUTURE_RESPONSE;
+ }
+ if (context.time > notAfterPlusSlop) {
+ context.expired = true;
+ }
+
+ rv = der::OptionalExtensions(
+ input,
+ der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
+ [&context](Reader& extnID, const Input& extnValue, bool critical,
+ /*out*/ bool& understood) {
+ return RememberSingleExtension(context, extnID, extnValue, critical,
+ understood);
+ });
+
+ if (rv != Success) {
+ return rv;
+ }
+
+ if (context.thisUpdate) {
+ *context.thisUpdate = thisUpdate;
+ }
+ if (context.validThrough) {
+ *context.validThrough = notAfterPlusSlop;
+ }
+
+ return Success;
+}
+
+// CertID ::= SEQUENCE {
+// hashAlgorithm AlgorithmIdentifier,
+// issuerNameHash OCTET STRING, -- Hash of issuer's DN
+// issuerKeyHash OCTET STRING, -- Hash of issuer's public key
+// serialNumber CertificateSerialNumber }
+static inline Result
+MatchCertID(Reader& input, const Context& context, /*out*/ bool& match)
+{
+ match = false;
+
+ DigestAlgorithm hashAlgorithm;
+ Result rv = der::DigestAlgorithmIdentifier(input, hashAlgorithm);
+ if (rv != Success) {
+ if (rv == Result::ERROR_INVALID_ALGORITHM) {
+ // Skip entries that are hashed with algorithms we don't support.
+ input.SkipToEnd();
+ return Success;
+ }
+ return rv;
+ }
+
+ Input issuerNameHash;
+ rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, issuerNameHash);
+ if (rv != Success) {
+ return rv;
+ }
+
+ Input issuerKeyHash;
+ rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, issuerKeyHash);
+ if (rv != Success) {
+ return rv;
+ }
+
+ Input serialNumber;
+ rv = der::CertificateSerialNumber(input, serialNumber);
+ if (rv != Success) {
+ return rv;
+ }
+
+ if (!InputsAreEqual(serialNumber, context.certID.serialNumber)) {
+ // This does not reference the certificate we're interested in.
+ // Consume the rest of the input and return successfully to
+ // potentially continue processing other responses.
+ input.SkipToEnd();
+ return Success;
+ }
+
+ // TODO: support SHA-2 hashes.
+
+ if (hashAlgorithm != DigestAlgorithm::sha1) {
+ // Again, not interested in this response. Consume input, return success.
+ input.SkipToEnd();
+ return Success;
+ }
+
+ if (issuerNameHash.GetLength() != SHA1_DIGEST_LENGTH) {
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
+ }
+
+ // From http://tools.ietf.org/html/rfc6960#section-4.1.1:
+ // "The hash shall be calculated over the DER encoding of the
+ // issuer's name field in the certificate being checked."
+ uint8_t hashBuf[SHA1_DIGEST_LENGTH];
+ rv = context.trustDomain.DigestBuf(context.certID.issuer,
+ DigestAlgorithm::sha1, hashBuf,
+ sizeof(hashBuf));
+ if (rv != Success) {
+ return rv;
+ }
+ Input computed(hashBuf);
+ if (!InputsAreEqual(computed, issuerNameHash)) {
+ // Again, not interested in this response. Consume input, return success.
+ input.SkipToEnd();
+ return Success;
+ }
+
+ return MatchKeyHash(context.trustDomain, issuerKeyHash,
+ context.certID.issuerSubjectPublicKeyInfo, match);
+}
+
+// From http://tools.ietf.org/html/rfc6960#section-4.1.1:
+// "The hash shall be calculated over the value (excluding tag and length) of
+// the subject public key field in the issuer's certificate."
+//
+// From http://tools.ietf.org/html/rfc6960#appendix-B.1:
+// KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
+// -- (i.e., the SHA-1 hash of the value of the
+// -- BIT STRING subjectPublicKey [excluding
+// -- the tag, length, and number of unused
+// -- bits] in the responder's certificate)
+static Result
+MatchKeyHash(TrustDomain& trustDomain, Input keyHash,
+ const Input subjectPublicKeyInfo, /*out*/ bool& match)
+{
+ if (keyHash.GetLength() != SHA1_DIGEST_LENGTH) {
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
+ }
+ uint8_t hashBuf[SHA1_DIGEST_LENGTH];
+ Result rv = KeyHash(trustDomain, subjectPublicKeyInfo, hashBuf,
+ sizeof hashBuf);
+ if (rv != Success) {
+ return rv;
+ }
+ Input computed(hashBuf);
+ match = InputsAreEqual(computed, keyHash);
+ return Success;
+}
+
+// TODO(bug 966856): support SHA-2 hashes
+Result
+KeyHash(TrustDomain& trustDomain, const Input subjectPublicKeyInfo,
+ /*out*/ uint8_t* hashBuf, size_t hashBufSize)
+{
+ if (!hashBuf || hashBufSize != SHA1_DIGEST_LENGTH) {
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+
+ // RFC 5280 Section 4.1
+ //
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+
+ Reader spki;
+ Result rv = der::ExpectTagAndGetValueAtEnd(subjectPublicKeyInfo,
+ der::SEQUENCE, spki);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // Skip AlgorithmIdentifier
+ rv = der::ExpectTagAndSkipValue(spki, der::SEQUENCE);
+ if (rv != Success) {
+ return rv;
+ }
+
+ Input subjectPublicKey;
+ rv = der::BitStringWithNoUnusedBits(spki, subjectPublicKey);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = der::End(spki);
+ if (rv != Success) {
+ return rv;
+ }
+
+ return trustDomain.DigestBuf(subjectPublicKey, DigestAlgorithm::sha1,
+ hashBuf, hashBufSize);
+}
+
+Result
+ExtensionNotUnderstood(Reader& /*extnID*/, Input /*extnValue*/,
+ bool /*critical*/, /*out*/ bool& understood)
+{
+ understood = false;
+ return Success;
+}
+
+Result
+RememberSingleExtension(Context& context, Reader& extnID, Input extnValue,
+ bool /*critical*/, /*out*/ bool& understood)
+{
+ understood = false;
+
+ // SingleExtension for Signed Certificate Timestamp List.
+ // See Section 3.3 of RFC 6962.
+ // python DottedOIDToCode.py
+ // id_ocsp_singleExtensionSctList 1.3.6.1.4.1.11129.2.4.5
+ static const uint8_t id_ocsp_singleExtensionSctList[] = {
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x05
+ };
+
+ if (extnID.MatchRest(id_ocsp_singleExtensionSctList)) {
+ // Empty values are not allowed for this extension. Note that
+ // we assume this later, when checking if the extension was present.
+ if (extnValue.GetLength() == 0) {
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
+ }
+ if (context.signedCertificateTimestamps.Init(extnValue) != Success) {
+ // Duplicate extension.
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
+ }
+ understood = true;
+ }
+
+ return Success;
+}
+
+// 1. The certificate identified in a received response corresponds to
+// the certificate that was identified in the corresponding request;
+// 2. The signature on the response is valid;
+// 3. The identity of the signer matches the intended recipient of the
+// request;
+// 4. The signer is currently authorized to provide a response for the
+// certificate in question;
+// 5. The time at which the status being indicated is known to be
+// correct (thisUpdate) is sufficiently recent;
+// 6. When available, the time at or before which newer information will
+// be available about the status of the certificate (nextUpdate) is
+// greater than the current time.
+//
+// Responses whose nextUpdate value is earlier than
+// the local system time value SHOULD be considered unreliable.
+// Responses whose thisUpdate time is later than the local system time
+// SHOULD be considered unreliable.
+//
+// If nextUpdate is not set, the responder is indicating that newer
+// revocation information is available all the time.
+//
+// http://tools.ietf.org/html/rfc5019#section-4
+
+Result
+CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID,
+ /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH],
+ /*out*/ size_t& outLen)
+{
+ // We do not add any extensions to the request.
+
+ // RFC 6960 says "An OCSP client MAY wish to specify the kinds of response
+ // types it understands. To do so, it SHOULD use an extension with the OID
+ // id-pkix-ocsp-response." This use of MAY and SHOULD is unclear. MSIE11
+ // on Windows 8.1 does not include any extensions, whereas NSS has always
+ // included the id-pkix-ocsp-response extension. Avoiding the sending the
+ // extension is better for OCSP GET because it makes the request smaller,
+ // and thus more likely to fit within the 255 byte limit for OCSP GET that
+ // is specified in RFC 5019 Section 5.
+
+ // Bug 966856: Add the id-pkix-ocsp-pref-sig-algs extension.
+
+ // Since we don't know whether the OCSP responder supports anything other
+ // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and
+ // issuerKeyHash.
+ static const uint8_t hashAlgorithm[11] = {
+ 0x30, 0x09, // SEQUENCE
+ 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJECT IDENTIFIER id-sha1
+ 0x05, 0x00, // NULL
+ };
+ static const uint8_t hashLen = 160 / 8;
+
+ static const unsigned int totalLenWithoutSerialNumberData
+ = 2 // OCSPRequest
+ + 2 // tbsRequest
+ + 2 // requestList
+ + 2 // Request
+ + 2 // reqCert (CertID)
+ + sizeof(hashAlgorithm) // hashAlgorithm
+ + 2 + hashLen // issuerNameHash
+ + 2 + hashLen // issuerKeyHash
+ + 2; // serialNumber (header)
+
+ // The only way we could have a request this large is if the serialNumber was
+ // ridiculously and unreasonably large. RFC 5280 says "Conforming CAs MUST
+ // NOT use serialNumber values longer than 20 octets." With this restriction,
+ // we allow for some amount of non-conformance with that requirement while
+ // still ensuring we can encode the length values in the ASN.1 TLV structures
+ // in a single byte.
+ static_assert(totalLenWithoutSerialNumberData < OCSP_REQUEST_MAX_LENGTH,
+ "totalLenWithoutSerialNumberData too big");
+ if (certID.serialNumber.GetLength() >
+ OCSP_REQUEST_MAX_LENGTH - totalLenWithoutSerialNumberData) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ outLen = totalLenWithoutSerialNumberData + certID.serialNumber.GetLength();
+
+ uint8_t totalLen = static_cast<uint8_t>(outLen);
+
+ uint8_t* d = out;
+ *d++ = 0x30; *d++ = totalLen - 2u; // OCSPRequest (SEQUENCE)
+ *d++ = 0x30; *d++ = totalLen - 4u; // tbsRequest (SEQUENCE)
+ *d++ = 0x30; *d++ = totalLen - 6u; // requestList (SEQUENCE OF)
+ *d++ = 0x30; *d++ = totalLen - 8u; // Request (SEQUENCE)
+ *d++ = 0x30; *d++ = totalLen - 10u; // reqCert (CertID SEQUENCE)
+
+ // reqCert.hashAlgorithm
+ for (const uint8_t hashAlgorithmByte : hashAlgorithm) {
+ *d++ = hashAlgorithmByte;
+ }
+
+ // reqCert.issuerNameHash (OCTET STRING)
+ *d++ = 0x04;
+ *d++ = hashLen;
+ Result rv = trustDomain.DigestBuf(certID.issuer, DigestAlgorithm::sha1, d,
+ hashLen);
+ if (rv != Success) {
+ return rv;
+ }
+ d += hashLen;
+
+ // reqCert.issuerKeyHash (OCTET STRING)
+ *d++ = 0x04;
+ *d++ = hashLen;
+ rv = KeyHash(trustDomain, certID.issuerSubjectPublicKeyInfo, d, hashLen);
+ if (rv != Success) {
+ return rv;
+ }
+ d += hashLen;
+
+ // reqCert.serialNumber (INTEGER)
+ *d++ = 0x02; // INTEGER
+ *d++ = static_cast<uint8_t>(certID.serialNumber.GetLength());
+ Reader serialNumber(certID.serialNumber);
+ do {
+ rv = serialNumber.Read(*d);
+ if (rv != Success) {
+ return rv;
+ }
+ ++d;
+ } while (!serialNumber.AtEnd());
+
+ assert(d == out + totalLen);
+
+ return Success;
+}
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/lib/pkixresult.cpp b/security/nss/lib/mozpkix/lib/pkixresult.cpp
new file mode 100644
index 000000000..871d9a0fe
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixresult.cpp
@@ -0,0 +1,46 @@
+/*- *- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/Result.h"
+#include "mozpkix/pkixutil.h"
+
+namespace mozilla { namespace pkix {
+
+const char*
+MapResultToName(Result result)
+{
+ switch (result)
+ {
+#define MOZILLA_PKIX_MAP(mozilla_pkix_result, value, nss_result) \
+ case Result::mozilla_pkix_result: return "Result::" #mozilla_pkix_result;
+
+ MOZILLA_PKIX_MAP_LIST
+
+#undef MOZILLA_PKIX_MAP
+
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+}
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/lib/pkixtime.cpp b/security/nss/lib/mozpkix/lib/pkixtime.cpp
new file mode 100644
index 000000000..38e063804
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixtime.cpp
@@ -0,0 +1,78 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2014 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/Time.h"
+#include "mozpkix/pkixutil.h"
+
+#ifdef _WINDOWS
+#ifdef _MSC_VER
+#pragma warning(push, 3)
+#endif
+#include "windows.h"
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+#else
+#include "sys/time.h"
+#endif
+
+namespace mozilla { namespace pkix {
+
+Time
+Now()
+{
+ uint64_t seconds;
+
+#ifdef _WINDOWS
+ // "Contains a 64-bit value representing the number of 100-nanosecond
+ // intervals since January 1, 1601 (UTC)."
+ // - http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ uint64_t ft64 = (static_cast<uint64_t>(ft.dwHighDateTime) << 32) |
+ ft.dwLowDateTime;
+ seconds = (DaysBeforeYear(1601) * Time::ONE_DAY_IN_SECONDS) +
+ ft64 / (1000u * 1000u * 1000u / 100u);
+#else
+ // "The gettimeofday() function shall obtain the current time, expressed as
+ // seconds and microseconds since the Epoch."
+ // - http://pubs.opengroup.org/onlinepubs/009695399/functions/gettimeofday.html
+ timeval tv;
+ (void) gettimeofday(&tv, nullptr);
+ seconds = (DaysBeforeYear(1970) * Time::ONE_DAY_IN_SECONDS) +
+ static_cast<uint64_t>(tv.tv_sec);
+#endif
+
+ return TimeFromElapsedSecondsAD(seconds);
+}
+
+Time
+TimeFromEpochInSeconds(uint64_t secondsSinceEpoch)
+{
+ uint64_t seconds = (DaysBeforeYear(1970) * Time::ONE_DAY_IN_SECONDS) +
+ secondsSinceEpoch;
+ return TimeFromElapsedSecondsAD(seconds);
+}
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/lib/pkixverify.cpp b/security/nss/lib/mozpkix/lib/pkixverify.cpp
new file mode 100644
index 000000000..8ceb2c184
--- /dev/null
+++ b/security/nss/lib/mozpkix/lib/pkixverify.cpp
@@ -0,0 +1,106 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2015 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/pkixutil.h"
+
+namespace mozilla { namespace pkix {
+
+Result
+DigestSignedData(TrustDomain& trustDomain,
+ const der::SignedDataWithSignature& signedData,
+ /*out*/ uint8_t(&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES],
+ /*out*/ der::PublicKeyAlgorithm& publicKeyAlg,
+ /*out*/ SignedDigest& signedDigest)
+{
+ Reader signatureAlg(signedData.algorithm);
+ Result rv = der::SignatureAlgorithmIdentifierValue(
+ signatureAlg, publicKeyAlg, signedDigest.digestAlgorithm);
+ if (rv != Success) {
+ return rv;
+ }
+ if (!signatureAlg.AtEnd()) {
+ return Result::ERROR_BAD_DER;
+ }
+
+ size_t digestLen;
+ switch (signedDigest.digestAlgorithm) {
+ case DigestAlgorithm::sha512: digestLen = 512 / 8; break;
+ case DigestAlgorithm::sha384: digestLen = 384 / 8; break;
+ case DigestAlgorithm::sha256: digestLen = 256 / 8; break;
+ case DigestAlgorithm::sha1: digestLen = 160 / 8; break;
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+ assert(digestLen <= sizeof(digestBuf));
+
+ rv = trustDomain.DigestBuf(signedData.data, signedDigest.digestAlgorithm,
+ digestBuf, digestLen);
+ if (rv != Success) {
+ return rv;
+ }
+ rv = signedDigest.digest.Init(digestBuf, digestLen);
+ if (rv != Success) {
+ return rv;
+ }
+
+ return signedDigest.signature.Init(signedData.signature);
+}
+
+Result
+VerifySignedDigest(TrustDomain& trustDomain,
+ der::PublicKeyAlgorithm publicKeyAlg,
+ const SignedDigest& signedDigest,
+ Input signerSubjectPublicKeyInfo)
+{
+ switch (publicKeyAlg) {
+ case der::PublicKeyAlgorithm::ECDSA:
+ return trustDomain.VerifyECDSASignedDigest(signedDigest,
+ signerSubjectPublicKeyInfo);
+ case der::PublicKeyAlgorithm::RSA_PKCS1:
+ return trustDomain.VerifyRSAPKCS1SignedDigest(signedDigest,
+ signerSubjectPublicKeyInfo);
+ case der::PublicKeyAlgorithm::Uninitialized:
+ assert(false);
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+}
+
+Result
+VerifySignedData(TrustDomain& trustDomain,
+ const der::SignedDataWithSignature& signedData,
+ Input signerSubjectPublicKeyInfo)
+{
+ uint8_t digestBuf[MAX_DIGEST_SIZE_IN_BYTES];
+ der::PublicKeyAlgorithm publicKeyAlg;
+ SignedDigest signedDigest;
+ Result rv = DigestSignedData(trustDomain, signedData, digestBuf,
+ publicKeyAlg, signedDigest);
+ if (rv != Success) {
+ return rv;
+ }
+ return VerifySignedDigest(trustDomain, publicKeyAlg, signedDigest,
+ signerSubjectPublicKeyInfo);
+}
+
+} } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/mozpkix.gyp b/security/nss/lib/mozpkix/mozpkix.gyp
new file mode 100644
index 000000000..1c552ba5f
--- /dev/null
+++ b/security/nss/lib/mozpkix/mozpkix.gyp
@@ -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/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'mozpkix',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+ 'sources': [
+ 'lib/pkixbuild.cpp',
+ 'lib/pkixcert.cpp',
+ 'lib/pkixcheck.cpp',
+ 'lib/pkixder.cpp',
+ 'lib/pkixnames.cpp',
+ 'lib/pkixnss.cpp',
+ 'lib/pkixocsp.cpp',
+ 'lib/pkixresult.cpp',
+ 'lib/pkixtime.cpp',
+ 'lib/pkixverify.cpp',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_mozpkix_exports',
+ ],
+ 'conditions': [
+ [ 'mozpkix_only==0', {
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'mozpkix-testlib',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+ 'sources': [
+ 'test-lib/pkixtestalg.cpp',
+ 'test-lib/pkixtestnss.cpp',
+ 'test-lib/pkixtestutil.cpp',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_mozpkix_exports',
+ ],
+ 'conditions': [
+ [ 'mozpkix_only==0', {
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ],
+ }],
+ ],
+ },
+ ],
+ 'variables': {
+ 'module': 'nss',
+ }
+}
diff --git a/security/nss/lib/mozpkix/test-lib/pkixtestalg.cpp b/security/nss/lib/mozpkix/test-lib/pkixtestalg.cpp
new file mode 100644
index 000000000..304641e2f
--- /dev/null
+++ b/security/nss/lib/mozpkix/test-lib/pkixtestalg.cpp
@@ -0,0 +1,211 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2015 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/test/pkixtestutil.h"
+
+#include "mozpkix/pkixder.h"
+#include "mozpkix/nss_scoped_ptrs.h"
+
+// python DottedOIDToCode.py --prefixdefine PREFIX_1_2_840_10040 1.2.840.10040
+#define PREFIX_1_2_840_10040 0x2a, 0x86, 0x48, 0xce, 0x38
+
+// python DottedOIDToCode.py --prefixdefine PREFIX_1_2_840_10045 1.2.840.10045
+#define PREFIX_1_2_840_10045 0x2a, 0x86, 0x48, 0xce, 0x3d
+
+// python DottedOIDToCode.py --prefixdefine PREFIX_1_2_840_113549 1.2.840.113549
+#define PREFIX_1_2_840_113549 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d
+
+namespace mozilla { namespace pkix { namespace test {
+
+namespace {
+
+enum class NULLParam { NO, YES };
+
+template <size_t SIZE>
+ByteString
+OID(const uint8_t (&rawValue)[SIZE])
+{
+ return TLV(der::OIDTag, ByteString(rawValue, SIZE));
+}
+
+template <size_t SIZE>
+ByteString
+SimpleAlgID(const uint8_t (&rawValue)[SIZE],
+ NULLParam nullParam = NULLParam::NO)
+{
+ ByteString sequenceValue(OID(rawValue));
+ if (nullParam == NULLParam::YES) {
+ sequenceValue.append(TLV(der::NULLTag, ByteString()));
+ }
+ return TLV(der::SEQUENCE, sequenceValue);
+}
+
+template <size_t SIZE>
+ByteString
+DERInteger(const uint8_t (&rawValue)[SIZE])
+{
+ ByteString value(rawValue, SIZE);
+ if (value[0] & 0x80u) {
+ // Prefix with a leading zero to disambiguate this from a negative value.
+ value.insert(value.begin(), 0x00);
+ }
+ return TLV(der::INTEGER, value);
+}
+
+// Generated with "openssl dsaparam -C -noout 2048" and reformatted.
+// openssl 1.0 or later must be used so that a 256-bit Q value is
+// generated.
+static const uint8_t DSS_P_RAW[] =
+{
+ 0xB3,0xCD,0x29,0x44,0xF0,0x25,0xA7,0x73,0xFC,0x86,0x70,0xA2,
+ 0x69,0x5A,0x97,0x3F,0xBD,0x1C,0x6F,0xAA,0x4A,0x40,0x42,0x8E,
+ 0xCF,0xAE,0x62,0x12,0xED,0xB4,0xFD,0x05,0xC2,0xAE,0xB1,0x8C,
+ 0xFC,0xBE,0x38,0x90,0xBB,0x7C,0xFF,0x16,0xF4,0xED,0xCE,0x72,
+ 0x12,0x93,0x83,0xF0,0xA4,0xA1,0x71,0xDC,0x4B,0xF0,0x4E,0x3A,
+ 0x2B,0xFA,0x17,0xB7,0xB3,0x2A,0xCC,0x2C,0xD3,0xC8,0x21,0x49,
+ 0x7A,0x83,0x71,0x8B,0x3D,0x62,0x96,0xDC,0xAD,0xA8,0x03,0xBE,
+ 0x1D,0x33,0x11,0xF3,0xEB,0xD8,0x1B,0x8D,0xDB,0x62,0x79,0x83,
+ 0xF8,0x67,0x4E,0x62,0x21,0x2C,0x81,0x59,0xE8,0x73,0xD7,0xAF,
+ 0xB9,0x63,0x60,0xEA,0xAE,0xEC,0x68,0x6A,0xB4,0xB0,0x65,0xBA,
+ 0xA3,0x4C,0x09,0x99,0x29,0x6A,0x2E,0x2B,0xFC,0x6D,0x51,0xCA,
+ 0x30,0xA2,0x2F,0x7A,0x65,0x76,0xA7,0x55,0x13,0x11,0xA0,0x02,
+ 0xA2,0x59,0x4B,0xCE,0xA7,0x05,0xF6,0x07,0x35,0x9B,0x41,0xD7,
+ 0x11,0x5A,0x18,0x57,0xA7,0x78,0x88,0xC3,0xA8,0xE3,0x39,0xF5,
+ 0x47,0x3D,0x2E,0x18,0x54,0xB0,0xF0,0xBF,0x65,0x3F,0x77,0xC7,
+ 0x11,0xB8,0x0D,0x52,0xAD,0xC8,0xE8,0x6D,0xF6,0x7E,0x88,0x65,
+ 0x84,0x2B,0xF7,0xEF,0x8E,0xB5,0x7C,0xBD,0x2E,0x0D,0xF3,0xC6,
+ 0xDD,0x0B,0xB4,0xF2,0x23,0x1F,0xDA,0x55,0x05,0xF5,0xDC,0x53,
+ 0xA6,0x83,0xDA,0x5C,0xEF,0x29,0x02,0x78,0x68,0xD0,0xA4,0x39,
+ 0x09,0x7F,0xFA,0x49,0x18,0xD0,0xB5,0x19,0x35,0x31,0x8E,0xDE,
+ 0x43,0x35,0xA3,0xB9,0x6D,0xC1,0x70,0xC6,0x0D,0x18,0x24,0xEB,
+ 0x1E,0x4D,0x52,0xB7,
+};
+
+static const uint8_t DSS_Q_RAW[] =
+{
+ 0x8D,0x6B,0x86,0x89,0x9C,0x8D,0x30,0x91,0xCC,0x6E,0x34,0xF1,
+ 0xE8,0x9C,0x8A,0x5C,0xD6,0xAB,0x01,0x1E,0xC4,0xDB,0xFD,0x07,
+ 0xEB,0x5F,0x4E,0xE8,0xFA,0xFC,0x98,0x2D,
+};
+
+static const uint8_t DSS_G_RAW[] =
+{
+ 0x0E,0x2C,0x34,0xB2,0xE1,0x66,0x49,0xB6,0x9A,0x7D,0x67,0x3E,
+ 0xEE,0x98,0x35,0x18,0x28,0x35,0xFC,0x05,0x36,0x3B,0x94,0xE6,
+ 0x1E,0x1C,0x5B,0x05,0x3E,0x86,0x1B,0xE3,0xED,0xD2,0xE1,0xF3,
+ 0xF7,0xF7,0x60,0x6D,0x7D,0xA1,0xAF,0x9A,0xD1,0xDF,0xA2,0x9C,
+ 0xFC,0xA2,0xEB,0x90,0x8B,0x1C,0x82,0x92,0x45,0x7B,0x30,0x2A,
+ 0xFD,0x7A,0xE6,0x68,0x8F,0xEC,0x89,0x3A,0x9A,0xAD,0xFE,0x25,
+ 0x5E,0x51,0xC5,0x29,0x45,0x7F,0xAC,0xDE,0xFC,0xB4,0x1B,0x3A,
+ 0xDA,0xC7,0x21,0x68,0x87,0x27,0x8D,0x7B,0xB2,0xBB,0x41,0x60,
+ 0x46,0x42,0x5B,0x6B,0xE8,0x80,0xD2,0xE4,0xA3,0x30,0x8F,0xD5,
+ 0x71,0x07,0x8A,0x7B,0x32,0x56,0x84,0x41,0x1C,0xDF,0x69,0xE9,
+ 0xFD,0xBA,0x48,0xE0,0x43,0xA0,0x38,0x92,0x12,0xF3,0x52,0xA5,
+ 0x40,0x87,0xCB,0x34,0xBB,0x3E,0x25,0x29,0x3C,0xC6,0xA5,0x17,
+ 0xFD,0x58,0x47,0x89,0xDB,0x9B,0xB9,0xCF,0xE9,0xA8,0xF2,0xEC,
+ 0x55,0x76,0xF5,0xF1,0x9C,0x6E,0x0A,0x3F,0x16,0x5F,0x49,0x31,
+ 0x31,0x1C,0x43,0xA2,0x83,0xDA,0xDD,0x7F,0x1C,0xEA,0x05,0x36,
+ 0x7B,0xED,0x09,0xFB,0x6F,0x8A,0x2B,0x55,0xB9,0xBC,0x4A,0x8C,
+ 0x28,0xC1,0x4D,0x13,0x6E,0x47,0xF4,0xAD,0x79,0x00,0xE9,0x5A,
+ 0xB6,0xC7,0x73,0x28,0xA9,0x89,0xAD,0xE8,0x6E,0xC6,0x54,0xA5,
+ 0x56,0x2D,0xAA,0x81,0x83,0x9E,0xC1,0x13,0x79,0xA4,0x12,0xE0,
+ 0x76,0x1F,0x25,0x43,0xB6,0xDE,0x56,0xF7,0x52,0xCC,0x07,0xB8,
+ 0x37,0xE2,0x8C,0xC5,0x56,0x8C,0xDD,0x63,0xF5,0xB6,0xA3,0x46,
+ 0x62,0xF6,0x35,0x76,
+};
+
+} // namespace
+
+TestSignatureAlgorithm::TestSignatureAlgorithm(
+ const TestPublicKeyAlgorithm& aPublicKeyAlg,
+ TestDigestAlgorithmID aDigestAlg,
+ const ByteString& aAlgorithmIdentifier,
+ bool aAccepted)
+ : publicKeyAlg(aPublicKeyAlg)
+ , digestAlg(aDigestAlg)
+ , algorithmIdentifier(aAlgorithmIdentifier)
+ , accepted(aAccepted)
+{
+}
+
+ByteString DSS_P() { return ByteString(DSS_P_RAW, sizeof(DSS_P_RAW)); }
+ByteString DSS_Q() { return ByteString(DSS_Q_RAW, sizeof(DSS_Q_RAW)); }
+ByteString DSS_G() { return ByteString(DSS_G_RAW, sizeof(DSS_G_RAW)); }
+
+TestPublicKeyAlgorithm
+DSS()
+{
+ static const uint8_t oidValue[] = { PREFIX_1_2_840_10040, 4, 1 };
+
+ // RFC 3279 Section-2.3.2
+ return TestPublicKeyAlgorithm(
+ TLV(der::SEQUENCE,
+ OID(oidValue) +
+ TLV(der::SEQUENCE,
+ DERInteger(DSS_P_RAW) +
+ DERInteger(DSS_Q_RAW) +
+ DERInteger(DSS_G_RAW))));
+}
+
+// RFC 3279 Section 2.3.1
+TestPublicKeyAlgorithm
+RSA_PKCS1()
+{
+ static const uint8_t rsaEncryption[] = { PREFIX_1_2_840_113549, 1, 1, 1 };
+ return TestPublicKeyAlgorithm(SimpleAlgID(rsaEncryption, NULLParam::YES));
+}
+
+// RFC 3279 Section 2.2.1
+TestSignatureAlgorithm md2WithRSAEncryption()
+{
+ static const uint8_t oidValue[] = { PREFIX_1_2_840_113549, 1, 1, 2 };
+ return TestSignatureAlgorithm(RSA_PKCS1(), TestDigestAlgorithmID::MD2,
+ SimpleAlgID(oidValue), false);
+}
+
+// RFC 3279 Section 2.2.1
+TestSignatureAlgorithm md5WithRSAEncryption()
+{
+ static const uint8_t oidValue[] = { PREFIX_1_2_840_113549, 1, 1, 4 };
+ return TestSignatureAlgorithm(RSA_PKCS1(), TestDigestAlgorithmID::MD5,
+ SimpleAlgID(oidValue), false);
+}
+
+// RFC 3279 Section 2.2.1
+TestSignatureAlgorithm sha1WithRSAEncryption()
+{
+ static const uint8_t oidValue[] = { PREFIX_1_2_840_113549, 1, 1, 5 };
+ return TestSignatureAlgorithm(RSA_PKCS1(), TestDigestAlgorithmID::SHA1,
+ SimpleAlgID(oidValue), true);
+}
+
+// RFC 4055 Section 5
+TestSignatureAlgorithm sha256WithRSAEncryption()
+{
+ static const uint8_t oidValue[] = { PREFIX_1_2_840_113549, 1, 1, 11 };
+ return TestSignatureAlgorithm(RSA_PKCS1(), TestDigestAlgorithmID::SHA256,
+ SimpleAlgID(oidValue), true);
+}
+
+} } } // namespace mozilla::pkix
diff --git a/security/nss/lib/mozpkix/test-lib/pkixtestnss.cpp b/security/nss/lib/mozpkix/test-lib/pkixtestnss.cpp
new file mode 100644
index 000000000..ee59b1d97
--- /dev/null
+++ b/security/nss/lib/mozpkix/test-lib/pkixtestnss.cpp
@@ -0,0 +1,364 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/test/pkixtestutil.h"
+#include "mozpkix/test/pkixtestnss.h"
+
+#include <limits>
+
+#include "cryptohi.h"
+#include "keyhi.h"
+#include "nss.h"
+#include "pk11pqg.h"
+#include "pk11pub.h"
+#include "mozpkix/nss_scoped_ptrs.h"
+#include "mozpkix/pkixnss.h"
+#include "mozpkix/pkixder.h"
+#include "mozpkix/pkixutil.h"
+#include "prinit.h"
+#include "secerr.h"
+#include "secitem.h"
+
+namespace mozilla { namespace pkix { namespace test {
+
+namespace {
+
+TestKeyPair* GenerateKeyPairInner();
+
+void
+InitNSSIfNeeded()
+{
+ if (NSS_NoDB_Init(nullptr) != SECSuccess) {
+ abort();
+ }
+}
+
+static ScopedTestKeyPair reusedKeyPair;
+
+PRStatus
+InitReusedKeyPair()
+{
+ InitNSSIfNeeded();
+ reusedKeyPair.reset(GenerateKeyPairInner());
+ return reusedKeyPair ? PR_SUCCESS : PR_FAILURE;
+}
+
+class NSSTestKeyPair final : public TestKeyPair
+{
+public:
+ NSSTestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg,
+ const ByteString& spk,
+ const ByteString& aEncryptedPrivateKey,
+ const ByteString& aEncryptionAlgorithm,
+ const ByteString& aEncryptionParams)
+ : TestKeyPair(aPublicKeyAlg, spk)
+ , encryptedPrivateKey(aEncryptedPrivateKey)
+ , encryptionAlgorithm(aEncryptionAlgorithm)
+ , encryptionParams(aEncryptionParams)
+ {
+ }
+
+ Result SignData(const ByteString& tbs,
+ const TestSignatureAlgorithm& signatureAlgorithm,
+ /*out*/ ByteString& signature) const override
+ {
+ SECOidTag oidTag;
+ if (signatureAlgorithm.publicKeyAlg == RSA_PKCS1()) {
+ switch (signatureAlgorithm.digestAlg) {
+ case TestDigestAlgorithmID::MD2:
+ oidTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
+ break;
+ case TestDigestAlgorithmID::MD5:
+ oidTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
+ break;
+ case TestDigestAlgorithmID::SHA1:
+ oidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+ break;
+ case TestDigestAlgorithmID::SHA224:
+ oidTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION;
+ break;
+ case TestDigestAlgorithmID::SHA256:
+ oidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
+ break;
+ case TestDigestAlgorithmID::SHA384:
+ oidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
+ break;
+ case TestDigestAlgorithmID::SHA512:
+ oidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
+ break;
+ MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
+ }
+ } else {
+ abort();
+ }
+
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ if (!slot) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ SECItem encryptedPrivateKeyInfoItem = {
+ siBuffer,
+ const_cast<uint8_t*>(encryptedPrivateKey.data()),
+ static_cast<unsigned int>(encryptedPrivateKey.length())
+ };
+ SECItem encryptionAlgorithmItem = {
+ siBuffer,
+ const_cast<uint8_t*>(encryptionAlgorithm.data()),
+ static_cast<unsigned int>(encryptionAlgorithm.length())
+ };
+ SECItem encryptionParamsItem = {
+ siBuffer,
+ const_cast<uint8_t*>(encryptionParams.data()),
+ static_cast<unsigned int>(encryptionParams.length())
+ };
+ SECKEYEncryptedPrivateKeyInfo encryptedPrivateKeyInfo = {
+ nullptr,
+ { encryptionAlgorithmItem, encryptionParamsItem },
+ encryptedPrivateKeyInfoItem
+ };
+ SECItem passwordItem = { siBuffer, nullptr, 0 };
+ SECItem publicValueItem = {
+ siBuffer,
+ const_cast<uint8_t*>(subjectPublicKey.data()),
+ static_cast<unsigned int>(subjectPublicKey.length())
+ };
+ SECKEYPrivateKey* privateKey;
+ // This should always be an RSA key (we'll have aborted above if we're not
+ // doing an RSA signature).
+ if (PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
+ slot.get(), &encryptedPrivateKeyInfo, &passwordItem, nullptr,
+ &publicValueItem, false, false, rsaKey, KU_ALL, &privateKey,
+ nullptr) != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ ScopedSECKEYPrivateKey scopedPrivateKey(privateKey);
+ SECItem signatureItem;
+ if (SEC_SignData(&signatureItem, tbs.data(),
+ static_cast<int>(tbs.length()),
+ scopedPrivateKey.get(), oidTag) != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ signature.assign(signatureItem.data, signatureItem.len);
+ SECITEM_FreeItem(&signatureItem, false);
+ return Success;
+ }
+
+ TestKeyPair* Clone() const override
+ {
+ return new (std::nothrow) NSSTestKeyPair(publicKeyAlg,
+ subjectPublicKey,
+ encryptedPrivateKey,
+ encryptionAlgorithm,
+ encryptionParams);
+ }
+
+private:
+ const ByteString encryptedPrivateKey;
+ const ByteString encryptionAlgorithm;
+ const ByteString encryptionParams;
+};
+
+} // namespace
+
+// This private function is also used by Gecko's PSM test framework
+// (OCSPCommon.cpp).
+TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
+ const ScopedSECKEYPublicKey& publicKey,
+ const ScopedSECKEYPrivateKey& privateKey)
+{
+ ScopedCERTSubjectPublicKeyInfo
+ spki(SECKEY_CreateSubjectPublicKeyInfo(publicKey.get()));
+ if (!spki) {
+ return nullptr;
+ }
+ SECItem spkDER = spki->subjectPublicKey;
+ DER_ConvertBitString(&spkDER); // bits to bytes
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ if (!slot) {
+ return nullptr;
+ }
+ // Because NSSTestKeyPair isn't tracked by XPCOM and won't otherwise be aware
+ // of shutdown, we don't have a way to release NSS resources at the
+ // appropriate time. To work around this, NSSTestKeyPair doesn't hold on to
+ // NSS resources. Instead, we export the generated private key part as an
+ // encrypted blob (with an empty password and fairly lame encryption). When we
+ // need to use it (e.g. to sign something), we decrypt it and create a
+ // temporary key object.
+ SECItem passwordItem = { siBuffer, nullptr, 0 };
+ ScopedSECKEYEncryptedPrivateKeyInfo encryptedPrivateKey(
+ PK11_ExportEncryptedPrivKeyInfo(
+ slot.get(), SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
+ &passwordItem, privateKey.get(), 1, nullptr));
+ if (!encryptedPrivateKey) {
+ return nullptr;
+ }
+
+ return new (std::nothrow) NSSTestKeyPair(
+ publicKeyAlg,
+ ByteString(spkDER.data, spkDER.len),
+ ByteString(encryptedPrivateKey->encryptedData.data,
+ encryptedPrivateKey->encryptedData.len),
+ ByteString(encryptedPrivateKey->algorithm.algorithm.data,
+ encryptedPrivateKey->algorithm.algorithm.len),
+ ByteString(encryptedPrivateKey->algorithm.parameters.data,
+ encryptedPrivateKey->algorithm.parameters.len));
+}
+
+namespace {
+
+TestKeyPair*
+GenerateKeyPairInner()
+{
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ if (!slot) {
+ abort();
+ }
+
+ // Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient
+ // entropy to generate a random key. Attempting to add some entropy and
+ // retrying appears to solve this issue.
+ for (uint32_t retries = 0; retries < 10; retries++) {
+ PK11RSAGenParams params;
+ params.keySizeInBits = 2048;
+ params.pe = 3;
+ SECKEYPublicKey* publicKeyTemp = nullptr;
+ ScopedSECKEYPrivateKey
+ privateKey(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
+ &params, &publicKeyTemp, false, true,
+ nullptr));
+ ScopedSECKEYPublicKey publicKey(publicKeyTemp);
+ if (privateKey) {
+ return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
+ }
+
+ assert(!publicKeyTemp);
+
+ if (PR_GetError() != SEC_ERROR_PKCS11_FUNCTION_FAILED) {
+ break;
+ }
+
+ // Since these keys are only for testing, we don't need them to be good,
+ // random keys.
+ // https://xkcd.com/221/
+ static const uint8_t RANDOM_NUMBER[] = { 4, 4, 4, 4, 4, 4, 4, 4 };
+ if (PK11_RandomUpdate((void*) &RANDOM_NUMBER,
+ sizeof(RANDOM_NUMBER)) != SECSuccess) {
+ break;
+ }
+ }
+
+ abort();
+}
+
+} // namespace
+
+TestKeyPair*
+GenerateKeyPair()
+{
+ InitNSSIfNeeded();
+ return GenerateKeyPairInner();
+}
+
+TestKeyPair*
+CloneReusedKeyPair()
+{
+ static PRCallOnceType initCallOnce;
+ if (PR_CallOnce(&initCallOnce, InitReusedKeyPair) != PR_SUCCESS) {
+ abort();
+ }
+ assert(reusedKeyPair);
+ return reusedKeyPair->Clone();
+}
+
+TestKeyPair*
+GenerateDSSKeyPair()
+{
+ InitNSSIfNeeded();
+
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ if (!slot) {
+ return nullptr;
+ }
+
+ ByteString p(DSS_P());
+ ByteString q(DSS_Q());
+ ByteString g(DSS_G());
+
+ static const PQGParams PARAMS = {
+ nullptr,
+ { siBuffer,
+ const_cast<uint8_t*>(p.data()),
+ static_cast<unsigned int>(p.length())
+ },
+ { siBuffer,
+ const_cast<uint8_t*>(q.data()),
+ static_cast<unsigned int>(q.length())
+ },
+ { siBuffer,
+ const_cast<uint8_t*>(g.data()),
+ static_cast<unsigned int>(g.length())
+ }
+ };
+
+ SECKEYPublicKey* publicKeyTemp = nullptr;
+ ScopedSECKEYPrivateKey
+ privateKey(PK11_GenerateKeyPair(slot.get(), CKM_DSA_KEY_PAIR_GEN,
+ const_cast<PQGParams*>(&PARAMS),
+ &publicKeyTemp, false, true, nullptr));
+ if (!privateKey) {
+ return nullptr;
+ }
+ ScopedSECKEYPublicKey publicKey(publicKeyTemp);
+ return CreateTestKeyPair(DSS(), publicKey, privateKey);
+}
+
+Result
+TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
+ Input subjectPublicKeyInfo)
+{
+ InitNSSIfNeeded();
+ return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
+ nullptr);
+}
+
+Result
+TestVerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
+ Input subjectPublicKeyInfo)
+{
+ InitNSSIfNeeded();
+ return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
+ nullptr);
+}
+
+Result
+TestDigestBuf(Input item,
+ DigestAlgorithm digestAlg,
+ /*out*/ uint8_t* digestBuf,
+ size_t digestBufLen)
+{
+ InitNSSIfNeeded();
+ return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
+}
+
+} } } // namespace mozilla::pkix::test
diff --git a/security/nss/lib/mozpkix/test-lib/pkixtestutil.cpp b/security/nss/lib/mozpkix/test-lib/pkixtestutil.cpp
new file mode 100644
index 000000000..b1b89c07e
--- /dev/null
+++ b/security/nss/lib/mozpkix/test-lib/pkixtestutil.cpp
@@ -0,0 +1,1155 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mozpkix/test/pkixtestutil.h"
+
+#include <cerrno>
+#include <cstdio>
+#include <limits>
+#include <new>
+#include <sstream>
+#include <cstdlib>
+
+#include "mozpkix/pkixder.h"
+#include "mozpkix/pkixutil.h"
+
+using namespace std;
+
+namespace mozilla { namespace pkix { namespace test {
+
+namespace {
+
+struct ScopedMaybeDeleteFile {
+ void operator()(FILE* f) {
+ if (f) {
+ (void)fclose(f);
+ }
+ }
+};
+typedef std::unique_ptr<FILE, ScopedMaybeDeleteFile> ScopedFILE;
+
+FILE*
+OpenFile(const string& dir, const string& filename, const string& mode)
+{
+ string path = dir + '/' + filename;
+
+ ScopedFILE file;
+#ifdef _MSC_VER
+ {
+ FILE* rawFile;
+ errno_t error = fopen_s(&rawFile, path.c_str(), mode.c_str());
+ if (error) {
+ // TODO: map error to NSPR error code
+ rawFile = nullptr;
+ }
+ file.reset(rawFile);
+ }
+#else
+ file.reset(fopen(path.c_str(), mode.c_str()));
+#endif
+ return file.release();
+}
+
+} // namespace
+
+bool
+InputEqualsByteString(Input input, const ByteString& bs)
+{
+ Input bsInput;
+ if (bsInput.Init(bs.data(), bs.length()) != Success) {
+ // Init can only fail if it is given a bad pointer or if the input is too
+ // long, which won't ever happen. Plus, if it does, it is ok to call abort
+ // since this is only test code.
+ abort();
+ }
+ return InputsAreEqual(input, bsInput);
+}
+
+ByteString
+InputToByteString(Input input)
+{
+ ByteString result;
+ Reader reader(input);
+ for (;;) {
+ uint8_t b;
+ if (reader.Read(b) != Success) {
+ return result;
+ }
+ result.push_back(b);
+ }
+}
+
+Result
+TamperOnce(/*in/out*/ ByteString& item, const ByteString& from,
+ const ByteString& to)
+{
+ if (from.length() < 8) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+ if (from.length() != to.length()) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+ size_t pos = item.find(from);
+ if (pos == string::npos) {
+ return Result::FATAL_ERROR_INVALID_ARGS; // No matches.
+ }
+ if (item.find(from, pos + from.length()) != string::npos) {
+ return Result::FATAL_ERROR_INVALID_ARGS; // More than once match.
+ }
+ item.replace(pos, from.length(), to);
+ return Success;
+}
+
+// Given a tag and a value, generates a DER-encoded tag-length-value item.
+ByteString
+TLV(uint8_t tag, size_t length, const ByteString& value)
+{
+ ByteString result;
+ result.push_back(tag);
+
+ if (value.length() < 128) {
+ result.push_back(static_cast<uint8_t>(length));
+ } else if (value.length() < 256) {
+ result.push_back(0x81u);
+ result.push_back(static_cast<uint8_t>(length));
+ } else if (value.length() < 65536) {
+ result.push_back(0x82u);
+ result.push_back(static_cast<uint8_t>(length / 256));
+ result.push_back(static_cast<uint8_t>(length % 256));
+ } else {
+ // It is MUCH more convenient for TLV to be infallible than for it to have
+ // "proper" error handling.
+ abort();
+ }
+ result.append(value);
+ return result;
+}
+
+OCSPResponseExtension::OCSPResponseExtension()
+ : id()
+ , critical(false)
+ , value()
+ , next(nullptr)
+{
+}
+
+OCSPResponseContext::OCSPResponseContext(const CertID& aCertID, time_t time)
+ : certID(aCertID)
+ , responseStatus(successful)
+ , skipResponseBytes(false)
+ , producedAt(time)
+ , singleExtensions(nullptr)
+ , responseExtensions(nullptr)
+ , includeEmptyExtensions(false)
+ , signatureAlgorithm(sha256WithRSAEncryption())
+ , badSignature(false)
+ , certs(nullptr)
+
+ , certStatus(good)
+ , revocationTime(0)
+ , thisUpdate(time)
+ , nextUpdate(time + static_cast<time_t>(Time::ONE_DAY_IN_SECONDS))
+ , includeNextUpdate(true)
+{
+}
+
+static ByteString ResponseBytes(OCSPResponseContext& context);
+static ByteString BasicOCSPResponse(OCSPResponseContext& context);
+static ByteString ResponseData(OCSPResponseContext& context);
+static ByteString ResponderID(OCSPResponseContext& context);
+static ByteString KeyHash(const ByteString& subjectPublicKeyInfo);
+static ByteString SingleResponse(OCSPResponseContext& context);
+static ByteString CertID(OCSPResponseContext& context);
+static ByteString CertStatus(OCSPResponseContext& context);
+
+static ByteString
+SHA1(const ByteString& toHash)
+{
+ uint8_t digestBuf[20];
+ Input input;
+ if (input.Init(toHash.data(), toHash.length()) != Success) {
+ abort();
+ }
+ Result rv = TestDigestBuf(input, DigestAlgorithm::sha1, digestBuf,
+ sizeof(digestBuf));
+ if (rv != Success) {
+ abort();
+ }
+ return ByteString(digestBuf, sizeof(digestBuf));
+}
+
+static ByteString
+HashedOctetString(const ByteString& bytes)
+{
+ ByteString digest(SHA1(bytes));
+ if (ENCODING_FAILED(digest)) {
+ return ByteString();
+ }
+ return TLV(der::OCTET_STRING, digest);
+}
+
+static ByteString
+BitString(const ByteString& rawBytes, bool corrupt)
+{
+ ByteString prefixed;
+ // We have to add a byte at the beginning indicating no unused bits.
+ // TODO: add ability to have bit strings of bit length not divisible by 8,
+ // resulting in unused bits in the bitstring encoding
+ prefixed.push_back(0);
+ prefixed.append(rawBytes);
+ if (corrupt) {
+ assert(prefixed.length() > 8);
+ prefixed[8]++;
+ }
+ return TLV(der::BIT_STRING, prefixed);
+}
+
+ByteString
+Boolean(bool value)
+{
+ ByteString encodedValue;
+ encodedValue.push_back(value ? 0xffu : 0x00u);
+ return TLV(der::BOOLEAN, encodedValue);
+}
+
+ByteString
+Integer(long value)
+{
+ if (value < 0 || value > 127) {
+ // TODO: add encoding of larger values
+ // It is MUCH more convenient for Integer to be infallible than for it to
+ // have "proper" error handling.
+ abort();
+ }
+
+ ByteString encodedValue;
+ encodedValue.push_back(static_cast<uint8_t>(value));
+ return TLV(der::INTEGER, encodedValue);
+}
+
+enum TimeEncoding { UTCTime = 0, GeneralizedTime = 1 };
+
+// Windows doesn't provide gmtime_r, but it provides something very similar.
+#if defined(_WINDOWS) && (!defined(_POSIX_C_SOURCE) || !defined(_POSIX_THREAD_SAFE_FUNCTIONS))
+static tm*
+gmtime_r(const time_t* t, /*out*/ tm* exploded)
+{
+ if (gmtime_s(exploded, t) != 0) {
+ return nullptr;
+ }
+ return exploded;
+}
+#endif
+
+// http://tools.ietf.org/html/rfc5280#section-4.1.2.5
+// UTCTime: YYMMDDHHMMSSZ (years 1950-2049 only)
+// GeneralizedTime: YYYYMMDDHHMMSSZ
+//
+// This assumes that time/time_t are POSIX-compliant in that time() returns
+// the number of seconds since the Unix epoch.
+static ByteString
+TimeToEncodedTime(time_t time, TimeEncoding encoding)
+{
+ assert(encoding == UTCTime || encoding == GeneralizedTime);
+
+ tm exploded;
+ if (!gmtime_r(&time, &exploded)) {
+ return ByteString();
+ }
+
+ if (exploded.tm_sec >= 60) {
+ // round down for leap seconds
+ exploded.tm_sec = 59;
+ }
+
+ // exploded.tm_year is the year offset by 1900.
+ int year = exploded.tm_year + 1900;
+
+ if (encoding == UTCTime && (year < 1950 || year >= 2050)) {
+ return ByteString();
+ }
+
+ ByteString value;
+
+ if (encoding == GeneralizedTime) {
+ value.push_back(static_cast<uint8_t>('0' + (year / 1000)));
+ value.push_back(static_cast<uint8_t>('0' + ((year % 1000) / 100)));
+ }
+
+ value.push_back(static_cast<uint8_t>('0' + ((year % 100) / 10)));
+ value.push_back(static_cast<uint8_t>('0' + (year % 10)));
+ value.push_back(static_cast<uint8_t>('0' + ((exploded.tm_mon + 1) / 10)));
+ value.push_back(static_cast<uint8_t>('0' + ((exploded.tm_mon + 1) % 10)));
+ value.push_back(static_cast<uint8_t>('0' + (exploded.tm_mday / 10)));
+ value.push_back(static_cast<uint8_t>('0' + (exploded.tm_mday % 10)));
+ value.push_back(static_cast<uint8_t>('0' + (exploded.tm_hour / 10)));
+ value.push_back(static_cast<uint8_t>('0' + (exploded.tm_hour % 10)));
+ value.push_back(static_cast<uint8_t>('0' + (exploded.tm_min / 10)));
+ value.push_back(static_cast<uint8_t>('0' + (exploded.tm_min % 10)));
+ value.push_back(static_cast<uint8_t>('0' + (exploded.tm_sec / 10)));
+ value.push_back(static_cast<uint8_t>('0' + (exploded.tm_sec % 10)));
+ value.push_back('Z');
+
+ return TLV(encoding == GeneralizedTime ? der::GENERALIZED_TIME : der::UTCTime,
+ value);
+}
+
+static ByteString
+TimeToGeneralizedTime(time_t time)
+{
+ return TimeToEncodedTime(time, GeneralizedTime);
+}
+
+// http://tools.ietf.org/html/rfc5280#section-4.1.2.5: "CAs conforming to this
+// profile MUST always encode certificate validity dates through the year 2049
+// as UTCTime; certificate validity dates in 2050 or later MUST be encoded as
+// GeneralizedTime." (This is a special case of the rule that we must always
+// use the shortest possible encoding.)
+static ByteString
+TimeToTimeChoice(time_t time)
+{
+ tm exploded;
+ if (!gmtime_r(&time, &exploded)) {
+ return ByteString();
+ }
+ TimeEncoding encoding = (exploded.tm_year + 1900 >= 1950 &&
+ exploded.tm_year + 1900 < 2050)
+ ? UTCTime
+ : GeneralizedTime;
+
+ return TimeToEncodedTime(time, encoding);
+}
+
+Time
+YMDHMS(uint16_t year, uint16_t month, uint16_t day,
+ uint16_t hour, uint16_t minutes, uint16_t seconds)
+{
+ assert(year <= 9999);
+ assert(month >= 1);
+ assert(month <= 12);
+ assert(day >= 1);
+ assert(hour < 24);
+ assert(minutes < 60);
+ assert(seconds < 60);
+
+ uint64_t days = DaysBeforeYear(year);
+
+ {
+ static const int16_t DAYS_IN_MONTH[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+
+ int16_t i = 1;
+ for (;;) {
+ int16_t daysInMonth = DAYS_IN_MONTH[i - 1];
+ if (i == 2 &&
+ ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)))) {
+ // Add leap day
+ ++daysInMonth;
+ }
+ if (i == month) {
+ assert(day <= daysInMonth);
+ break;
+ }
+ days += daysInMonth;
+ ++i;
+ }
+ }
+
+ days += (day - 1);
+
+ uint64_t totalSeconds = days * Time::ONE_DAY_IN_SECONDS;
+ totalSeconds += hour * 60 * 60;
+ totalSeconds += minutes * 60;
+ totalSeconds += seconds;
+ return TimeFromElapsedSecondsAD(totalSeconds);
+}
+
+static ByteString
+SignedData(const ByteString& tbsData,
+ const TestKeyPair& keyPair,
+ const TestSignatureAlgorithm& signatureAlgorithm,
+ bool corrupt, /*optional*/ const ByteString* certs)
+{
+ ByteString signature;
+ if (keyPair.SignData(tbsData, signatureAlgorithm, signature) != Success) {
+ return ByteString();
+ }
+
+ // TODO: add ability to have signatures of bit length not divisible by 8,
+ // resulting in unused bits in the bitstring encoding
+ ByteString signatureNested(BitString(signature, corrupt));
+ if (ENCODING_FAILED(signatureNested)) {
+ return ByteString();
+ }
+
+ ByteString certsNested;
+ if (certs) {
+ ByteString certsSequenceValue;
+ while (!(*certs).empty()) {
+ certsSequenceValue.append(*certs);
+ ++certs;
+ }
+ ByteString certsSequence(TLV(der::SEQUENCE, certsSequenceValue));
+ certsNested = TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
+ certsSequence);
+ }
+
+ ByteString value;
+ value.append(tbsData);
+ value.append(signatureAlgorithm.algorithmIdentifier);
+ value.append(signatureNested);
+ value.append(certsNested);
+ return TLV(der::SEQUENCE, value);
+}
+
+// Extension ::= SEQUENCE {
+// extnID OBJECT IDENTIFIER,
+// critical BOOLEAN DEFAULT FALSE,
+// extnValue OCTET STRING
+// -- contains the DER encoding of an ASN.1 value
+// -- corresponding to the extension type identified
+// -- by extnID
+// }
+static ByteString
+Extension(Input extnID, Critical critical, const ByteString& extnValueBytes)
+{
+ ByteString encoded;
+
+ encoded.append(ByteString(extnID.UnsafeGetData(), extnID.GetLength()));
+
+ if (critical == Critical::Yes) {
+ encoded.append(Boolean(true));
+ }
+
+ ByteString extnValueSequence(TLV(der::SEQUENCE, extnValueBytes));
+ ByteString extnValue(TLV(der::OCTET_STRING, extnValueSequence));
+ encoded.append(extnValue);
+ return TLV(der::SEQUENCE, encoded);
+}
+
+static ByteString
+EmptyExtension(Input extnID, Critical critical)
+{
+ ByteString encoded(extnID.UnsafeGetData(), extnID.GetLength());
+
+ if (critical == Critical::Yes) {
+ encoded.append(Boolean(true));
+ }
+
+ ByteString extnValue(TLV(der::OCTET_STRING, ByteString()));
+ encoded.append(extnValue);
+ return TLV(der::SEQUENCE, encoded);
+}
+
+std::string
+GetEnv(const char* name)
+{
+ std::string result;
+
+#ifndef _MSC_VER
+ // XXX: Not thread safe.
+ const char* value = getenv(name);
+ if (value) {
+ result = value;
+ }
+#else
+ char* value = nullptr;
+ size_t valueLength = 0;
+ if (_dupenv_s(&value, &valueLength, name) != 0) {
+ abort();
+ }
+ if (value) {
+ result = value;
+ free(value);
+ }
+#endif
+ return result;
+}
+
+void
+MaybeLogOutput(const ByteString& result, const char* suffix)
+{
+ assert(suffix);
+
+ // This allows us to more easily debug the generated output, by creating a
+ // file in the directory given by MOZILLA_PKIX_TEST_LOG_DIR for each
+ // NOT THREAD-SAFE!!!
+ std::string logPath(GetEnv("MOZILLA_PKIX_TEST_LOG_DIR"));
+ if (!logPath.empty()) {
+ static int counter = 0;
+
+ std::ostringstream counterStream;
+ counterStream << counter;
+ if (!counterStream) {
+ assert(false);
+ return;
+ }
+ string filename = counterStream.str() + '-' + suffix + ".der";
+
+ ++counter;
+ ScopedFILE file(OpenFile(logPath, filename, "wb"));
+ if (file) {
+ (void) fwrite(result.data(), result.length(), 1, file.get());
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Certificates
+
+static ByteString TBSCertificate(long version, const ByteString& serialNumber,
+ const ByteString& signature,
+ const ByteString& issuer,
+ time_t notBefore, time_t notAfter,
+ const ByteString& subject,
+ const ByteString& subjectPublicKeyInfo,
+ /*optional*/ const ByteString* extensions);
+
+// Certificate ::= SEQUENCE {
+// tbsCertificate TBSCertificate,
+// signatureAlgorithm AlgorithmIdentifier,
+// signatureValue BIT STRING }
+ByteString
+CreateEncodedCertificate(long version,
+ const TestSignatureAlgorithm& signature,
+ const ByteString& serialNumber,
+ const ByteString& issuerNameDER,
+ time_t notBefore, time_t notAfter,
+ const ByteString& subjectNameDER,
+ const TestKeyPair& subjectKeyPair,
+ /*optional*/ const ByteString* extensions,
+ const TestKeyPair& issuerKeyPair,
+ const TestSignatureAlgorithm& signatureAlgorithm)
+{
+ ByteString tbsCertificate(TBSCertificate(version, serialNumber,
+ signature.algorithmIdentifier,
+ issuerNameDER, notBefore,
+ notAfter, subjectNameDER,
+ subjectKeyPair.subjectPublicKeyInfo,
+ extensions));
+ if (ENCODING_FAILED(tbsCertificate)) {
+ return ByteString();
+ }
+
+ ByteString result(SignedData(tbsCertificate, issuerKeyPair,
+ signatureAlgorithm, false, nullptr));
+ if (ENCODING_FAILED(result)) {
+ return ByteString();
+ }
+
+ MaybeLogOutput(result, "cert");
+
+ return result;
+}
+
+// TBSCertificate ::= SEQUENCE {
+// version [0] Version DEFAULT v1,
+// serialNumber CertificateSerialNumber,
+// signature AlgorithmIdentifier,
+// issuer Name,
+// validity Validity,
+// subject Name,
+// subjectPublicKeyInfo SubjectPublicKeyInfo,
+// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
+// -- If present, version MUST be v2 or v3
+// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+// -- If present, version MUST be v2 or v3
+// extensions [3] Extensions OPTIONAL
+// -- If present, version MUST be v3 -- }
+static ByteString
+TBSCertificate(long versionValue,
+ const ByteString& serialNumber, const ByteString& signature,
+ const ByteString& issuer, time_t notBeforeTime,
+ time_t notAfterTime, const ByteString& subject,
+ const ByteString& subjectPublicKeyInfo,
+ /*optional*/ const ByteString* extensions)
+{
+ ByteString value;
+
+ if (versionValue != static_cast<long>(der::Version::v1)) {
+ ByteString versionInteger(Integer(versionValue));
+ ByteString version(TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
+ versionInteger));
+ value.append(version);
+ }
+
+ value.append(serialNumber);
+ value.append(signature);
+ value.append(issuer);
+
+ // Validity ::= SEQUENCE {
+ // notBefore Time,
+ // notAfter Time }
+ ByteString validity;
+ {
+ ByteString notBefore(TimeToTimeChoice(notBeforeTime));
+ if (ENCODING_FAILED(notBefore)) {
+ return ByteString();
+ }
+ ByteString notAfter(TimeToTimeChoice(notAfterTime));
+ if (ENCODING_FAILED(notAfter)) {
+ return ByteString();
+ }
+ ByteString validityValue;
+ validityValue.append(notBefore);
+ validityValue.append(notAfter);
+ validity = TLV(der::SEQUENCE, validityValue);
+ if (ENCODING_FAILED(validity)) {
+ return ByteString();
+ }
+ }
+ value.append(validity);
+
+ value.append(subject);
+
+ value.append(subjectPublicKeyInfo);
+
+ if (extensions) {
+ ByteString extensionsValue;
+ while (!(*extensions).empty()) {
+ extensionsValue.append(*extensions);
+ ++extensions;
+ }
+ ByteString extensionsSequence(TLV(der::SEQUENCE, extensionsValue));
+ if (ENCODING_FAILED(extensionsSequence)) {
+ return ByteString();
+ }
+ ByteString extensionsWrapped(
+ TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 3, extensionsSequence));
+ if (ENCODING_FAILED(extensionsWrapped)) {
+ return ByteString();
+ }
+ value.append(extensionsWrapped);
+ }
+
+ return TLV(der::SEQUENCE, value);
+}
+
+// AttributeTypeAndValue ::= SEQUENCE {
+// type AttributeType,
+// value AttributeValue }
+//
+// AttributeType ::= OBJECT IDENTIFIER
+//
+// AttributeValue ::= ANY -- DEFINED BY AttributeType
+//
+// DirectoryString ::= CHOICE {
+// teletexString TeletexString (SIZE (1..MAX)),
+// printableString PrintableString (SIZE (1..MAX)),
+// universalString UniversalString (SIZE (1..MAX)),
+// utf8String UTF8String (SIZE (1..MAX)),
+// bmpString BMPString (SIZE (1..MAX)) }
+template <size_t N>
+static ByteString
+AVA(const uint8_t (&type)[N], uint8_t directoryStringType,
+ const ByteString& value)
+{
+ ByteString wrappedValue(TLV(directoryStringType, value));
+ ByteString ava;
+ ava.append(type, N);
+ ava.append(wrappedValue);
+ return TLV(der::SEQUENCE, ava);
+}
+
+ByteString
+CN(const ByteString& value, uint8_t encodingTag)
+{
+ // id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 }
+ // id-at-commonName AttributeType ::= { id-at 3 }
+ // python DottedOIDToCode.py --tlv id-at-commonName 2.5.4.3
+ static const uint8_t tlv_id_at_commonName[] = {
+ 0x06, 0x03, 0x55, 0x04, 0x03
+ };
+ return AVA(tlv_id_at_commonName, encodingTag, value);
+}
+
+ByteString
+OU(const ByteString& value, uint8_t encodingTag)
+{
+ // id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 }
+ // id-at-organizationalUnitName AttributeType ::= { id-at 11 }
+ // python DottedOIDToCode.py --tlv id-at-organizationalUnitName 2.5.4.11
+ static const uint8_t tlv_id_at_organizationalUnitName[] = {
+ 0x06, 0x03, 0x55, 0x04, 0x0b
+ };
+
+ return AVA(tlv_id_at_organizationalUnitName, encodingTag, value);
+}
+
+ByteString
+emailAddress(const ByteString& value)
+{
+ // id-emailAddress AttributeType ::= { pkcs-9 1 }
+ // python DottedOIDToCode.py --tlv id-emailAddress 1.2.840.113549.1.9.1
+ static const uint8_t tlv_id_emailAddress[] = {
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01
+ };
+
+ return AVA(tlv_id_emailAddress, der::IA5String, value);
+}
+
+// RelativeDistinguishedName ::=
+// SET SIZE (1..MAX) OF AttributeTypeAndValue
+//
+ByteString
+RDN(const ByteString& avas)
+{
+ return TLV(der::SET, avas);
+}
+
+// Name ::= CHOICE { -- only one possibility for now --
+// rdnSequence RDNSequence }
+//
+// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+//
+ByteString
+Name(const ByteString& rdns)
+{
+ return TLV(der::SEQUENCE, rdns);
+}
+
+ByteString
+CreateEncodedSerialNumber(long serialNumberValue)
+{
+ return Integer(serialNumberValue);
+}
+
+// BasicConstraints ::= SEQUENCE {
+// cA BOOLEAN DEFAULT FALSE,
+// pathLenConstraint INTEGER (0..MAX) OPTIONAL }
+ByteString
+CreateEncodedBasicConstraints(bool isCA,
+ /*optional in*/ const long* pathLenConstraintValue,
+ Critical critical)
+{
+ ByteString value;
+
+ if (isCA) {
+ ByteString cA(Boolean(true));
+ value.append(cA);
+ }
+
+ if (pathLenConstraintValue) {
+ ByteString pathLenConstraint(Integer(*pathLenConstraintValue));
+ value.append(pathLenConstraint);
+ }
+
+ // python DottedOIDToCode.py --tlv id-ce-basicConstraints 2.5.29.19
+ static const uint8_t tlv_id_ce_basicConstraints[] = {
+ 0x06, 0x03, 0x55, 0x1d, 0x13
+ };
+ return Extension(Input(tlv_id_ce_basicConstraints), critical, value);
+}
+
+// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+// KeyPurposeId ::= OBJECT IDENTIFIER
+ByteString
+CreateEncodedEKUExtension(Input ekuOID, Critical critical)
+{
+ ByteString value(ekuOID.UnsafeGetData(), ekuOID.GetLength());
+
+ // python DottedOIDToCode.py --tlv id-ce-extKeyUsage 2.5.29.37
+ static const uint8_t tlv_id_ce_extKeyUsage[] = {
+ 0x06, 0x03, 0x55, 0x1d, 0x25
+ };
+
+ return Extension(Input(tlv_id_ce_extKeyUsage), critical, value);
+}
+
+// python DottedOIDToCode.py --tlv id-ce-subjectAltName 2.5.29.17
+static const uint8_t tlv_id_ce_subjectAltName[] = {
+ 0x06, 0x03, 0x55, 0x1d, 0x11
+};
+
+ByteString
+CreateEncodedSubjectAltName(const ByteString& names)
+{
+ return Extension(Input(tlv_id_ce_subjectAltName), Critical::No, names);
+}
+
+ByteString
+CreateEncodedEmptySubjectAltName()
+{
+ return EmptyExtension(Input(tlv_id_ce_subjectAltName), Critical::No);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OCSP responses
+
+ByteString
+CreateEncodedOCSPResponse(OCSPResponseContext& context)
+{
+ if (!context.skipResponseBytes) {
+ if (!context.signerKeyPair) {
+ return ByteString();
+ }
+ }
+
+ // OCSPResponse ::= SEQUENCE {
+ // responseStatus OCSPResponseStatus,
+ // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+
+ // OCSPResponseStatus ::= ENUMERATED {
+ // successful (0), -- Response has valid confirmations
+ // malformedRequest (1), -- Illegal confirmation request
+ // internalError (2), -- Internal error in issuer
+ // tryLater (3), -- Try again later
+ // -- (4) is not used
+ // sigRequired (5), -- Must sign the request
+ // unauthorized (6) -- Request unauthorized
+ // }
+ ByteString reponseStatusValue;
+ reponseStatusValue.push_back(context.responseStatus);
+ ByteString responseStatus(TLV(der::ENUMERATED, reponseStatusValue));
+
+ ByteString responseBytesNested;
+ if (!context.skipResponseBytes) {
+ ByteString responseBytes(ResponseBytes(context));
+ if (ENCODING_FAILED(responseBytes)) {
+ return ByteString();
+ }
+
+ responseBytesNested = TLV(der::CONSTRUCTED | der::CONTEXT_SPECIFIC,
+ responseBytes);
+ }
+
+ ByteString value;
+ value.append(responseStatus);
+ value.append(responseBytesNested);
+ ByteString result(TLV(der::SEQUENCE, value));
+
+ MaybeLogOutput(result, "ocsp");
+
+ return result;
+}
+
+// ResponseBytes ::= SEQUENCE {
+// responseType OBJECT IDENTIFIER,
+// response OCTET STRING }
+ByteString
+ResponseBytes(OCSPResponseContext& context)
+{
+ // Includes tag and length
+ static const uint8_t id_pkix_ocsp_basic_encoded[] = {
+ 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+ };
+ ByteString response(BasicOCSPResponse(context));
+ if (ENCODING_FAILED(response)) {
+ return ByteString();
+ }
+ ByteString responseNested = TLV(der::OCTET_STRING, response);
+
+ ByteString value;
+ value.append(id_pkix_ocsp_basic_encoded,
+ sizeof(id_pkix_ocsp_basic_encoded));
+ value.append(responseNested);
+ return TLV(der::SEQUENCE, value);
+}
+
+// BasicOCSPResponse ::= SEQUENCE {
+// tbsResponseData ResponseData,
+// signatureAlgorithm AlgorithmIdentifier,
+// signature BIT STRING,
+// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ByteString
+BasicOCSPResponse(OCSPResponseContext& context)
+{
+ ByteString tbsResponseData(ResponseData(context));
+ if (ENCODING_FAILED(tbsResponseData)) {
+ return ByteString();
+ }
+
+ return SignedData(tbsResponseData, *context.signerKeyPair,
+ context.signatureAlgorithm, context.badSignature,
+ context.certs);
+}
+
+// Extension ::= SEQUENCE {
+// id OBJECT IDENTIFIER,
+// critical BOOLEAN DEFAULT FALSE
+// value OCTET STRING
+// }
+static ByteString
+OCSPExtension(OCSPResponseExtension& extension)
+{
+ ByteString encoded;
+ encoded.append(extension.id);
+ if (extension.critical) {
+ encoded.append(Boolean(true));
+ }
+ ByteString value(TLV(der::OCTET_STRING, extension.value));
+ encoded.append(value);
+ return TLV(der::SEQUENCE, encoded);
+}
+
+// Extensions ::= [1] {
+// SEQUENCE OF Extension
+// }
+static ByteString
+OCSPExtensions(OCSPResponseExtension* extensions)
+{
+ ByteString value;
+ for (OCSPResponseExtension* extension = extensions;
+ extension; extension = extension->next) {
+ ByteString extensionEncoded(OCSPExtension(*extension));
+ if (ENCODING_FAILED(extensionEncoded)) {
+ return ByteString();
+ }
+ value.append(extensionEncoded);
+ }
+ ByteString sequence(TLV(der::SEQUENCE, value));
+ return TLV(der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1, sequence);
+}
+
+// ResponseData ::= SEQUENCE {
+// version [0] EXPLICIT Version DEFAULT v1,
+// responderID ResponderID,
+// producedAt GeneralizedTime,
+// responses SEQUENCE OF SingleResponse,
+// responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ByteString
+ResponseData(OCSPResponseContext& context)
+{
+ ByteString responderID(ResponderID(context));
+ if (ENCODING_FAILED(responderID)) {
+ return ByteString();
+ }
+ ByteString producedAtEncoded(TimeToGeneralizedTime(context.producedAt));
+ if (ENCODING_FAILED(producedAtEncoded)) {
+ return ByteString();
+ }
+ ByteString response(SingleResponse(context));
+ if (ENCODING_FAILED(response)) {
+ return ByteString();
+ }
+ ByteString responses(TLV(der::SEQUENCE, response));
+ ByteString responseExtensions;
+ if (context.responseExtensions || context.includeEmptyExtensions) {
+ responseExtensions = OCSPExtensions(context.responseExtensions);
+ }
+
+ ByteString value;
+ value.append(responderID);
+ value.append(producedAtEncoded);
+ value.append(responses);
+ value.append(responseExtensions);
+ return TLV(der::SEQUENCE, value);
+}
+
+// ResponderID ::= CHOICE {
+// byName [1] Name,
+// byKey [2] KeyHash }
+// }
+ByteString
+ResponderID(OCSPResponseContext& context)
+{
+ ByteString contents;
+ uint8_t responderIDType;
+ if (!context.signerNameDER.empty()) {
+ contents = context.signerNameDER;
+ responderIDType = 1; // byName
+ } else {
+ contents = KeyHash(context.signerKeyPair->subjectPublicKey);
+ if (ENCODING_FAILED(contents)) {
+ return ByteString();
+ }
+ responderIDType = 2; // byKey
+ }
+
+ // XXX: MSVC 2015 wrongly warns about signed/unsigned conversion without the
+ // static_cast.
+ uint8_t tag = static_cast<uint8_t>(der::CONSTRUCTED | der::CONTEXT_SPECIFIC |
+ responderIDType);
+ return TLV(tag, contents);
+}
+
+// KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
+// -- (i.e., the SHA-1 hash of the value of the
+// -- BIT STRING subjectPublicKey [excluding
+// -- the tag, length, and number of unused
+// -- bits] in the responder's certificate)
+ByteString
+KeyHash(const ByteString& subjectPublicKey)
+{
+ return HashedOctetString(subjectPublicKey);
+}
+
+// SingleResponse ::= SEQUENCE {
+// certID CertID,
+// certStatus CertStatus,
+// thisUpdate GeneralizedTime,
+// nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+// singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ByteString
+SingleResponse(OCSPResponseContext& context)
+{
+ ByteString certID(CertID(context));
+ if (ENCODING_FAILED(certID)) {
+ return ByteString();
+ }
+ ByteString certStatus(CertStatus(context));
+ if (ENCODING_FAILED(certStatus)) {
+ return ByteString();
+ }
+ ByteString thisUpdateEncoded(TimeToGeneralizedTime(context.thisUpdate));
+ if (ENCODING_FAILED(thisUpdateEncoded)) {
+ return ByteString();
+ }
+ ByteString nextUpdateEncodedNested;
+ if (context.includeNextUpdate) {
+ ByteString nextUpdateEncoded(TimeToGeneralizedTime(context.nextUpdate));
+ if (ENCODING_FAILED(nextUpdateEncoded)) {
+ return ByteString();
+ }
+ nextUpdateEncodedNested = TLV(der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
+ nextUpdateEncoded);
+ }
+ ByteString singleExtensions;
+ if (context.singleExtensions || context.includeEmptyExtensions) {
+ singleExtensions = OCSPExtensions(context.singleExtensions);
+ }
+
+ ByteString value;
+ value.append(certID);
+ value.append(certStatus);
+ value.append(thisUpdateEncoded);
+ value.append(nextUpdateEncodedNested);
+ value.append(singleExtensions);
+ return TLV(der::SEQUENCE, value);
+}
+
+// CertID ::= SEQUENCE {
+// hashAlgorithm AlgorithmIdentifier,
+// issuerNameHash OCTET STRING, -- Hash of issuer's DN
+// issuerKeyHash OCTET STRING, -- Hash of issuer's public key
+// serialNumber CertificateSerialNumber }
+ByteString
+CertID(OCSPResponseContext& context)
+{
+ ByteString issuerName(context.certID.issuer.UnsafeGetData(),
+ context.certID.issuer.GetLength());
+ ByteString issuerNameHash(HashedOctetString(issuerName));
+ if (ENCODING_FAILED(issuerNameHash)) {
+ return ByteString();
+ }
+
+ ByteString issuerKeyHash;
+ {
+ // context.certID.issuerSubjectPublicKeyInfo is the entire
+ // SubjectPublicKeyInfo structure, but we need just the subjectPublicKey
+ // part.
+ Reader input(context.certID.issuerSubjectPublicKeyInfo);
+ Reader contents;
+ if (der::ExpectTagAndGetValue(input, der::SEQUENCE, contents) != Success) {
+ return ByteString();
+ }
+ // Skip AlgorithmIdentifier
+ if (der::ExpectTagAndSkipValue(contents, der::SEQUENCE) != Success) {
+ return ByteString();
+ }
+ Input subjectPublicKey;
+ if (der::BitStringWithNoUnusedBits(contents, subjectPublicKey)
+ != Success) {
+ return ByteString();
+ }
+ issuerKeyHash = KeyHash(ByteString(subjectPublicKey.UnsafeGetData(),
+ subjectPublicKey.GetLength()));
+ if (ENCODING_FAILED(issuerKeyHash)) {
+ return ByteString();
+ }
+ }
+
+ ByteString serialNumberValue(context.certID.serialNumber.UnsafeGetData(),
+ context.certID.serialNumber.GetLength());
+ ByteString serialNumber(TLV(der::INTEGER, serialNumberValue));
+
+ // python DottedOIDToCode.py --alg id-sha1 1.3.14.3.2.26
+ static const uint8_t alg_id_sha1[] = {
+ 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a
+ };
+
+ ByteString value;
+ value.append(alg_id_sha1, sizeof(alg_id_sha1));
+ value.append(issuerNameHash);
+ value.append(issuerKeyHash);
+ value.append(serialNumber);
+ return TLV(der::SEQUENCE, value);
+}
+
+// CertStatus ::= CHOICE {
+// good [0] IMPLICIT NULL,
+// revoked [1] IMPLICIT RevokedInfo,
+// unknown [2] IMPLICIT UnknownInfo }
+//
+// RevokedInfo ::= SEQUENCE {
+// revocationTime GeneralizedTime,
+// revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+//
+// UnknownInfo ::= NULL
+//
+ByteString
+CertStatus(OCSPResponseContext& context)
+{
+ switch (context.certStatus) {
+ // Both good and unknown are ultimately represented as NULL - the only
+ // difference is in the tag that identifies them.
+ case 0:
+ case 2:
+ {
+ // XXX: MSVC 2015 wrongly warns about signed/unsigned conversion without
+ // the static cast.
+ return TLV(static_cast<uint8_t>(der::CONTEXT_SPECIFIC |
+ context.certStatus), ByteString());
+ }
+ case 1:
+ {
+ ByteString revocationTime(TimeToGeneralizedTime(context.revocationTime));
+ if (ENCODING_FAILED(revocationTime)) {
+ return ByteString();
+ }
+ // TODO(bug 980536): add support for revocationReason
+ return TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, revocationTime);
+ }
+ default:
+ assert(false);
+ // fall through
+ }
+ return ByteString();
+}
+
+static const ByteString NO_UNUSED_BITS(1, 0x00);
+
+// The SubjectPublicKeyInfo syntax is specified in RFC 5280 Section 4.1.
+TestKeyPair::TestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg,
+ const ByteString& spk)
+ : publicKeyAlg(aPublicKeyAlg)
+ , subjectPublicKeyInfo(TLV(der::SEQUENCE,
+ aPublicKeyAlg.algorithmIdentifier +
+ TLV(der::BIT_STRING, NO_UNUSED_BITS + spk)))
+ , subjectPublicKey(spk)
+{
+}
+
+} } } // namespace mozilla::pkix::test
diff --git a/security/nss/lib/mozpkix/tools/DottedOIDToCode.py b/security/nss/lib/mozpkix/tools/DottedOIDToCode.py
new file mode 100644
index 000000000..dfd4ade07
--- /dev/null
+++ b/security/nss/lib/mozpkix/tools/DottedOIDToCode.py
@@ -0,0 +1,216 @@
+# This code is made available to you under your choice of the following sets
+# of licensing terms:
+###############################################################################
+# 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/.
+###############################################################################
+# Copyright 2013 Mozilla Contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+import argparse
+import itertools
+import sys
+
+
+def base128(value):
+ """
+ Given an integral value, returns an array of the base-128 representation
+ of that value, with all but the last byte having the high bit set as
+ required by the DER rules for the nodes of an OID after the first two
+ bytes.
+
+ >>> base128(1)
+ [1]
+ >>> base128(10045)
+ [206, 61]
+ """
+
+ if value < 0:
+ raise ValueError("An OID must have only positive-value nodes.")
+
+ # least significant byte has highest bit unset
+ result = [value % 0x80]
+ value /= 0x80
+
+ while value != 0:
+ result = [0x80 | (value % 0x80)] + result
+ value /= 0x80
+
+ return result
+
+
+def dottedOIDToEncodedArray(dottedOID):
+ """
+ Takes a dotted OID string (e.g. '1.2.840.10045.4.3.4') as input, and
+ returns an array that contains the DER encoding of its value, without
+ the tag and length (e.g. [0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04]).
+ """
+ nodes = [int(x) for x in dottedOID.strip().split(".")]
+ if len(nodes) < 2:
+ raise ValueError("An OID must have at least two nodes.")
+ if not (0 <= nodes[0] <= 2):
+ raise ValueError("The first node of an OID must be 0, 1, or 2.")
+ if not (0 <= nodes[1] <= 39):
+ # XXX: Does this restriction apply when the first part is 2?
+ raise ValueError("The second node of an OID must be 0-39.")
+ firstByte = (40 * nodes[0]) + nodes[1]
+ restBase128 = [base128(x) for x in nodes[2:]]
+ return [firstByte] + list(itertools.chain.from_iterable(restBase128))
+
+
+def dottedOIDToCArray(dottedOID, mode):
+ """
+ Takes a dotted OID string (e.g. '1.2.840.10045.4.3.4') as input, and
+ returns a string that contains the hex encoding of the OID in C++ literal
+ notation, e.g. '0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04'.
+ """
+ bytes = dottedOIDToEncodedArray(dottedOID)
+
+ if mode != "value" and mode != "prefixdefine":
+ bytes = [0x06, len(bytes)] + bytes
+
+ if mode == "alg":
+ # Wrap the DER-encoded OID in a SEQUENCE to create an
+ # AlgorithmIdentifier with no parameters.
+ bytes = [0x30, len(bytes)] + bytes
+
+ return ", ".join(["0x%.2x" % b for b in bytes])
+
+
+def specNameToCName(specName):
+ """
+ Given an string containing an ASN.1 name, returns a string that is a valid
+ C++ identifier that is as similar to that name as possible. Since most
+ ASN.1 identifiers used in PKIX specifications are legal C++ names except
+ for containing hyphens, this function just converts the hyphens to
+ underscores. This may need to be improved in the future if we encounter
+ names with other funny characters.
+ """
+ return specName.replace("-", "_")
+
+
+def toCode(programName, specName, dottedOID, mode):
+ """
+ Given an ASN.1 name and a string containing the dotted representation of an
+ OID, returns a string that contains a C++ declaration for a named constant
+ that contains that OID value. If mode is "value" then only the value of
+ the OID (without the tag or length) will be included in the output. If mode
+ is "tlv" then the value will be prefixed with the tag and length. If mode
+ is "alg" then the value will be a complete der-encoded AlgorithmIdentifier
+ with no parameters.
+
+ This:
+
+ toCode("DottedOIDToCode.py", "ecdsa-with-SHA512", "1.2.840.10045.4.3.4",
+ "value")
+
+ would result in a string like:
+
+ // python DottedOIDToCode.py ecdsa-with-SHA512 1.2.840.10045.4.3.4
+ static const uint8_t ecdsa_with_SHA512[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
+ };
+
+ This:
+
+ toCode("DottedOIDToCode.py", "ecdsa-with-SHA512", "1.2.840.10045.4.3.4",
+ "tlv")
+
+ would result in a string like:
+
+ // python DottedOIDToCode.py --tlv ecdsa-with-SHA512 1.2.840.10045.4.3.4
+ static const uint8_t tlv_ecdsa_with_SHA512[] = {
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
+ };
+
+ This:
+
+ toCode("DottedOIDToCode.py", "ecdsa-with-SHA512", "1.2.840.10045.4.3.4",
+ "alg")
+
+ would result in a string like:
+
+ // python DottedOIDToCode.py --alg ecdsa-with-SHA512 1.2.840.10045.4.3.4
+ static const uint8_t alg_ecdsa_with_SHA512[] = {
+ 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
+ };
+
+ This:
+
+ toCode("DottedOIDToCode.py", "PREFIX_1_2_840_10045", "1.2.840.10045",
+ "prefixdefine")
+
+ would result in a string like this (note the lack of indention):
+
+ // python DottedOIDToCode.py --prefixdefine PREFIX_1_2_840_10045 1.2.840.10045
+ #define PREFIX_1_2_840_10045 0x2a, 0x86, 0x48, 0xce, 0x3d
+ """
+ programNameWithOptions = programName
+
+ if mode == "prefixdefine":
+ programNameWithOptions += " --prefixdefine"
+ varName = specName
+ return ("// python %s %s %s\n" +
+ "#define %s %s\n") % (programNameWithOptions, specName,
+ dottedOID, varName,
+ dottedOIDToCArray(dottedOID, mode))
+
+ varName = specNameToCName(specName)
+ if mode == "tlv":
+ programNameWithOptions += " --tlv"
+ varName = "tlv_" + varName
+ elif mode == "alg":
+ programNameWithOptions += " --alg"
+ varName = "alg_" + varName
+ elif mode == "prefixdefine":
+ programNameWithOptions += " --alg"
+ varName = varName
+
+ return (" // python %s %s %s\n" +
+ " static const uint8_t %s[] = {\n" +
+ " %s\n" +
+ " };\n") % (programNameWithOptions, specName, dottedOID, varName,
+ dottedOIDToCArray(dottedOID, mode))
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="Generate code snippets to handle OIDs in C++",
+ epilog="example: python %s ecdsa-with-SHA1 1.2.840.10045.4.1"
+ % sys.argv[0])
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument("--tlv", action='store_true',
+ help="Wrap the encoded OID value with the tag and length")
+ group.add_argument("--alg", action='store_true',
+ help="Wrap the encoded OID value in an encoded SignatureAlgorithm")
+ group.add_argument("--prefixdefine", action='store_true',
+ help="generate a OID prefix #define")
+ parser.add_argument("name",
+ help="The name given to the OID in the specification")
+ parser.add_argument("dottedOID", metavar="dotted-oid",
+ help="The OID value, in dotted notation")
+
+ args = parser.parse_args()
+ if args.alg:
+ mode = 'alg'
+ elif args.tlv:
+ mode = 'tlv'
+ elif args.prefixdefine:
+ mode = 'prefixdefine'
+ else:
+ mode = 'value'
+
+ print(toCode(sys.argv[0], args.name, args.dottedOID, mode))
diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def
index 4f0ade4d0..8a9b3b030 100644
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -1133,3 +1133,9 @@ SEC_CreateSignatureAlgorithmParameters;
;+ local:
;+ *;
;+};
+;+NSS_3.39 { # NSS 3.39 release
+;+ global:
+CERT_GetCertKeyType;
+;+ local:
+;+ *;
+;+};
diff --git a/security/nss/lib/nss/nss.h b/security/nss/lib/nss/nss.h
index efb0827c5..49c545ecc 100644
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -22,9 +22,9 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
-#define NSS_VERSION "3.38" _NSS_CUSTOMIZED
+#define NSS_VERSION "3.41" _NSS_CUSTOMIZED
#define NSS_VMAJOR 3
-#define NSS_VMINOR 38
+#define NSS_VMINOR 41
#define NSS_VPATCH 0
#define NSS_VBUILD 0
#define NSS_BETA PR_FALSE
diff --git a/security/nss/lib/nss/nssinit.c b/security/nss/lib/nss/nssinit.c
index 5d62d479c..9b6012771 100644
--- a/security/nss/lib/nss/nssinit.c
+++ b/security/nss/lib/nss/nssinit.c
@@ -12,7 +12,7 @@
#include "prprf.h"
#include "prmem.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secmod.h"
#include "secoid.h"
#include "nss.h"
@@ -54,7 +54,7 @@ nss_mktemp(char *path)
#define NSS_MAX_FLAG_SIZE sizeof("readOnly") + sizeof("noCertDB") + \
sizeof("noModDB") + sizeof("forceOpen") + sizeof("passwordRequired") + \
- sizeof("optimizeSpace")
+ sizeof("optimizeSpace") + sizeof("printPolicyFeedback")
#define NSS_DEFAULT_MOD_NAME "NSS Internal Module"
static char *
@@ -702,6 +702,30 @@ nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
if (SECOID_Init() != SECSuccess) {
goto loser;
}
+#ifdef POLICY_FILE
+ /* Load the system crypto policy file if it exists,
+ * unless the NSS_IGNORE_SYSTEM_POLICY environment
+ * variable has been set to 1. */
+ ignoreVar = PR_GetEnvSecure("NSS_IGNORE_SYSTEM_POLICY");
+ if (ignoreVar == NULL || strncmp(ignoreVar, "1", sizeof("1")) != 0) {
+ if (PR_Access(POLICY_PATH "/" POLICY_FILE, PR_ACCESS_READ_OK) == PR_SUCCESS) {
+ SECMODModule *module = SECMOD_LoadModule(
+ "name=\"Policy File\" "
+ "parameters=\"configdir='sql:" POLICY_PATH "' "
+ "secmod='" POLICY_FILE "' "
+ "flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" "
+ "NSS=\"flags=internal,moduleDB,skipFirst,moduleDBOnly,critical\"",
+ parent, PR_TRUE);
+ if (module) {
+ PRBool isLoaded = module->loaded;
+ SECMOD_DestroyModule(module);
+ if (!isLoaded) {
+ goto loser;
+ }
+ }
+ }
+ }
+#endif
if (STAN_LoadDefaultNSS3TrustDomain() != PR_SUCCESS) {
goto loser;
}
@@ -730,30 +754,6 @@ nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
}
}
}
-#ifdef POLICY_FILE
- /* Load the system crypto policy file if it exists,
- * unless the NSS_IGNORE_SYSTEM_POLICY environment
- * variable has been set to 1. */
- ignoreVar = PR_GetEnvSecure("NSS_IGNORE_SYSTEM_POLICY");
- if (ignoreVar == NULL || strncmp(ignoreVar, "1", sizeof("1")) != 0) {
- if (PR_Access(POLICY_PATH "/" POLICY_FILE, PR_ACCESS_READ_OK) == PR_SUCCESS) {
- SECMODModule *module = SECMOD_LoadModule(
- "name=\"Policy File\" "
- "parameters=\"configdir='sql:" POLICY_PATH "' "
- "secmod='" POLICY_FILE "' "
- "flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" "
- "NSS=\"flags=internal,moduleDB,skipFirst,moduleDBOnly,critical\"",
- parent, PR_TRUE);
- if (module) {
- PRBool isLoaded = module->loaded;
- SECMOD_DestroyModule(module);
- if (!isLoaded) {
- goto loser;
- }
- }
- }
- }
-#endif
pk11sdr_Init();
cert_CreateSubjectKeyIDHashTable();
diff --git a/security/nss/lib/pk11wrap/pk11akey.c b/security/nss/lib/pk11wrap/pk11akey.c
index 346e473a9..c6070e264 100644
--- a/security/nss/lib/pk11wrap/pk11akey.c
+++ b/security/nss/lib/pk11wrap/pk11akey.c
@@ -13,7 +13,7 @@
#include "pkcs11t.h"
#include "pk11func.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "keyi.h"
#include "secitem.h"
#include "secasn1.h"
@@ -804,30 +804,12 @@ PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType,
/* don't know? look it up */
if (keyType == nullKey) {
CK_KEY_TYPE pk11Type = CKK_RSA;
- SECItem info;
pk11Type = PK11_ReadULongAttribute(slot, privID, CKA_KEY_TYPE);
isTemp = (PRBool)!PK11_HasAttributeSet(slot, privID, CKA_TOKEN, PR_FALSE);
switch (pk11Type) {
case CKK_RSA:
keyType = rsaKey;
- /* determine RSA key type from the CKA_PUBLIC_KEY_INFO if present */
- rv = PK11_ReadAttribute(slot, privID, CKA_PUBLIC_KEY_INFO, NULL, &info);
- if (rv == SECSuccess) {
- CERTSubjectPublicKeyInfo *spki;
-
- spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&info);
- if (spki) {
- SECOidTag tag;
-
- tag = SECOID_GetAlgorithmTag(&spki->algorithm);
- if (tag == SEC_OID_PKCS1_RSA_PSS_SIGNATURE)
- keyType = rsaPssKey;
- SECKEY_DestroySubjectPublicKeyInfo(spki);
- }
- SECITEM_FreeItem(&info, PR_FALSE);
- }
-
break;
case CKK_DSA:
keyType = dsaKey;
diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c
index c1caf5e60..819769643 100644
--- a/security/nss/lib/pk11wrap/pk11cert.c
+++ b/security/nss/lib/pk11wrap/pk11cert.c
@@ -15,7 +15,7 @@
#include "cert.h"
#include "certi.h"
#include "secitem.h"
-#include "key.h"
+#include "keyhi.h"
#include "secoid.h"
#include "pkcs7t.h"
#include "cmsreclist.h"
@@ -741,7 +741,7 @@ find_certs_from_nickname(const char *nickname, void *wincx)
char *delimit = NULL;
char *tokenName;
- if (!strncmp(nickname, "pkcs11:", strlen("pkcs11:"))) {
+ if (!PORT_Strncasecmp(nickname, "pkcs11:", strlen("pkcs11:"))) {
certs = find_certs_from_uri(nickname, wincx);
if (certs)
return certs;
diff --git a/security/nss/lib/pk11wrap/pk11kea.c b/security/nss/lib/pk11wrap/pk11kea.c
index 331a19c16..1f228cfaf 100644
--- a/security/nss/lib/pk11wrap/pk11kea.c
+++ b/security/nss/lib/pk11wrap/pk11kea.c
@@ -14,7 +14,7 @@
#include "pkcs11.h"
#include "pk11func.h"
#include "secitem.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "sechash.h"
#include "cert.h"
diff --git a/security/nss/lib/pk11wrap/pk11obj.c b/security/nss/lib/pk11wrap/pk11obj.c
index b97caddd4..937ac654a 100644
--- a/security/nss/lib/pk11wrap/pk11obj.c
+++ b/security/nss/lib/pk11wrap/pk11obj.c
@@ -11,7 +11,7 @@
#include "pkcs11.h"
#include "pkcs11t.h"
#include "pk11func.h"
-#include "key.h"
+#include "keyhi.h"
#include "secitem.h"
#include "secerr.h"
#include "sslerr.h"
diff --git a/security/nss/lib/pk11wrap/pk11pars.c b/security/nss/lib/pk11wrap/pk11pars.c
index c165e1ef2..db60f7c9d 100644
--- a/security/nss/lib/pk11wrap/pk11pars.c
+++ b/security/nss/lib/pk11wrap/pk11pars.c
@@ -109,6 +109,7 @@ secmod_NewModule(void)
*other flags are set */
#define SECMOD_FLAG_MODULE_DB_SKIP_FIRST 0x02
#define SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB 0x04
+#define SECMOD_FLAG_MODULE_DB_POLICY_ONLY 0x08
/* private flags for internal (field in SECMODModule). */
/* The meaing of these flags is as follows:
@@ -193,7 +194,7 @@ typedef struct {
* This table should be merged with the SECOID table.
*/
#define CIPHER_NAME(x) x, (sizeof(x) - 1)
-static const oidValDef algOptList[] = {
+static const oidValDef curveOptList[] = {
/* Curves */
{ CIPHER_NAME("PRIME192V1"), SEC_OID_ANSIX962_EC_PRIME192V1,
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
@@ -315,7 +316,9 @@ static const oidValDef algOptList[] = {
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
{ CIPHER_NAME("SECT571R1"), SEC_OID_SECG_EC_SECT571R1,
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
+};
+static const oidValDef hashOptList[] = {
/* Hashes */
{ CIPHER_NAME("MD2"), SEC_OID_MD2,
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
@@ -333,7 +336,9 @@ static const oidValDef algOptList[] = {
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
{ CIPHER_NAME("SHA512"), SEC_OID_SHA512,
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
+};
+static const oidValDef macOptList[] = {
/* MACs */
{ CIPHER_NAME("HMAC-SHA1"), SEC_OID_HMAC_SHA1, NSS_USE_ALG_IN_SSL },
{ CIPHER_NAME("HMAC-SHA224"), SEC_OID_HMAC_SHA224, NSS_USE_ALG_IN_SSL },
@@ -341,7 +346,9 @@ static const oidValDef algOptList[] = {
{ CIPHER_NAME("HMAC-SHA384"), SEC_OID_HMAC_SHA384, NSS_USE_ALG_IN_SSL },
{ CIPHER_NAME("HMAC-SHA512"), SEC_OID_HMAC_SHA512, NSS_USE_ALG_IN_SSL },
{ CIPHER_NAME("HMAC-MD5"), SEC_OID_HMAC_MD5, NSS_USE_ALG_IN_SSL },
+};
+static const oidValDef cipherOptList[] = {
/* Ciphers */
{ CIPHER_NAME("AES128-CBC"), SEC_OID_AES_128_CBC, NSS_USE_ALG_IN_SSL },
{ CIPHER_NAME("AES192-CBC"), SEC_OID_AES_192_CBC, NSS_USE_ALG_IN_SSL },
@@ -361,7 +368,9 @@ static const oidValDef algOptList[] = {
{ CIPHER_NAME("RC2"), SEC_OID_RC2_CBC, NSS_USE_ALG_IN_SSL },
{ CIPHER_NAME("RC4"), SEC_OID_RC4, NSS_USE_ALG_IN_SSL },
{ CIPHER_NAME("IDEA"), SEC_OID_IDEA_CBC, NSS_USE_ALG_IN_SSL },
+};
+static const oidValDef kxOptList[] = {
/* Key exchange */
{ CIPHER_NAME("RSA"), SEC_OID_TLS_RSA, NSS_USE_ALG_IN_SSL_KX },
{ CIPHER_NAME("RSA-EXPORT"), SEC_OID_TLS_RSA_EXPORT, NSS_USE_ALG_IN_SSL_KX },
@@ -375,6 +384,20 @@ static const oidValDef algOptList[] = {
{ CIPHER_NAME("ECDH-RSA"), SEC_OID_TLS_ECDH_RSA, NSS_USE_ALG_IN_SSL_KX },
};
+typedef struct {
+ const oidValDef *list;
+ PRUint32 entries;
+ const char *description;
+} algListsDef;
+
+static const algListsDef algOptLists[] = {
+ { curveOptList, PR_ARRAY_SIZE(curveOptList), "ECC" },
+ { hashOptList, PR_ARRAY_SIZE(hashOptList), "HASH" },
+ { macOptList, PR_ARRAY_SIZE(macOptList), "MAC" },
+ { cipherOptList, PR_ARRAY_SIZE(cipherOptList), "CIPHER" },
+ { kxOptList, PR_ARRAY_SIZE(kxOptList), "OTHER-KX" },
+};
+
static const optionFreeDef sslOptList[] = {
/* Versions */
{ CIPHER_NAME("SSL2.0"), 0x002 },
@@ -401,7 +424,7 @@ static const optionFreeDef freeOptList[] = {
{ CIPHER_NAME("TLS-VERSION-MAX"), NSS_TLS_VERSION_MAX_POLICY },
/* constraints on DTLS Protocols */
{ CIPHER_NAME("DTLS-VERSION-MIN"), NSS_DTLS_VERSION_MIN_POLICY },
- { CIPHER_NAME("DTLS-VERSION-MAX"), NSS_DTLS_VERSION_MIN_POLICY }
+ { CIPHER_NAME("DTLS-VERSION-MAX"), NSS_DTLS_VERSION_MAX_POLICY }
};
static const policyFlagDef policyFlagList[] = {
@@ -446,7 +469,8 @@ secmod_ArgGetSubValue(const char *cipher, char sep1, char sep2,
}
static PRUint32
-secmod_parsePolicyValue(const char *policyFlags, int policyLength)
+secmod_parsePolicyValue(const char *policyFlags, int policyLength,
+ PRBool printPolicyFeedback)
{
const char *flag, *currentString;
PRUint32 flags = 0;
@@ -455,6 +479,7 @@ secmod_parsePolicyValue(const char *policyFlags, int policyLength)
for (currentString = policyFlags; currentString &&
currentString < policyFlags + policyLength;) {
int length;
+ PRBool unknown = PR_TRUE;
flag = secmod_ArgGetSubValue(currentString, ',', ':', &length,
&currentString);
if (length == 0) {
@@ -466,41 +491,49 @@ secmod_parsePolicyValue(const char *policyFlags, int policyLength)
if ((policy->name_size == length) &&
PORT_Strncasecmp(policy->name, flag, name_size) == 0) {
flags |= policy->flag;
+ unknown = PR_FALSE;
break;
}
}
+ if (unknown && printPolicyFeedback) {
+ PR_SetEnv("NSS_POLICY_FAIL=1");
+ fprintf(stderr, "NSS-POLICY-FAIL %.*s: unknown value: %.*s\n",
+ policyLength, policyFlags, length, flag);
+ }
}
return flags;
}
/* allow symbolic names for values. The only ones currently defines or
* SSL protocol versions. */
-static PRInt32
-secmod_getPolicyOptValue(const char *policyValue, int policyValueLength)
+static SECStatus
+secmod_getPolicyOptValue(const char *policyValue, int policyValueLength,
+ PRInt32 *result)
{
PRInt32 val = atoi(policyValue);
int i;
if ((val != 0) || (*policyValue == '0')) {
- return val;
+ *result = val;
+ return SECSuccess;
}
for (i = 0; i < PR_ARRAY_SIZE(sslOptList); i++) {
if (policyValueLength == sslOptList[i].name_size &&
PORT_Strncasecmp(sslOptList[i].name, policyValue,
sslOptList[i].name_size) == 0) {
- val = sslOptList[i].option;
- break;
+ *result = sslOptList[i].option;
+ return SECSuccess;
}
}
- return val;
+ return SECFailure;
}
static SECStatus
-secmod_applyCryptoPolicy(const char *policyString,
- PRBool allow)
+secmod_applyCryptoPolicy(const char *policyString, PRBool allow,
+ PRBool printPolicyFeedback)
{
const char *cipher, *currentString;
- unsigned i;
+ unsigned i, j;
SECStatus rv = SECSuccess;
PRBool unknown;
@@ -525,56 +558,63 @@ secmod_applyCryptoPolicy(const char *policyString,
/* disable or enable all options by default */
PRUint32 value = 0;
if (newValue) {
- value = secmod_parsePolicyValue(&cipher[3] + 1, length - 3 - 1);
+ value = secmod_parsePolicyValue(&cipher[3] + 1, length - 3 - 1, printPolicyFeedback);
}
- for (i = 0; i < PR_ARRAY_SIZE(algOptList); i++) {
- PRUint32 enable, disable;
- if (!newValue) {
- value = algOptList[i].val;
- }
- if (allow) {
- enable = value;
- disable = 0;
- } else {
- enable = 0;
- disable = value;
+ for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
+ const algListsDef *algOptList = &algOptLists[i];
+ for (j = 0; j < algOptList->entries; j++) {
+ PRUint32 enable, disable;
+ if (!newValue) {
+ value = algOptList->list[j].val;
+ }
+ if (allow) {
+ enable = value;
+ disable = 0;
+ } else {
+ enable = 0;
+ disable = value;
+ }
+ NSS_SetAlgorithmPolicy(algOptList->list[j].oid, enable, disable);
}
- NSS_SetAlgorithmPolicy(algOptList[i].oid, enable, disable);
}
continue;
}
- for (i = 0; i < PR_ARRAY_SIZE(algOptList); i++) {
- const oidValDef *algOpt = &algOptList[i];
- unsigned name_size = algOpt->name_size;
- PRBool newOption = PR_FALSE;
+ for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
+ const algListsDef *algOptList = &algOptLists[i];
+ for (j = 0; j < algOptList->entries; j++) {
+ const oidValDef *algOpt = &algOptList->list[j];
+ unsigned name_size = algOpt->name_size;
+ PRBool newOption = PR_FALSE;
- if ((length >= name_size) && (cipher[name_size] == '/')) {
- newOption = PR_TRUE;
- }
- if ((newOption || algOpt->name_size == length) &&
- PORT_Strncasecmp(algOpt->name, cipher, name_size) == 0) {
- PRUint32 value = algOpt->val;
- PRUint32 enable, disable;
- if (newOption) {
- value = secmod_parsePolicyValue(&cipher[name_size] + 1,
- length - name_size - 1);
+ if ((length >= name_size) && (cipher[name_size] == '/')) {
+ newOption = PR_TRUE;
}
- if (allow) {
- enable = value;
- disable = 0;
- } else {
- enable = 0;
- disable = value;
- }
- rv = NSS_SetAlgorithmPolicy(algOpt->oid, enable, disable);
- if (rv != SECSuccess) {
- /* could not enable option */
- /* NSS_SetAlgorithPolicy should have set the error code */
- return SECFailure;
+ if ((newOption || algOpt->name_size == length) &&
+ PORT_Strncasecmp(algOpt->name, cipher, name_size) == 0) {
+ PRUint32 value = algOpt->val;
+ PRUint32 enable, disable;
+ if (newOption) {
+ value = secmod_parsePolicyValue(&cipher[name_size] + 1,
+ length - name_size - 1,
+ printPolicyFeedback);
+ }
+ if (allow) {
+ enable = value;
+ disable = 0;
+ } else {
+ enable = 0;
+ disable = value;
+ }
+ rv = NSS_SetAlgorithmPolicy(algOpt->oid, enable, disable);
+ if (rv != SECSuccess) {
+ /* could not enable option */
+ /* NSS_SetAlgorithPolicy should have set the error code */
+ return SECFailure;
+ }
+ unknown = PR_FALSE;
+ break;
}
- unknown = PR_FALSE;
- break;
}
}
if (!unknown) {
@@ -587,9 +627,19 @@ secmod_applyCryptoPolicy(const char *policyString,
if ((length > name_size) && cipher[name_size] == '=' &&
PORT_Strncasecmp(freeOpt->name, cipher, name_size) == 0) {
- PRInt32 val = secmod_getPolicyOptValue(&cipher[name_size + 1],
- length - name_size - 1);
-
+ PRInt32 val;
+ const char *policyValue = &cipher[name_size + 1];
+ int policyValueLength = length - name_size - 1;
+ rv = secmod_getPolicyOptValue(policyValue, policyValueLength,
+ &val);
+ if (rv != SECSuccess) {
+ if (printPolicyFeedback) {
+ PR_SetEnv("NSS_POLICY_FAIL=1");
+ fprintf(stderr, "NSS-POLICY-FAIL %.*s: unknown value: %.*s\n",
+ length, cipher, policyValueLength, policyValue);
+ }
+ return SECFailure;
+ }
rv = NSS_OptionSet(freeOpt->option, val);
if (rv != SECSuccess) {
/* could not enable option */
@@ -602,12 +652,83 @@ secmod_applyCryptoPolicy(const char *policyString,
break;
}
}
+
+ if (unknown && printPolicyFeedback) {
+ PR_SetEnv("NSS_POLICY_FAIL=1");
+ fprintf(stderr, "NSS-POLICY-FAIL %s: unknown identifier: %.*s\n",
+ allow ? "allow" : "disallow", length, cipher);
+ }
}
return rv;
}
+static void
+secmod_sanityCheckCryptoPolicy(void)
+{
+ unsigned i, j;
+ SECStatus rv = SECSuccess;
+ unsigned num_kx_enabled = 0;
+ unsigned num_ssl_enabled = 0;
+ unsigned num_sig_enabled = 0;
+ unsigned enabledCount[PR_ARRAY_SIZE(algOptLists)];
+ const char *sWarn = "WARN";
+ const char *sInfo = "INFO";
+ PRBool haveWarning = PR_FALSE;
+
+ for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
+ const algListsDef *algOptList = &algOptLists[i];
+ enabledCount[i] = 0;
+ for (j = 0; j < algOptList->entries; j++) {
+ const oidValDef *algOpt = &algOptList->list[j];
+ PRUint32 value;
+ PRBool anyEnabled = PR_FALSE;
+ rv = NSS_GetAlgorithmPolicy(algOpt->oid, &value);
+ if (rv != SECSuccess) {
+ PR_SetEnv("NSS_POLICY_FAIL=1");
+ fprintf(stderr, "NSS-POLICY-FAIL: internal failure with NSS_GetAlgorithmPolicy at %u\n", i);
+ return;
+ }
+
+ if ((algOpt->val & NSS_USE_ALG_IN_SSL_KX) && (value & NSS_USE_ALG_IN_SSL_KX)) {
+ ++num_kx_enabled;
+ anyEnabled = PR_TRUE;
+ fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for KX\n", algOpt->name);
+ }
+ if ((algOpt->val & NSS_USE_ALG_IN_SSL) && (value & NSS_USE_ALG_IN_SSL)) {
+ ++num_ssl_enabled;
+ anyEnabled = PR_TRUE;
+ fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for SSL\n", algOpt->name);
+ }
+ if ((algOpt->val & NSS_USE_ALG_IN_CERT_SIGNATURE) && (value & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
+ ++num_sig_enabled;
+ anyEnabled = PR_TRUE;
+ fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for CERT-SIGNATURE\n", algOpt->name);
+ }
+ if (anyEnabled) {
+ ++enabledCount[i];
+ }
+ }
+ }
+ fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG-KX: %u\n", num_kx_enabled ? sInfo : sWarn, num_kx_enabled);
+ fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG: %u\n", num_ssl_enabled ? sInfo : sWarn, num_ssl_enabled);
+ fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CERT-SIG: %u\n", num_sig_enabled ? sInfo : sWarn, num_sig_enabled);
+ if (!num_kx_enabled || !num_ssl_enabled || !num_sig_enabled) {
+ haveWarning = PR_TRUE;
+ }
+ for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
+ const algListsDef *algOptList = &algOptLists[i];
+ fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s: %u\n", enabledCount[i] ? sInfo : sWarn, algOptList->description, enabledCount[i]);
+ if (!enabledCount[i]) {
+ haveWarning = PR_TRUE;
+ }
+ }
+ if (haveWarning) {
+ PR_SetEnv("NSS_POLICY_WARN=1");
+ }
+}
+
static SECStatus
-secmod_parseCryptoPolicy(const char *policyConfig)
+secmod_parseCryptoPolicy(const char *policyConfig, PRBool printPolicyFeedback)
{
char *disallow, *allow;
SECStatus rv;
@@ -622,16 +743,26 @@ secmod_parseCryptoPolicy(const char *policyConfig)
return rv;
}
disallow = NSSUTIL_ArgGetParamValue("disallow", policyConfig);
- rv = secmod_applyCryptoPolicy(disallow, PR_FALSE);
+ rv = secmod_applyCryptoPolicy(disallow, PR_FALSE, printPolicyFeedback);
if (disallow)
PORT_Free(disallow);
if (rv != SECSuccess) {
return rv;
}
allow = NSSUTIL_ArgGetParamValue("allow", policyConfig);
- rv = secmod_applyCryptoPolicy(allow, PR_TRUE);
+ rv = secmod_applyCryptoPolicy(allow, PR_TRUE, printPolicyFeedback);
if (allow)
PORT_Free(allow);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ if (printPolicyFeedback) {
+ /* This helps to distinguish configurations that don't contain any
+ * policy config= statement. */
+ PR_SetEnv("NSS_POLICY_LOADED=1");
+ fprintf(stderr, "NSS-POLICY-INFO: LOADED-SUCCESSFULLY\n");
+ secmod_sanityCheckCryptoPolicy();
+ }
return rv;
}
@@ -648,11 +779,16 @@ SECMOD_CreateModuleEx(const char *library, const char *moduleName,
char *slotParams, *ciphers;
/* pk11pars.h still does not have const char * interfaces */
char *nssc = (char *)nss;
+ PRBool printPolicyFeedback = NSSUTIL_ArgHasFlag("flags", "printPolicyFeedback", nssc);
- rv = secmod_parseCryptoPolicy(config);
+ rv = secmod_parseCryptoPolicy(config, printPolicyFeedback);
/* do not load the module if policy parsing fails */
if (rv != SECSuccess) {
+ if (printPolicyFeedback) {
+ PR_SetEnv("NSS_POLICY_FAIL=1");
+ fprintf(stderr, "NSS-POLICY-FAIL: policy config parsing failed, not loading module %s\n", moduleName);
+ }
return NULL;
}
@@ -703,6 +839,9 @@ SECMOD_CreateModuleEx(const char *library, const char *moduleName,
if (NSSUTIL_ArgHasFlag("flags", "defaultModDB", nssc)) {
flags |= SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB;
}
+ if (NSSUTIL_ArgHasFlag("flags", "policyOnly", nssc)) {
+ flags |= SECMOD_FLAG_MODULE_DB_POLICY_ONLY;
+ }
/* additional moduleDB flags could be added here in the future */
mod->isModuleDB = (PRBool)flags;
}
@@ -743,6 +882,14 @@ SECMOD_GetDefaultModDBFlag(SECMODModule *mod)
}
PRBool
+secmod_PolicyOnly(SECMODModule *mod)
+{
+ char flags = (char)mod->isModuleDB;
+
+ return (flags & SECMOD_FLAG_MODULE_DB_POLICY_ONLY) ? PR_TRUE : PR_FALSE;
+}
+
+PRBool
secmod_IsInternalKeySlot(SECMODModule *mod)
{
char flags = (char)mod->internal;
@@ -1635,6 +1782,7 @@ SECMOD_LoadModule(char *modulespec, SECMODModule *parent, PRBool recurse)
SECMODModule *module = NULL;
SECMODModule *oldModule = NULL;
SECStatus rv;
+ PRBool forwardPolicyFeedback = PR_FALSE;
/* initialize the underlying module structures */
SECMOD_Init();
@@ -1647,6 +1795,7 @@ SECMOD_LoadModule(char *modulespec, SECMODModule *parent, PRBool recurse)
}
module = SECMOD_CreateModuleEx(library, moduleName, parameters, nss, config);
+ forwardPolicyFeedback = NSSUTIL_ArgHasFlag("flags", "printPolicyFeedback", nss);
if (library)
PORT_Free(library);
if (moduleName)
@@ -1660,6 +1809,12 @@ SECMOD_LoadModule(char *modulespec, SECMODModule *parent, PRBool recurse)
if (!module) {
goto loser;
}
+
+ /* a policy only stanza doesn't actually get 'loaded'. policy has already
+ * been parsed as a side effect of the CreateModuleEx call */
+ if (secmod_PolicyOnly(module)) {
+ return module;
+ }
if (parent) {
module->parent = SECMOD_ReferenceModule(parent);
if (module->internal && secmod_IsInternalKeySlot(parent)) {
@@ -1703,7 +1858,15 @@ SECMOD_LoadModule(char *modulespec, SECMODModule *parent, PRBool recurse)
rv = SECFailure;
break;
}
- child = SECMOD_LoadModule(*index, module, PR_TRUE);
+ if (!forwardPolicyFeedback) {
+ child = SECMOD_LoadModule(*index, module, PR_TRUE);
+ } else {
+ /* Add printPolicyFeedback to the nss flags */
+ char *specWithForwards =
+ NSSUTIL_AddNSSFlagToModuleSpec(*index, "printPolicyFeedback");
+ child = SECMOD_LoadModule(specWithForwards, module, PR_TRUE);
+ PORT_Free(specWithForwards);
+ }
if (!child)
break;
if (child->isCritical && !child->loaded) {
diff --git a/security/nss/lib/pk11wrap/pk11pbe.c b/security/nss/lib/pk11wrap/pk11pbe.c
index 5f68f399e..4b6645578 100644
--- a/security/nss/lib/pk11wrap/pk11pbe.c
+++ b/security/nss/lib/pk11wrap/pk11pbe.c
@@ -23,7 +23,7 @@
#include "pkcs11.h"
#include "pk11func.h"
#include "secitem.h"
-#include "key.h"
+#include "keyhi.h"
typedef struct SEC_PKCS5PBEParameterStr SEC_PKCS5PBEParameter;
struct SEC_PKCS5PBEParameterStr {
diff --git a/security/nss/lib/pk11wrap/pk11pk12.c b/security/nss/lib/pk11wrap/pk11pk12.c
index 035143af8..47b6702c6 100644
--- a/security/nss/lib/pk11wrap/pk11pk12.c
+++ b/security/nss/lib/pk11wrap/pk11pk12.c
@@ -14,7 +14,7 @@
#include "pkcs11.h"
#include "pk11func.h"
#include "secitem.h"
-#include "key.h"
+#include "keyhi.h"
#include "secoid.h"
#include "secasn1.h"
#include "secerr.h"
diff --git a/security/nss/lib/pk11wrap/pk11priv.h b/security/nss/lib/pk11wrap/pk11priv.h
index 9281923fa..8848c81ec 100644
--- a/security/nss/lib/pk11wrap/pk11priv.h
+++ b/security/nss/lib/pk11wrap/pk11priv.h
@@ -7,7 +7,7 @@
#include "seccomon.h"
#include "secoidt.h"
#include "secdert.h"
-#include "keyt.h"
+#include "keythi.h"
#include "certt.h"
#include "pkcs11t.h"
#include "secmodt.h"
diff --git a/security/nss/lib/pk11wrap/pk11pub.h b/security/nss/lib/pk11wrap/pk11pub.h
index dbd8da092..8db969e4c 100644
--- a/security/nss/lib/pk11wrap/pk11pub.h
+++ b/security/nss/lib/pk11wrap/pk11pub.h
@@ -7,7 +7,7 @@
#include "seccomon.h"
#include "secoidt.h"
#include "secdert.h"
-#include "keyt.h"
+#include "keythi.h"
#include "certt.h"
#include "pkcs11t.h"
#include "secmodt.h"
diff --git a/security/nss/lib/pk11wrap/pk11slot.c b/security/nss/lib/pk11wrap/pk11slot.c
index c39abe17e..ebe54d495 100644
--- a/security/nss/lib/pk11wrap/pk11slot.c
+++ b/security/nss/lib/pk11wrap/pk11slot.c
@@ -607,12 +607,32 @@ PK11_FindSlotsByNames(const char *dllName, const char *slotName,
return slotList;
}
-PK11SlotInfo *
-PK11_FindSlotByName(const char *name)
+typedef PRBool (*PK11SlotMatchFunc)(PK11SlotInfo *slot, const void *arg);
+
+static PRBool
+pk11_MatchSlotByTokenName(PK11SlotInfo *slot, const void *arg)
+{
+ return PORT_Strcmp(slot->token_name, arg) == 0;
+}
+
+static PRBool
+pk11_MatchSlotBySerial(PK11SlotInfo *slot, const void *arg)
{
+ return PORT_Memcmp(slot->serial, arg, sizeof(slot->serial)) == 0;
+}
+
+static PRBool
+pk11_MatchSlotByTokenURI(PK11SlotInfo *slot, const void *arg)
+{
+ return pk11_MatchUriTokenInfo(slot, (PK11URI *)arg);
+}
+
+static PK11SlotInfo *
+pk11_FindSlot(const void *arg, PK11SlotMatchFunc func)
+{
+ SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
SECMODModuleList *mlp;
SECMODModuleList *modules;
- SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
int i;
PK11SlotInfo *slot = NULL;
@@ -620,10 +640,6 @@ PK11_FindSlotByName(const char *name)
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
return slot;
}
- if ((name == NULL) || (*name == 0)) {
- return PK11_GetInternalKeySlot();
- }
-
/* work through all the slots */
SECMOD_GetReadLock(moduleLock);
modules = SECMOD_GetDefaultModuleList();
@@ -631,7 +647,7 @@ PK11_FindSlotByName(const char *name)
for (i = 0; i < mlp->module->slotCount; i++) {
PK11SlotInfo *tmpSlot = mlp->module->slots[i];
if (PK11_IsPresent(tmpSlot)) {
- if (PORT_Strcmp(tmpSlot->token_name, name) == 0) {
+ if (func(tmpSlot, arg)) {
slot = PK11_ReferenceSlot(tmpSlot);
break;
}
@@ -649,43 +665,41 @@ PK11_FindSlotByName(const char *name)
return slot;
}
-PK11SlotInfo *
-PK11_FindSlotBySerial(char *serial)
+static PK11SlotInfo *
+pk11_FindSlotByTokenURI(const char *uriString)
{
- SECMODModuleList *mlp;
- SECMODModuleList *modules;
- SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
- int i;
PK11SlotInfo *slot = NULL;
+ PK11URI *uri;
- if (!moduleLock) {
- PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ uri = PK11URI_ParseURI(uriString);
+ if (!uri) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
return slot;
}
- /* work through all the slots */
- SECMOD_GetReadLock(moduleLock);
- modules = SECMOD_GetDefaultModuleList();
- for (mlp = modules; mlp != NULL; mlp = mlp->next) {
- for (i = 0; i < mlp->module->slotCount; i++) {
- PK11SlotInfo *tmpSlot = mlp->module->slots[i];
- if (PK11_IsPresent(tmpSlot)) {
- if (PORT_Memcmp(tmpSlot->serial, serial,
- sizeof(tmpSlot->serial)) == 0) {
- slot = PK11_ReferenceSlot(tmpSlot);
- break;
- }
- }
- }
- if (slot != NULL)
- break;
+
+ slot = pk11_FindSlot(uri, pk11_MatchSlotByTokenURI);
+ PK11URI_DestroyURI(uri);
+ return slot;
+}
+
+PK11SlotInfo *
+PK11_FindSlotByName(const char *name)
+{
+ if ((name == NULL) || (*name == 0)) {
+ return PK11_GetInternalKeySlot();
}
- SECMOD_ReleaseReadLock(moduleLock);
- if (slot == NULL) {
- PORT_SetError(SEC_ERROR_NO_TOKEN);
+ if (!PORT_Strncasecmp(name, "pkcs11:", strlen("pkcs11:"))) {
+ return pk11_FindSlotByTokenURI(name);
}
- return slot;
+ return pk11_FindSlot(name, pk11_MatchSlotByTokenName);
+}
+
+PK11SlotInfo *
+PK11_FindSlotBySerial(char *serial)
+{
+ return pk11_FindSlot(serial, pk11_MatchSlotBySerial);
}
/*
diff --git a/security/nss/lib/pk11wrap/secmodi.h b/security/nss/lib/pk11wrap/secmodi.h
index 84f5f2a30..7ec77ced6 100644
--- a/security/nss/lib/pk11wrap/secmodi.h
+++ b/security/nss/lib/pk11wrap/secmodi.h
@@ -13,7 +13,7 @@
#include "secdert.h"
#include "certt.h"
#include "secmodt.h"
-#include "keyt.h"
+#include "keythi.h"
SEC_BEGIN_PROTOS
diff --git a/security/nss/lib/pkcs12/p12.h b/security/nss/lib/pkcs12/p12.h
index 118db6efa..495bbf6c4 100644
--- a/security/nss/lib/pkcs12/p12.h
+++ b/security/nss/lib/pkcs12/p12.h
@@ -6,7 +6,7 @@
#define _P12_H_
#include "secoid.h"
-#include "key.h"
+#include "keyhi.h"
#include "secpkcs7.h"
#include "p12t.h"
diff --git a/security/nss/lib/pkcs12/p12t.h b/security/nss/lib/pkcs12/p12t.h
index 62c2b502e..b22f0dd82 100644
--- a/security/nss/lib/pkcs12/p12t.h
+++ b/security/nss/lib/pkcs12/p12t.h
@@ -6,7 +6,7 @@
#define _P12T_H_
#include "secoid.h"
-#include "key.h"
+#include "keythi.h"
#include "pkcs11.h"
#include "secpkcs7.h"
#include "secdig.h" /* for SGNDigestInfo */
diff --git a/security/nss/lib/pkcs12/pkcs12t.h b/security/nss/lib/pkcs12/pkcs12t.h
index ad00d7b5b..db10d28af 100644
--- a/security/nss/lib/pkcs12/pkcs12t.h
+++ b/security/nss/lib/pkcs12/pkcs12t.h
@@ -8,7 +8,7 @@
#include "seccomon.h"
#include "secoid.h"
#include "cert.h"
-#include "key.h"
+#include "keythi.h"
#include "plarena.h"
#include "secpkcs7.h"
#include "secdig.h" /* for SGNDigestInfo */
diff --git a/security/nss/lib/pkcs7/p7decode.c b/security/nss/lib/pkcs7/p7decode.c
index ba51955ab..641d201e5 100644
--- a/security/nss/lib/pkcs7/p7decode.c
+++ b/security/nss/lib/pkcs7/p7decode.c
@@ -16,7 +16,7 @@
/* include should be removed! */
/*#include "cdbhdl.h" */
#include "cryptohi.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/pkcs7/secmime.c b/security/nss/lib/pkcs7/secmime.c
index ca1046aa5..8a4afe45b 100644
--- a/security/nss/lib/pkcs7/secmime.c
+++ b/security/nss/lib/pkcs7/secmime.c
@@ -14,7 +14,7 @@
#include "secasn1.h"
#include "secitem.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secerr.h"
typedef struct smime_cipher_map_struct {
diff --git a/security/nss/lib/pkcs7/secpkcs7.h b/security/nss/lib/pkcs7/secpkcs7.h
index 78270bd15..4a88df1df 100644
--- a/security/nss/lib/pkcs7/secpkcs7.h
+++ b/security/nss/lib/pkcs7/secpkcs7.h
@@ -13,7 +13,7 @@
#include "secoidt.h"
#include "certt.h"
-#include "keyt.h"
+#include "keythi.h"
#include "hasht.h"
#include "pkcs7t.h"
diff --git a/security/nss/lib/smime/cms.h b/security/nss/lib/smime/cms.h
index 244df4879..f4a8a39e9 100644
--- a/security/nss/lib/smime/cms.h
+++ b/security/nss/lib/smime/cms.h
@@ -13,7 +13,7 @@
#include "secoidt.h"
#include "certt.h"
-#include "keyt.h"
+#include "keythi.h"
#include "hasht.h"
#include "cmst.h"
diff --git a/security/nss/lib/smime/cmsasn1.c b/security/nss/lib/smime/cmsasn1.c
index 15cf08fcc..8ba95d044 100644
--- a/security/nss/lib/smime/cmsasn1.c
+++ b/security/nss/lib/smime/cmsasn1.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/cmsdecode.c b/security/nss/lib/smime/cmsdecode.c
index 62b4ebfe5..69965bdd7 100644
--- a/security/nss/lib/smime/cmsdecode.c
+++ b/security/nss/lib/smime/cmsdecode.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/cmsdigest.c b/security/nss/lib/smime/cmsdigest.c
index 64b64a0f8..bd1474068 100644
--- a/security/nss/lib/smime/cmsdigest.c
+++ b/security/nss/lib/smime/cmsdigest.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secitem.h"
#include "secoid.h"
#include "pk11func.h"
diff --git a/security/nss/lib/smime/cmsencdata.c b/security/nss/lib/smime/cmsencdata.c
index c3a4549ad..d2fc3358b 100644
--- a/security/nss/lib/smime/cmsencdata.c
+++ b/security/nss/lib/smime/cmsencdata.c
@@ -8,7 +8,7 @@
#include "cmslocal.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/cmsencode.c b/security/nss/lib/smime/cmsencode.c
index 0d723e865..703492b5e 100644
--- a/security/nss/lib/smime/cmsencode.c
+++ b/security/nss/lib/smime/cmsencode.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secoid.h"
#include "secitem.h"
diff --git a/security/nss/lib/smime/cmsenvdata.c b/security/nss/lib/smime/cmsenvdata.c
index f2c8e171d..d5d5c4123 100644
--- a/security/nss/lib/smime/cmsenvdata.c
+++ b/security/nss/lib/smime/cmsenvdata.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/cmspubkey.c b/security/nss/lib/smime/cmspubkey.c
index bc3cd993e..8f18f60de 100644
--- a/security/nss/lib/smime/cmspubkey.c
+++ b/security/nss/lib/smime/cmspubkey.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/cmsrecinfo.c b/security/nss/lib/smime/cmsrecinfo.c
index 8cab288d2..20dd698e8 100644
--- a/security/nss/lib/smime/cmsrecinfo.c
+++ b/security/nss/lib/smime/cmsrecinfo.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/cmsreclist.c b/security/nss/lib/smime/cmsreclist.c
index 99d7e9087..f75347407 100644
--- a/security/nss/lib/smime/cmsreclist.c
+++ b/security/nss/lib/smime/cmsreclist.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/cmssiginfo.c b/security/nss/lib/smime/cmssiginfo.c
index ce4f87c0a..79aaf8f0a 100644
--- a/security/nss/lib/smime/cmssiginfo.c
+++ b/security/nss/lib/smime/cmssiginfo.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/cmsutil.c b/security/nss/lib/smime/cmsutil.c
index cd12603fa..713b94aac 100644
--- a/security/nss/lib/smime/cmsutil.c
+++ b/security/nss/lib/smime/cmsutil.c
@@ -9,7 +9,7 @@
#include "cmslocal.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/smimemessage.c b/security/nss/lib/smime/smimemessage.c
index 774b9f3fd..3073ab245 100644
--- a/security/nss/lib/smime/smimemessage.c
+++ b/security/nss/lib/smime/smimemessage.c
@@ -10,7 +10,7 @@
#include "smime.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
diff --git a/security/nss/lib/smime/smimeutil.c b/security/nss/lib/smime/smimeutil.c
index 7674a65fd..0e6bd32fd 100644
--- a/security/nss/lib/smime/smimeutil.c
+++ b/security/nss/lib/smime/smimeutil.c
@@ -13,7 +13,7 @@
#include "secasn1.h"
#include "secitem.h"
#include "cert.h"
-#include "key.h"
+#include "keyhi.h"
#include "secerr.h"
#include "cms.h"
#include "nss.h"
diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c
index 385d3c144..7eec3d7ee 100644
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -3106,7 +3106,7 @@ RSA_HashCheckSign(SECOidTag digestOid, NSSLOWKEYPublicKey *key,
digest.len = digestLen;
rv = _SGN_VerifyPKCS1DigestInfo(
digestOid, &digest, &pkcs1DigestInfo,
- PR_TRUE /*XXX: unsafeAllowMissingParameters*/);
+ PR_FALSE /*XXX: unsafeAllowMissingParameters*/);
}
PORT_Free(pkcs1DigestInfoData);
diff --git a/security/nss/lib/softoken/softkver.h b/security/nss/lib/softoken/softkver.h
index 827bf2e22..c1f63d769 100644
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -17,9 +17,9 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
-#define SOFTOKEN_VERSION "3.38" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION "3.41" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VMAJOR 3
-#define SOFTOKEN_VMINOR 38
+#define SOFTOKEN_VMINOR 41
#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h
index f01d16583..9be219494 100644
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -552,3 +552,15 @@ ER3(SSL_ERROR_RX_MALFORMED_DTLS_ACK, (SSL_ERROR_BASE + 174),
ER3(SSL_ERROR_DH_KEY_TOO_LONG, (SSL_ERROR_BASE + 175),
"SSL received a DH key share that's too long (>8192 bit).")
+
+ER3(SSL_ERROR_RX_MALFORMED_ESNI_KEYS, (SSL_ERROR_BASE + 176),
+ "SSL received a malformed ESNI keys structure")
+
+ER3(SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, (SSL_ERROR_BASE + 177),
+ "SSL received a malformed ESNI extension")
+
+ER3(SSL_ERROR_MISSING_ESNI_EXTENSION, (SSL_ERROR_BASE + 178),
+ "SSL did not receive an ESNI extension")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, (SSL_ERROR_BASE + 179),
+ "SSL received an unexpected record type.")
diff --git a/security/nss/lib/ssl/authcert.c b/security/nss/lib/ssl/authcert.c
index 2765c8342..d05b30a72 100644
--- a/security/nss/lib/ssl/authcert.c
+++ b/security/nss/lib/ssl/authcert.c
@@ -13,7 +13,7 @@
#include "cert.h"
#include "nspr.h"
#include "secder.h"
-#include "key.h"
+#include "keyhi.h"
#include "nss.h"
#include "ssl.h"
#include "pk11func.h" /* for PK11_ function calls */
diff --git a/security/nss/lib/ssl/cmpcert.c b/security/nss/lib/ssl/cmpcert.c
index e6edbee83..8ab4a7f8d 100644
--- a/security/nss/lib/ssl/cmpcert.c
+++ b/security/nss/lib/ssl/cmpcert.c
@@ -13,7 +13,7 @@
#include "cert.h"
#include "nspr.h"
#include "secder.h"
-#include "key.h"
+#include "keyhi.h"
#include "nss.h"
/*
@@ -27,13 +27,9 @@ NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames)
SECItem *caname;
CERTCertificate *curcert;
CERTCertificate *oldcert;
- PRInt32 contentlen;
int j;
- int headerlen;
int depth;
- SECStatus rv;
SECItem issuerName;
- SECItem compatIssuerName;
if (!cert || !caNames || !caNames->nnames || !caNames->names ||
!caNames->names->data)
@@ -44,29 +40,11 @@ NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames)
while (curcert) {
issuerName = curcert->derIssuer;
- /* compute an alternate issuer name for compatibility with 2.0
- * enterprise server, which send the CA names without
- * the outer layer of DER header
- */
- rv = DER_Lengths(&issuerName, &headerlen, (PRUint32 *)&contentlen);
- if (rv == SECSuccess) {
- compatIssuerName.data = &issuerName.data[headerlen];
- compatIssuerName.len = issuerName.len - headerlen;
- } else {
- compatIssuerName.data = NULL;
- compatIssuerName.len = 0;
- }
-
for (j = 0; j < caNames->nnames; j++) {
caname = &caNames->names[j];
if (SECITEM_CompareItem(&issuerName, caname) == SECEqual) {
- rv = SECSuccess;
CERT_DestroyCertificate(curcert);
- goto done;
- } else if (SECITEM_CompareItem(&compatIssuerName, caname) == SECEqual) {
- rv = SECSuccess;
- CERT_DestroyCertificate(curcert);
- goto done;
+ return SECSuccess;
}
}
if ((depth <= 20) &&
@@ -82,8 +60,5 @@ NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames)
curcert = NULL;
}
}
- rv = SECFailure;
-
-done:
- return rv;
+ return SECFailure;
}
diff --git a/security/nss/lib/ssl/config.mk b/security/nss/lib/ssl/config.mk
index d13613f78..b901a8830 100644
--- a/security/nss/lib/ssl/config.mk
+++ b/security/nss/lib/ssl/config.mk
@@ -60,3 +60,7 @@ endif
ifdef NSS_DISABLE_TLS_1_3
DEFINES += -DNSS_DISABLE_TLS_1_3
endif
+
+ifeq (,$(filter-out DragonFly FreeBSD Linux NetBSD OpenBSD, $(OS_TARGET)))
+CFLAGS += -std=gnu99
+endif
diff --git a/security/nss/lib/ssl/dtls13con.c b/security/nss/lib/ssl/dtls13con.c
index de6cb47ca..81d196dee 100644
--- a/security/nss/lib/ssl/dtls13con.c
+++ b/security/nss/lib/ssl/dtls13con.c
@@ -32,7 +32,7 @@ dtls13_InsertCipherTextHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
return sslBuffer_AppendNumber(wrBuf, seq, 2);
}
- rv = sslBuffer_AppendNumber(wrBuf, content_application_data, 1);
+ rv = sslBuffer_AppendNumber(wrBuf, ssl_ct_application_data, 1);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -147,7 +147,7 @@ dtls13_SendAck(sslSocket *ss)
}
ssl_GetXmitBufLock(ss);
- sent = ssl3_SendRecord(ss, NULL, content_ack,
+ sent = ssl3_SendRecord(ss, NULL, ssl_ct_ack,
buf.buf, buf.len, 0);
ssl_ReleaseXmitBufLock(ss);
if (sent != buf.len) {
@@ -343,7 +343,7 @@ dtls13_SetupAcks(sslSocket *ss)
*/
SECStatus
dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
- SSL3ContentType rType,
+ SSLContentType rType,
sslBuffer *databuf)
{
SECStatus rv;
@@ -360,7 +360,7 @@ dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
SSL_TRC(10, ("%d: DTLS13[%d]: handle out of epoch record: type=%d", SSL_GETPID(),
ss->fd, rType));
- if (rType == content_ack) {
+ if (rType == ssl_ct_ack) {
ssl_GetSSL3HandshakeLock(ss);
rv = dtls13_HandleAck(ss, &buf);
ssl_ReleaseSSL3HandshakeLock(ss);
@@ -380,7 +380,7 @@ dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
* retransmitted Finished (e.g., because our ACK got lost.)
* We just retransmit the previous Finished to let the client
* complete. */
- if (rType == content_handshake) {
+ if (rType == ssl_ct_handshake) {
if ((ss->sec.isServer) &&
(ss->ssl3.hs.ws == idle_handshake)) {
PORT_Assert(dtls_TimerActive(ss, ss->ssl3.hs.hdTimer));
diff --git a/security/nss/lib/ssl/dtls13con.h b/security/nss/lib/ssl/dtls13con.h
index ca48ef363..ce92a8a55 100644
--- a/security/nss/lib/ssl/dtls13con.h
+++ b/security/nss/lib/ssl/dtls13con.h
@@ -21,7 +21,7 @@ PRBool dtls_NextUnackedRange(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset,
PRUint32 len, PRUint32 *startOut, PRUint32 *endOut);
SECStatus dtls13_SetupAcks(sslSocket *ss);
SECStatus dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
- SSL3ContentType rType,
+ SSLContentType rType,
sslBuffer *databuf);
SECStatus dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf);
diff --git a/security/nss/lib/ssl/dtlscon.c b/security/nss/lib/ssl/dtlscon.c
index a82295c66..a5c604bca 100644
--- a/security/nss/lib/ssl/dtlscon.c
+++ b/security/nss/lib/ssl/dtlscon.c
@@ -120,7 +120,7 @@ ssl3_DisableNonDTLSSuites(sslSocket *ss)
* Called from dtls_QueueMessage()
*/
static DTLSQueuedMessage *
-dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSL3ContentType type,
+dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSLContentType ct,
const unsigned char *data, PRUint32 len)
{
DTLSQueuedMessage *msg;
@@ -138,7 +138,7 @@ dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSL3ContentType type,
msg->len = len;
msg->cwSpec = cwSpec;
- msg->type = type;
+ msg->type = ct;
/* Safe if we are < 1.3, since the refct is
* already very high. */
ssl_CipherSpecAddRef(cwSpec);
@@ -517,7 +517,7 @@ loser:
* ssl3_SendChangeCipherSpecs()
*/
SECStatus
-dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
+dtls_QueueMessage(sslSocket *ss, SSLContentType ct,
const PRUint8 *pIn, PRInt32 nIn)
{
SECStatus rv = SECSuccess;
@@ -528,7 +528,7 @@ dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
spec = ss->ssl3.cwSpec;
- msg = dtls_AllocQueuedMessage(spec, type, pIn, nIn);
+ msg = dtls_AllocQueuedMessage(spec, ct, pIn, nIn);
if (!msg) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
@@ -562,7 +562,7 @@ dtls_StageHandshakeMessage(sslSocket *ss)
if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
return rv;
- rv = dtls_QueueMessage(ss, content_handshake,
+ rv = dtls_QueueMessage(ss, ssl_ct_handshake,
ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len);
/* Whether we succeeded or failed, toss the old handshake data. */
@@ -696,7 +696,7 @@ dtls_FragmentHandshake(sslSocket *ss, DTLSQueuedMessage *msg)
PORT_Assert(msg->len >= DTLS_HS_HDR_LEN);
/* DTLS only supports fragmenting handshaking messages. */
- PORT_Assert(msg->type == content_handshake);
+ PORT_Assert(msg->type == ssl_ct_handshake);
msgSeq = (msg->data[4] << 8) | msg->data[5];
@@ -848,7 +848,7 @@ dtls_TransmitMessageFlight(sslSocket *ss)
* be quite fragmented. Adding an extra flush here would push new
* messages into new records and reduce fragmentation. */
- if (msg->type == content_handshake) {
+ if (msg->type == ssl_ct_handshake) {
rv = dtls_FragmentHandshake(ss, msg);
} else {
PORT_Assert(!tls13_MaybeTls13(ss));
@@ -1327,9 +1327,9 @@ dtls_IsLongHeader(SSL3ProtocolVersion version, PRUint8 firstOctet)
{
#ifndef UNSAFE_FUZZER_MODE
return version < SSL_LIBRARY_VERSION_TLS_1_3 ||
- firstOctet == content_handshake ||
- firstOctet == content_ack ||
- firstOctet == content_alert;
+ firstOctet == ssl_ct_handshake ||
+ firstOctet == ssl_ct_ack ||
+ firstOctet == ssl_ct_alert;
#else
return PR_TRUE;
#endif
@@ -1359,7 +1359,7 @@ dtls_ReadEpoch(const ssl3CipherSpec *crSpec, const PRUint8 *hdr)
}
/* dtls_GatherData should ensure that this works. */
- PORT_Assert(hdr[0] == content_application_data);
+ PORT_Assert(hdr[0] == ssl_ct_application_data);
/* This uses the same method as is used to recover the sequence number in
* dtls_ReadSequenceNumber, except that the maximum value is set to the
diff --git a/security/nss/lib/ssl/dtlscon.h b/security/nss/lib/ssl/dtlscon.h
index 45fc069b9..4ede3c2ca 100644
--- a/security/nss/lib/ssl/dtlscon.h
+++ b/security/nss/lib/ssl/dtlscon.h
@@ -23,7 +23,7 @@ extern SECStatus dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch,
extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss,
PRUint8 *b, PRUint32 length);
extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss);
-extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
+extern SECStatus dtls_QueueMessage(sslSocket *ss, SSLContentType type,
const PRUint8 *pIn, PRInt32 nIn);
extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss);
diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn
index ca9b9ee7b..fe9470bd0 100644
--- a/security/nss/lib/ssl/manifest.mn
+++ b/security/nss/lib/ssl/manifest.mn
@@ -1,4 +1,3 @@
-#
# 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/.
@@ -56,6 +55,7 @@ CSRCS = \
tls13replay.c \
sslcert.c \
sslgrp.c \
+ tls13esni.c \
$(NULL)
LIBRARY_NAME = ssl
diff --git a/security/nss/lib/ssl/ssl.gyp b/security/nss/lib/ssl/ssl.gyp
index 3694ab91a..2e28f6775 100644
--- a/security/nss/lib/ssl/ssl.gyp
+++ b/security/nss/lib/ssl/ssl.gyp
@@ -43,6 +43,7 @@
'ssltrace.c',
'sslver.c',
'tls13con.c',
+ 'tls13esni.c',
'tls13exthandle.c',
'tls13hashstate.c',
'tls13hkdf.c',
@@ -67,6 +68,11 @@
'UNSAFE_FUZZER_MODE',
],
}],
+ [ 'OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd" or OS=="linux"', {
+ 'cflags': [
+ '-std=gnu99',
+ ],
+ }],
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h
index ecc4f9506..fc4a4a70c 100644
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -13,7 +13,7 @@
#include "prio.h"
#include "seccomon.h"
#include "cert.h"
-#include "keyt.h"
+#include "keythi.h"
#include "sslt.h" /* public ssl data types */
@@ -282,6 +282,23 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
*/
#define SSL_ENABLE_DTLS_SHORT_HEADER 36
+/*
+ * Enables the processing of the downgrade sentinel that can be added to the
+ * ServerHello.random by a server that supports Section 4.1.3 of TLS 1.3
+ * [RFC8446]. This sentinel will always be generated by a server that
+ * negotiates a version lower than its maximum, this only controls whether a
+ * client will treat receipt of a value that indicates a downgrade as an error.
+ */
+#define SSL_ENABLE_HELLO_DOWNGRADE_CHECK 37
+
+/* Enables the SSLv2-compatible ClientHello for servers. NSS does not support
+ * SSLv2 and will never send an SSLv2-compatible ClientHello as a client. An
+ * NSS server with this option enabled will accept a ClientHello that is
+ * v2-compatible as defined in Appendix E.1 of RFC 6101.
+ *
+ * This is disabled by default and will be removed in a future version. */
+#define SSL_ENABLE_V2_COMPATIBLE_HELLO 38
+
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 466fc296f..3b5c69b11 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -93,8 +93,8 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
{ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
- { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
- { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE},
/* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is out of order to work around
* bug 946147.
*/
@@ -114,7 +114,7 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
{ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,SSL_ALLOWED,PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
- { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
@@ -143,7 +143,7 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
/* RSA */
{ TLS_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
- { TLS_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
@@ -501,19 +501,19 @@ ssl3_DecodeContentType(int msgType)
static char line[40];
switch (msgType) {
- case content_change_cipher_spec:
+ case ssl_ct_change_cipher_spec:
rv = "change_cipher_spec (20)";
break;
- case content_alert:
+ case ssl_ct_alert:
rv = "alert (21)";
break;
- case content_handshake:
+ case ssl_ct_handshake:
rv = "handshake (22)";
break;
- case content_application_data:
+ case ssl_ct_application_data:
rv = "application_data (23)";
break;
- case content_ack:
+ case ssl_ct_ack:
rv = "ack (25)";
break;
default:
@@ -656,7 +656,7 @@ ssl_LookupCipherSuiteCfgMutable(ssl3CipherSuite suite,
return NULL;
}
-const static ssl3CipherSuiteCfg *
+const ssl3CipherSuiteCfg *
ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, const ssl3CipherSuiteCfg *suites)
{
return ssl_LookupCipherSuiteCfgMutable(suite,
@@ -765,6 +765,9 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType)
}
return PR_TRUE;
}
+ if (authType == ssl_auth_rsa_sign) {
+ return ssl_HasCert(ss, ssl_auth_rsa_pss);
+ }
return PR_FALSE;
}
@@ -851,9 +854,9 @@ ssl3_config_match_init(sslSocket *ss)
/* Return PR_TRUE if suite is usable. This if the suite is permitted by policy,
* enabled, has a certificate (as needed), has a viable key agreement method, is
* usable with the negotiated TLS version, and is otherwise usable. */
-static PRBool
-config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
- const SSLVersionRange *vrange, const sslSocket *ss)
+PRBool
+ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
+ const SSLVersionRange *vrange, const sslSocket *ss)
{
const ssl3CipherSuiteDef *cipher_def;
const ssl3KEADef *kea_def;
@@ -896,7 +899,7 @@ count_cipher_suites(sslSocket *ss, PRUint8 policy)
return 0;
}
for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
- if (config_match(&ss->cipherSuites[i], policy, &ss->vrange, ss))
+ if (ssl3_config_match(&ss->cipherSuites[i], policy, &ss->vrange, ss))
count++;
}
if (count == 0) {
@@ -1120,6 +1123,8 @@ ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key,
if (ss->sec.isServer) {
ss->sec.signatureScheme = ss->ssl3.hs.signatureScheme;
+ ss->sec.authType =
+ ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
}
PRINT_BUF(60, (NULL, "signed hashes", (unsigned char *)buf->data, buf->len));
done:
@@ -1255,6 +1260,7 @@ ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *ha
}
if (!ss->sec.isServer) {
ss->sec.signatureScheme = scheme;
+ ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme);
}
loser:
@@ -1506,7 +1512,7 @@ loser:
static SECStatus
ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch,
sslSequenceNumber seqNum,
- SSL3ContentType type,
+ SSLContentType ct,
PRBool includesVersion,
SSL3ProtocolVersion version,
PRBool isDTLS,
@@ -1526,7 +1532,7 @@ ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch,
if (rv != SECSuccess) {
return SECFailure;
}
- rv = sslBuffer_AppendNumber(buf, type, 1);
+ rv = sslBuffer_AppendNumber(buf, ct, 1);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -1994,7 +2000,7 @@ SECStatus
ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
PRBool isServer,
PRBool isDTLS,
- SSL3ContentType type,
+ SSLContentType ct,
const PRUint8 *pIn,
PRUint32 contentLen,
sslBuffer *wrBuf)
@@ -2041,7 +2047,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
}
rv = ssl3_BuildRecordPseudoHeader(
- cwSpec->epoch, cwSpec->nextSeqNum, type,
+ cwSpec->epoch, cwSpec->nextSeqNum, ct,
cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->recordVersion,
isDTLS, contentLen, &pseudoHeader);
PORT_Assert(rv == SECSuccess);
@@ -2163,7 +2169,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
/* Note: though this can report failure, it shouldn't. */
SECStatus
ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
- SSL3ContentType contentType, sslBuffer *wrBuf,
+ SSLContentType contentType, sslBuffer *wrBuf,
PRBool *needsLength)
{
SECStatus rv;
@@ -2175,7 +2181,7 @@ ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
return dtls13_InsertCipherTextHeader(ss, cwSpec, wrBuf,
needsLength);
}
- contentType = content_application_data;
+ contentType = ssl_ct_application_data;
}
#endif
rv = sslBuffer_AppendNumber(wrBuf, contentType, 1);
@@ -2202,7 +2208,7 @@ ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
}
SECStatus
-ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type,
+ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct,
const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf)
{
PRBool needsLength;
@@ -2222,7 +2228,7 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type,
return SECFailure;
}
- rv = ssl_InsertRecordHeader(ss, cwSpec, type, wrBuf, &needsLength);
+ rv = ssl_InsertRecordHeader(ss, cwSpec, ct, wrBuf, &needsLength);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -2246,9 +2252,9 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type,
}
#else
if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
- rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, wrBuf);
+ rv = tls13_ProtectRecord(ss, cwSpec, ct, pIn, contentLen, wrBuf);
} else {
- rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), type,
+ rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), ct,
pIn, contentLen, wrBuf);
}
#endif
@@ -2270,7 +2276,7 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type,
}
SECStatus
-ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type,
+ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSLContentType ct,
const PRUint8 *pIn, unsigned int nIn,
unsigned int *written)
{
@@ -2294,7 +2300,7 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type,
}
}
- rv = ssl_ProtectRecord(ss, spec, type, pIn, contentLen, wrBuf);
+ rv = ssl_ProtectRecord(ss, spec, ct, pIn, contentLen, wrBuf);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -2328,7 +2334,7 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type,
PRInt32
ssl3_SendRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec, /* non-NULL for DTLS retransmits */
- SSL3ContentType type,
+ SSLContentType ct,
const PRUint8 *pIn, /* input buffer */
PRInt32 nIn, /* bytes of input */
PRInt32 flags)
@@ -2339,7 +2345,7 @@ ssl3_SendRecord(sslSocket *ss,
PRInt32 totalSent = 0;
SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
- SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
+ SSL_GETPID(), ss->fd, ssl3_DecodeContentType(ct),
nIn));
PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn));
@@ -2349,7 +2355,7 @@ ssl3_SendRecord(sslSocket *ss,
if (ss->ssl3.fatalAlertSent) {
SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
SSL_GETPID(), ss->fd));
- if (type != content_alert) {
+ if (ct != ssl_ct_alert) {
/* If we are sending an alert, then we already have an
* error, so don't overwrite. */
PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
@@ -2366,8 +2372,8 @@ ssl3_SendRecord(sslSocket *ss,
if (cwSpec) {
/* cwSpec can only be set for retransmissions of the DTLS handshake. */
PORT_Assert(IS_DTLS(ss) &&
- (type == content_handshake ||
- type == content_change_cipher_spec));
+ (ct == ssl_ct_handshake ||
+ ct == ssl_ct_change_cipher_spec));
spec = cwSpec;
} else {
spec = ss->ssl3.cwSpec;
@@ -2378,7 +2384,7 @@ ssl3_SendRecord(sslSocket *ss,
PRInt32 sent;
ssl_GetSpecReadLock(ss);
- rv = ssl_ProtectNextRecord(ss, spec, type, pIn, nIn, &written);
+ rv = ssl_ProtectNextRecord(ss, spec, ct, pIn, nIn, &written);
ssl_ReleaseSpecReadLock(ss);
if (rv != SECSuccess) {
goto loser;
@@ -2386,7 +2392,7 @@ ssl3_SendRecord(sslSocket *ss,
PORT_Assert(written > 0);
/* DTLS should not fragment non-application data here. */
- if (IS_DTLS(ss) && type != content_application_data) {
+ if (IS_DTLS(ss) && ct != ssl_ct_application_data) {
PORT_Assert(written == nIn);
}
@@ -2535,7 +2541,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
* Note that the 0 epoch is OK because flags will never require
* its use, as guaranteed by the PORT_Assert above.
*/
- sent = ssl3_SendRecord(ss, NULL, content_application_data,
+ sent = ssl3_SendRecord(ss, NULL, ssl_ct_application_data,
in + totalSent, toSend, flags);
if (sent < 0) {
if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) {
@@ -2618,7 +2624,7 @@ ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
- count = ssl3_SendRecord(ss, NULL, content_handshake,
+ count = ssl3_SendRecord(ss, NULL, ssl_ct_handshake,
ss->sec.ci.sendBuf.buf,
ss->sec.ci.sendBuf.len, flags);
if (count < 0) {
@@ -2744,7 +2750,7 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
if (rv == SECSuccess) {
PRInt32 sent;
- sent = ssl3_SendRecord(ss, NULL, content_alert, bytes, 2,
+ sent = ssl3_SendRecord(ss, NULL, ssl_ct_alert, bytes, 2,
(desc == no_certificate) ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
}
@@ -3041,13 +3047,13 @@ ssl3_SendChangeCipherSpecsInt(sslSocket *ss)
if (!IS_DTLS(ss)) {
PRInt32 sent;
- sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec,
+ sent = ssl3_SendRecord(ss, NULL, ssl_ct_change_cipher_spec,
&change, 1, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
if (sent < 0) {
return SECFailure; /* error code set by ssl3_SendRecord */
}
} else {
- rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1);
+ rv = dtls_QueueMessage(ss, ssl_ct_change_cipher_spec, &change, 1);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -4002,8 +4008,8 @@ ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme)
return ssl_hash_none;
}
-KeyType
-ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme)
+static PRBool
+ssl_SignatureSchemeMatchesSpkiOid(SSLSignatureScheme scheme, SECOidTag spkiOid)
{
switch (scheme) {
case ssl_sig_rsa_pkcs1_sha256:
@@ -4013,133 +4019,243 @@ ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme)
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_rsae_sha512:
+ case ssl_sig_rsa_pkcs1_sha1md5:
+ return (spkiOid == SEC_OID_X500_RSA_ENCRYPTION) ||
+ (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION);
case ssl_sig_rsa_pss_pss_sha256:
case ssl_sig_rsa_pss_pss_sha384:
case ssl_sig_rsa_pss_pss_sha512:
- case ssl_sig_rsa_pkcs1_sha1md5:
- return rsaKey;
+ return spkiOid == SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
case ssl_sig_ecdsa_secp521r1_sha512:
case ssl_sig_ecdsa_sha1:
- return ecKey;
+ return spkiOid == SEC_OID_ANSIX962_EC_PUBLIC_KEY;
case ssl_sig_dsa_sha256:
case ssl_sig_dsa_sha384:
case ssl_sig_dsa_sha512:
case ssl_sig_dsa_sha1:
- return dsaKey;
+ return spkiOid == SEC_OID_ANSIX9_DSA_SIGNATURE;
case ssl_sig_none:
case ssl_sig_ed25519:
case ssl_sig_ed448:
break;
}
PORT_Assert(0);
- return nullKey;
+ return PR_FALSE;
}
-static SSLNamedGroup
-ssl_NamedGroupForSignatureScheme(SSLSignatureScheme scheme)
+/* Validate that the signature scheme works for the given key type. */
+static PRBool
+ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
+ PRBool isTls13)
{
- switch (scheme) {
- case ssl_sig_ecdsa_secp256r1_sha256:
- return ssl_grp_ec_secp256r1;
- case ssl_sig_ecdsa_secp384r1_sha384:
- return ssl_grp_ec_secp384r1;
- case ssl_sig_ecdsa_secp521r1_sha512:
- return ssl_grp_ec_secp521r1;
- default:
+ if (!ssl_IsSupportedSignatureScheme(scheme)) {
+ return PR_FALSE;
+ }
+ if (!ssl_SignatureSchemeMatchesSpkiOid(scheme, spkiOid)) {
+ return PR_FALSE;
+ }
+ if (isTls13) {
+ if (ssl_SignatureSchemeToHashType(scheme) == ssl_hash_sha1) {
+ return PR_FALSE;
+ }
+ /* With TLS 1.3, EC keys should have been selected based on calling
+ * ssl_SignatureSchemeFromSpki(), reject them otherwise. */
+ return spkiOid != SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+ }
+ return PR_TRUE;
+}
+
+static SECStatus
+ssl_SignatureSchemeFromPssSpki(CERTSubjectPublicKeyInfo *spki,
+ SSLSignatureScheme *scheme)
+{
+ SECKEYRSAPSSParams pssParam = { 0 };
+ PORTCheapArenaPool arena;
+ SECStatus rv;
+
+ /* The key doesn't have parameters, boo. */
+ if (!spki->algorithm.parameters.len) {
+ *scheme = ssl_sig_none;
+ return SECSuccess;
+ }
+
+ PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
+ rv = SEC_QuickDERDecodeItem(&arena.arena, &pssParam,
+ SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate),
+ &spki->algorithm.parameters);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* Not having hashAlg means SHA-1 and we don't accept that. */
+ if (!pssParam.hashAlg) {
+ goto loser;
+ }
+ switch (SECOID_GetAlgorithmTag(pssParam.hashAlg)) {
+ case SEC_OID_SHA256:
+ *scheme = ssl_sig_rsa_pss_pss_sha256;
break;
+ case SEC_OID_SHA384:
+ *scheme = ssl_sig_rsa_pss_pss_sha384;
+ break;
+ case SEC_OID_SHA512:
+ *scheme = ssl_sig_rsa_pss_pss_sha512;
+ break;
+ default:
+ goto loser;
}
- PORT_Assert(0);
- return 0;
+
+ PORT_DestroyCheapArena(&arena);
+ return SECSuccess;
+
+loser:
+ PORT_DestroyCheapArena(&arena);
+ PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
+ return SECFailure;
}
-/* Validate that the signature scheme works for the given key.
- * If |allowSha1| is set, we allow the use of SHA-1.
- * If |matchGroup| is set, we also check that the group and hash match. */
-static PRBool
-ssl_SignatureSchemeValidForKey(PRBool allowSha1, PRBool matchGroup,
- KeyType keyType,
- const sslNamedGroupDef *ecGroup,
- SSLSignatureScheme scheme)
+static SECStatus
+ssl_SignatureSchemeFromEcSpki(CERTSubjectPublicKeyInfo *spki,
+ SSLSignatureScheme *scheme)
{
- if (!ssl_IsSupportedSignatureScheme(scheme)) {
- return PR_FALSE;
+ const sslNamedGroupDef *group;
+ SECKEYPublicKey *key;
+
+ key = SECKEY_ExtractPublicKey(spki);
+ if (!key) {
+ PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
+ return SECFailure;
}
- if (keyType != ssl_SignatureSchemeToKeyType(scheme)) {
- return PR_FALSE;
+ group = ssl_ECPubKey2NamedGroup(key);
+ SECKEY_DestroyPublicKey(key);
+ if (!group) {
+ PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
+ return SECFailure;
}
- if (!allowSha1 && ssl_SignatureSchemeToHashType(scheme) == ssl_hash_sha1) {
- return PR_FALSE;
+ switch (group->name) {
+ case ssl_grp_ec_secp256r1:
+ *scheme = ssl_sig_ecdsa_secp256r1_sha256;
+ return SECSuccess;
+ case ssl_grp_ec_secp384r1:
+ *scheme = ssl_sig_ecdsa_secp384r1_sha384;
+ return SECSuccess;
+ case ssl_grp_ec_secp521r1:
+ *scheme = ssl_sig_ecdsa_secp521r1_sha512;
+ return SECSuccess;
+ default:
+ break;
}
- if (keyType != ecKey) {
- return PR_TRUE;
+ PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
+ return SECFailure;
+}
+
+/* Newer signature schemes are designed so that a single SPKI can be used with
+ * that scheme. This determines that scheme from the SPKI. If the SPKI doesn't
+ * have a single scheme, |*scheme| is set to ssl_sig_none. */
+static SECStatus
+ssl_SignatureSchemeFromSpki(CERTSubjectPublicKeyInfo *spki,
+ PRBool isTls13, SSLSignatureScheme *scheme)
+{
+ SECOidTag spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm);
+
+ if (spkiOid == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
+ return ssl_SignatureSchemeFromPssSpki(spki, scheme);
}
- if (!ecGroup) {
- return PR_FALSE;
+
+ /* Only do this lookup for TLS 1.3, where the scheme can be determined from
+ * the SPKI alone because the ECDSA key size determines the hash. Earlier
+ * TLS versions allow the same EC key to be used with different hashes. */
+ if (isTls13 && spkiOid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
+ return ssl_SignatureSchemeFromEcSpki(spki, scheme);
}
- /* If |allowSha1| is present and the scheme is ssl_sig_ecdsa_sha1, it's OK.
- * This scheme isn't bound to a specific group. */
- if (allowSha1 && (scheme == ssl_sig_ecdsa_sha1)) {
- return PR_TRUE;
+
+ *scheme = ssl_sig_none;
+ return SECSuccess;
+}
+
+static PRBool
+ssl_SignatureSchemeEnabled(sslSocket *ss, SSLSignatureScheme scheme)
+{
+ unsigned int i;
+ for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ if (scheme == ss->ssl3.signatureSchemes[i]) {
+ return PR_TRUE;
+ }
}
- if (!matchGroup) {
- return PR_TRUE;
+ return PR_FALSE;
+}
+
+static PRBool
+ssl_SignatureKeyMatchesSpkiOid(const ssl3KEADef *keaDef, SECOidTag spkiOid)
+{
+ switch (spkiOid) {
+ case SEC_OID_X500_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
+ return keaDef->signKeyType == rsaKey;
+ case SEC_OID_ANSIX9_DSA_SIGNATURE:
+ return keaDef->signKeyType == dsaKey;
+ case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+ return keaDef->signKeyType == ecKey;
+ default:
+ break;
}
- return ecGroup->name == ssl_NamedGroupForSignatureScheme(scheme);
+ return PR_FALSE;
}
-/* ssl3_CheckSignatureSchemeConsistency checks that the signature
- * algorithm identifier in |sigAndHash| is consistent with the public key in
- * |cert|. It also checks the hash algorithm against the configured signature
- * algorithms. If all the tests pass, SECSuccess is returned. Otherwise,
- * PORT_SetError is called and SECFailure is returned. */
+/* ssl3_CheckSignatureSchemeConsistency checks that the signature algorithm
+ * identifier in |scheme| is consistent with the public key in |cert|. It also
+ * checks the hash algorithm against the configured signature algorithms. If
+ * all the tests pass, SECSuccess is returned. Otherwise, PORT_SetError is
+ * called and SECFailure is returned. */
SECStatus
-ssl_CheckSignatureSchemeConsistency(
- sslSocket *ss, SSLSignatureScheme scheme, CERTCertificate *cert)
+ssl_CheckSignatureSchemeConsistency(sslSocket *ss, SSLSignatureScheme scheme,
+ CERTCertificate *cert)
{
- unsigned int i;
- const sslNamedGroupDef *group = NULL;
- SECKEYPublicKey *key;
- KeyType keyType;
+ SSLSignatureScheme spkiScheme;
PRBool isTLS13 = ss->version == SSL_LIBRARY_VERSION_TLS_1_3;
+ SECOidTag spkiOid;
+ SECStatus rv;
- key = CERT_ExtractPublicKey(cert);
- if (key == NULL) {
- ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo, isTLS13,
+ &spkiScheme);
+ if (rv != SECSuccess) {
return SECFailure;
}
-
- keyType = SECKEY_GetPublicKeyType(key);
- if (keyType == ecKey) {
- group = ssl_ECPubKey2NamedGroup(key);
+ if (spkiScheme != ssl_sig_none) {
+ /* The SPKI in the certificate can only be used for a single scheme. */
+ if (spkiScheme != scheme ||
+ !ssl_SignatureSchemeEnabled(ss, scheme)) {
+ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+ return SECFailure;
+ }
+ return SECSuccess;
}
- SECKEY_DestroyPublicKey(key);
+
+ spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
/* If we're a client, check that the signature algorithm matches the signing
* key type of the cipher suite. */
- if (!isTLS13 &&
- !ss->sec.isServer &&
- ss->ssl3.hs.kea_def->signKeyType != keyType) {
- PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
- return SECFailure;
+ if (!isTLS13 && !ss->sec.isServer) {
+ if (!ssl_SignatureKeyMatchesSpkiOid(ss->ssl3.hs.kea_def, spkiOid)) {
+ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+ return SECFailure;
+ }
}
/* Verify that the signature scheme matches the signing key. */
- if (!ssl_SignatureSchemeValidForKey(!isTLS13 /* allowSha1 */,
- isTLS13 /* matchGroup */,
- keyType, group, scheme)) {
+ if (!ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13)) {
PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
return SECFailure;
}
- for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
- if (scheme == ss->ssl3.signatureSchemes[i]) {
- return SECSuccess;
- }
+ if (!ssl_SignatureSchemeEnabled(ss, scheme)) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ return SECFailure;
}
- PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
- return SECFailure;
+
+ return SECSuccess;
}
PRBool
@@ -4153,6 +4269,9 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_rsae_sha512:
+ case ssl_sig_rsa_pss_pss_sha256:
+ case ssl_sig_rsa_pss_pss_sha384:
+ case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
case ssl_sig_ecdsa_secp521r1_sha512:
@@ -4164,9 +4283,6 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
return PR_TRUE;
case ssl_sig_rsa_pkcs1_sha1md5:
- case ssl_sig_rsa_pss_pss_sha256:
- case ssl_sig_rsa_pss_pss_sha384:
- case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_none:
case ssl_sig_ed25519:
case ssl_sig_ed448:
@@ -4182,6 +4298,9 @@ ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme)
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_rsae_sha512:
+ case ssl_sig_rsa_pss_pss_sha256:
+ case ssl_sig_rsa_pss_pss_sha384:
+ case ssl_sig_rsa_pss_pss_sha512:
return PR_TRUE;
default:
@@ -4190,6 +4309,41 @@ ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme)
return PR_FALSE;
}
+SSLAuthType
+ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
+{
+ switch (scheme) {
+ case ssl_sig_rsa_pkcs1_sha1:
+ case ssl_sig_rsa_pkcs1_sha1md5:
+ case ssl_sig_rsa_pkcs1_sha256:
+ case ssl_sig_rsa_pkcs1_sha384:
+ case ssl_sig_rsa_pkcs1_sha512:
+ /* We report based on the key type for PSS signatures. */
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
+ return ssl_auth_rsa_sign;
+ case ssl_sig_rsa_pss_pss_sha256:
+ case ssl_sig_rsa_pss_pss_sha384:
+ case ssl_sig_rsa_pss_pss_sha512:
+ return ssl_auth_rsa_pss;
+ case ssl_sig_ecdsa_secp256r1_sha256:
+ case ssl_sig_ecdsa_secp384r1_sha384:
+ case ssl_sig_ecdsa_secp521r1_sha512:
+ case ssl_sig_ecdsa_sha1:
+ return ssl_auth_ecdsa;
+ case ssl_sig_dsa_sha1:
+ case ssl_sig_dsa_sha256:
+ case ssl_sig_dsa_sha384:
+ case ssl_sig_dsa_sha512:
+ return ssl_auth_dsa;
+
+ default:
+ PORT_Assert(0);
+ }
+ return ssl_auth_null;
+}
+
/* ssl_ConsumeSignatureScheme reads a SSLSignatureScheme (formerly
* SignatureAndHashAlgorithm) structure from |b| and puts the resulting value
* into |out|. |b| and |length| are updated accordingly.
@@ -4617,9 +4771,13 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
* If we have an sid and it comes from an external cache, we use it. */
if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
PORT_Assert(!ss->sec.isServer);
- sid = ss->sec.ci.sid;
+ sid = ssl_ReferenceSID(ss->sec.ci.sid);
SSL_TRC(3, ("%d: SSL3[%d]: using external resumption token in ClientHello",
SSL_GETPID(), ss->fd));
+ } else if (ss->sec.ci.sid && ss->statelessResume && type == client_hello_retry) {
+ /* If we are sending a second ClientHello, reuse the same SID
+ * as the original one. */
+ sid = ssl_ReferenceSID(ss->sec.ci.sid);
} else if (!ss->opt.noCache) {
/* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
* handles expired entries and other details.
@@ -4644,7 +4802,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
suite = ssl_LookupCipherSuiteCfg(sid->u.ssl3.cipherSuite,
ss->cipherSuites);
PORT_Assert(suite);
- if (!suite || !config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
+ if (!suite || !ssl3_config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
sidOK = PR_FALSE;
}
@@ -4765,9 +4923,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
ssl_ReleaseSpecWriteLock(ss);
- if (ss->sec.ci.sid != NULL) {
- ssl_FreeSID(ss->sec.ci.sid); /* decrement ref count, free if zero */
- }
+ ssl_FreeSID(ss->sec.ci.sid); /* release the old sid */
ss->sec.ci.sid = sid;
/* HACK for SCSV in SSL 3.0. On initial handshake, prepend SCSV,
@@ -4792,6 +4948,14 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
PR_RWLock_Rlock(sid->u.ssl3.lock);
}
+ /* Generate a new random if this is the first attempt. */
+ if (type == client_hello_initial) {
+ rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random);
+ if (rv != SECSuccess) {
+ goto loser; /* err set by GetNewRandom. */
+ }
+ }
+
if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3 &&
type == client_hello_initial) {
rv = tls13_SetupClientHello(ss);
@@ -4799,6 +4963,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
goto loser;
}
}
+
if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) {
rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_client_hello);
if (rv != SECSuccess) {
@@ -4870,13 +5035,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
goto loser; /* err set by ssl3_AppendHandshake* */
}
- /* Generate a new random if this is the first attempt. */
- if (type == client_hello_initial) {
- rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random);
- if (rv != SECSuccess) {
- goto loser; /* err set by GetNewRandom. */
- }
- }
rv = ssl3_AppendHandshake(ss, ss->ssl3.hs.client_random,
SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
@@ -4931,7 +5089,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
- if (config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
+ if (ssl3_config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
actual_count++;
if (actual_count > num_suites) {
/* set error card removal/insertion error */
@@ -5394,6 +5552,7 @@ ssl3_GetWrappingKey(sslSocket *ss,
switch (authType) {
case ssl_auth_rsa_decrypt:
case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
+ case ssl_auth_rsa_pss:
asymWrapMechanism = CKM_RSA_PKCS;
rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey,
unwrappedWrappingKey, &wrappedKey);
@@ -5843,20 +6002,59 @@ ssl3_SendClientKeyExchange(sslSocket *ss)
return rv; /* err code already set. */
}
+/* Used by ssl_PickSignatureScheme(). */
+static PRBool
+ssl_CanUseSignatureScheme(SSLSignatureScheme scheme,
+ const SSLSignatureScheme *peerSchemes,
+ unsigned int peerSchemeCount,
+ PRBool requireSha1,
+ PRBool slotDoesPss)
+{
+ SSLHashType hashType;
+ SECOidTag hashOID;
+ PRUint32 policy;
+ unsigned int i;
+
+ /* Skip RSA-PSS schemes when the certificate's private key slot does
+ * not support this signature mechanism. */
+ if (ssl_IsRsaPssSignatureScheme(scheme) && !slotDoesPss) {
+ return PR_FALSE;
+ }
+
+ hashType = ssl_SignatureSchemeToHashType(scheme);
+ if (requireSha1 && (hashType != ssl_hash_sha1)) {
+ return PR_FALSE;
+ }
+ hashOID = ssl3_HashTypeToOID(hashType);
+ if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
+ !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+ return PR_FALSE;
+ }
+
+ for (i = 0; i < peerSchemeCount; i++) {
+ if (peerSchemes[i] == scheme) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+}
+
SECStatus
ssl_PickSignatureScheme(sslSocket *ss,
+ CERTCertificate *cert,
SECKEYPublicKey *pubKey,
SECKEYPrivateKey *privKey,
const SSLSignatureScheme *peerSchemes,
unsigned int peerSchemeCount,
PRBool requireSha1)
{
- unsigned int i, j;
- const sslNamedGroupDef *group = NULL;
- KeyType keyType;
+ unsigned int i;
PK11SlotInfo *slot;
PRBool slotDoesPss;
PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
+ SECStatus rv;
+ SSLSignatureScheme scheme;
+ SECOidTag spkiOid;
/* We can't require SHA-1 in TLS 1.3. */
PORT_Assert(!(requireSha1 && isTLS13));
@@ -5874,47 +6072,35 @@ ssl_PickSignatureScheme(sslSocket *ss,
slotDoesPss = PK11_DoesMechanism(slot, auth_alg_defs[ssl_auth_rsa_pss]);
PK11_FreeSlot(slot);
- keyType = SECKEY_GetPublicKeyType(pubKey);
- if (keyType == ecKey) {
- group = ssl_ECPubKey2NamedGroup(pubKey);
+ /* If the certificate SPKI indicates a single scheme, don't search. */
+ rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo,
+ isTLS13, &scheme);
+ if (rv != SECSuccess) {
+ return SECFailure;
}
-
- /* Here we look for the first local preference that the client has
- * indicated support for in their signature_algorithms extension. */
- for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
- SSLHashType hashType;
- SECOidTag hashOID;
- SSLSignatureScheme preferred = ss->ssl3.signatureSchemes[i];
- PRUint32 policy;
-
- if (!ssl_SignatureSchemeValidForKey(!isTLS13 /* allowSha1 */,
- isTLS13 /* matchGroup */,
- keyType, group, preferred)) {
- continue;
+ if (scheme != ssl_sig_none) {
+ if (!ssl_SignatureSchemeEnabled(ss, scheme) ||
+ !ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount,
+ requireSha1, slotDoesPss)) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ return SECFailure;
}
+ ss->ssl3.hs.signatureScheme = scheme;
+ return SECSuccess;
+ }
- /* Skip RSA-PSS schemes when the certificate's private key slot does
- * not support this signature mechanism. */
- if (ssl_IsRsaPssSignatureScheme(preferred) && !slotDoesPss) {
- continue;
- }
+ spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
- hashType = ssl_SignatureSchemeToHashType(preferred);
- if (requireSha1 && (hashType != ssl_hash_sha1)) {
- continue;
- }
- hashOID = ssl3_HashTypeToOID(hashType);
- if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
- !(policy & NSS_USE_ALG_IN_SSL_KX)) {
- /* we ignore hashes we don't support */
- continue;
- }
+ /* Now we have to search based on the key type. Go through our preferred
+ * schemes in order and find the first that can be used. */
+ for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ scheme = ss->ssl3.signatureSchemes[i];
- for (j = 0; j < peerSchemeCount; j++) {
- if (peerSchemes[j] == preferred) {
- ss->ssl3.hs.signatureScheme = preferred;
- return SECSuccess;
- }
+ if (ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13) &&
+ ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount,
+ requireSha1, slotDoesPss)) {
+ ss->ssl3.hs.signatureScheme = scheme;
+ return SECSuccess;
}
}
@@ -5956,17 +6142,19 @@ ssl_PickFallbackSignatureScheme(sslSocket *ss, SECKEYPublicKey *pubKey)
static SECStatus
ssl3_PickServerSignatureScheme(sslSocket *ss)
{
- sslKeyPair *keyPair = ss->sec.serverCert->serverKeyPair;
+ const sslServerCert *cert = ss->sec.serverCert;
PRBool isTLS12 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_2;
if (!isTLS12 || !ssl3_ExtensionNegotiated(ss, ssl_signature_algorithms_xtn)) {
/* If the client didn't provide any signature_algorithms extension then
* we can assume that they support SHA-1: RFC5246, Section 7.4.1.4.1. */
- return ssl_PickFallbackSignatureScheme(ss, keyPair->pubKey);
+ return ssl_PickFallbackSignatureScheme(ss, cert->serverKeyPair->pubKey);
}
/* Sets error code, if needed. */
- return ssl_PickSignatureScheme(ss, keyPair->pubKey, keyPair->privKey,
+ return ssl_PickSignatureScheme(ss, cert->serverCert,
+ cert->serverKeyPair->pubKey,
+ cert->serverKeyPair->privKey,
ss->xtnData.sigSchemes,
ss->xtnData.numSigSchemes,
PR_FALSE /* requireSha1 */);
@@ -5977,23 +6165,18 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
unsigned int numSchemes)
{
SECKEYPrivateKey *privKey = ss->ssl3.clientPrivateKey;
- SECKEYPublicKey *pubKey;
SECStatus rv;
-
PRBool isTLS13 = (PRBool)ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
- pubKey = CERT_ExtractPublicKey(ss->ssl3.clientCertificate);
+ SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(ss->ssl3.clientCertificate);
+
PORT_Assert(pubKey);
- if (!isTLS13 && numSchemes == 0) {
- /* If the server didn't provide any signature algorithms
- * then let's assume they support SHA-1. */
- rv = ssl_PickFallbackSignatureScheme(ss, pubKey);
- SECKEY_DestroyPublicKey(pubKey);
- return rv;
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ /* We should have already checked that a signature scheme was
+ * listed in the request. */
+ PORT_Assert(schemes && numSchemes > 0);
}
- PORT_Assert(schemes && numSchemes > 0);
-
if (!isTLS13 &&
(SECKEY_GetPublicKeyType(pubKey) == rsaKey ||
SECKEY_GetPublicKeyType(pubKey) == dsaKey) &&
@@ -6004,7 +6187,8 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
* older, DSA key size is at most 1024 bits and the hash function must
* be SHA-1.
*/
- rv = ssl_PickSignatureScheme(ss, pubKey, privKey, schemes, numSchemes,
+ rv = ssl_PickSignatureScheme(ss, ss->ssl3.clientCertificate,
+ pubKey, privKey, schemes, numSchemes,
PR_TRUE /* requireSha1 */);
if (rv == SECSuccess) {
SECKEY_DestroyPublicKey(pubKey);
@@ -6013,7 +6197,8 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
/* If this fails, that's because the peer doesn't advertise SHA-1,
* so fall back to the full negotiation. */
}
- rv = ssl_PickSignatureScheme(ss, pubKey, privKey, schemes, numSchemes,
+ rv = ssl_PickSignatureScheme(ss, ss->ssl3.clientCertificate,
+ pubKey, privKey, schemes, numSchemes,
PR_FALSE /* requireSha1 */);
SECKEY_DestroyPublicKey(pubKey);
return rv;
@@ -6141,7 +6326,7 @@ ssl_ClientSetCipherSuite(sslSocket *ss, SSL3ProtocolVersion version,
ssl3CipherSuiteCfg *suiteCfg = &ss->cipherSuites[i];
if (suite == suiteCfg->cipher_suite) {
SSLVersionRange vrange = { version, version };
- if (!config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) {
+ if (!ssl3_config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) {
/* config_match already checks whether the cipher suite is
* acceptable for the version, but the check is repeated here
* in order to give a more precise error code. */
@@ -6201,18 +6386,56 @@ ssl_CheckServerSessionIdCorrectness(sslSocket *ss, SECItem *sidBytes)
/* TLS 1.2: Session ID shouldn't match if we sent a fake. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- return !sentFakeSid || !sidMatch;
+ if (sentFakeSid) {
+ return !sidMatch;
+ }
+ return PR_TRUE;
}
/* TLS 1.3: We sent a session ID. The server's should match. */
- if (sentRealSid || sentFakeSid) {
+ if (!IS_DTLS(ss) && (sentRealSid || sentFakeSid)) {
return sidMatch;
}
- /* TLS 1.3: The server shouldn't send a session ID. */
+ /* TLS 1.3 (no SID)/DTLS 1.3: The server shouldn't send a session ID. */
return sidBytes->len == 0;
}
+static SECStatus
+ssl_CheckServerRandom(sslSocket *ss)
+{
+ /* Check the ServerHello.random per [RFC 8446 Section 4.1.3].
+ *
+ * TLS 1.3 clients receiving a ServerHello indicating TLS 1.2 or below
+ * MUST check that the last 8 bytes are not equal to either of these
+ * values. TLS 1.2 clients SHOULD also check that the last 8 bytes are
+ * not equal to the second value if the ServerHello indicates TLS 1.1 or
+ * below. If a match is found, the client MUST abort the handshake with
+ * an "illegal_parameter" alert.
+ */
+ SSL3ProtocolVersion checkVersion =
+ ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion
+ : ss->vrange.max;
+
+ if (checkVersion >= SSL_LIBRARY_VERSION_TLS_1_2 &&
+ checkVersion > ss->version) {
+ /* Both sections use the same sentinel region. */
+ PRUint8 *downgrade_sentinel =
+ ss->ssl3.hs.server_random +
+ SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
+ if (!PORT_Memcmp(downgrade_sentinel,
+ tls13_downgrade_random,
+ sizeof(tls13_downgrade_random)) ||
+ !PORT_Memcmp(downgrade_sentinel,
+ tls12_downgrade_random,
+ sizeof(tls12_downgrade_random))) {
+ return SECFailure;
+ }
+ }
+
+ return SECSuccess;
+}
+
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 ServerHello message.
* Caller must hold Handshake and RecvBuf locks.
@@ -6229,9 +6452,6 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
SSL3AlertDescription desc = illegal_parameter;
const PRUint8 *savedMsg = b;
const PRUint32 savedLength = length;
-#ifndef TLS_1_3_DRAFT_VERSION
- SSL3ProtocolVersion downgradeCheckVersion;
-#endif
SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello handshake",
SSL_GETPID(), ss->fd));
@@ -6341,9 +6561,20 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
goto alert_loser;
}
- /* The server didn't pick 1.3 although we either received a
- * HelloRetryRequest, or we prepared to send early app data. */
+ /* There are three situations in which the server must pick
+ * TLS 1.3.
+ *
+ * 1. We offered ESNI.
+ * 2. We received HRR
+ * 3. We sent early app data.
+ *
+ */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ if (ss->xtnData.esniPrivateKey) {
+ desc = protocol_version;
+ errCode = SSL_ERROR_UNSUPPORTED_VERSION;
+ goto alert_loser;
+ }
if (isHelloRetry || ss->ssl3.hs.helloRetry) {
/* SSL3_SendAlert() will uncache the SID. */
desc = illegal_parameter;
@@ -6368,39 +6599,19 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
goto alert_loser;
}
-#ifndef TLS_1_3_DRAFT_VERSION
- /* Check the ServerHello.random per
- * [draft-ietf-tls-tls13-11 Section 6.3.1.1].
- *
- * TLS 1.3 clients receiving a TLS 1.2 or below ServerHello MUST check
- * that the top eight octets are not equal to either of these values.
- * TLS 1.2 clients SHOULD also perform this check if the ServerHello
- * indicates TLS 1.1 or below. If a match is found the client MUST
- * abort the handshake with a fatal "illegal_parameter" alert.
- *
- * Disable this test during the TLS 1.3 draft version period.
- */
- downgradeCheckVersion = ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion
- : ss->vrange.max;
-
- if (downgradeCheckVersion >= SSL_LIBRARY_VERSION_TLS_1_2 &&
- downgradeCheckVersion > ss->version) {
- /* Both sections use the same sentinel region. */
- PRUint8 *downgrade_sentinel =
- ss->ssl3.hs.server_random +
- SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
- if (!PORT_Memcmp(downgrade_sentinel,
- tls13_downgrade_random,
- sizeof(tls13_downgrade_random)) ||
- !PORT_Memcmp(downgrade_sentinel,
- tls12_downgrade_random,
- sizeof(tls12_downgrade_random))) {
+ if (ss->opt.enableHelloDowngradeCheck
+#ifdef DTLS_1_3_DRAFT_VERSION
+ /* Disable this check while we are on draft DTLS 1.3 versions. */
+ && !IS_DTLS(ss)
+#endif
+ ) {
+ rv = ssl_CheckServerRandom(ss);
+ if (rv != SECSuccess) {
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
goto alert_loser;
}
}
-#endif
/* Finally, now all the version-related checks have passed. */
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
@@ -6776,12 +6987,12 @@ ssl_HandleDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length)
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
if (rv != SECSuccess) {
- goto loser; /* malformed or unsupported. */
+ goto alert_loser; /* malformed or unsupported. */
}
rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
ss->sec.peerCert);
if (rv != SECSuccess) {
- goto loser;
+ goto alert_loser;
}
hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
} else {
@@ -7005,7 +7216,8 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
SECStatus rv;
SECItem buf;
SSLSignatureScheme *schemes = NULL;
- unsigned int numSchemes = 0;
+ unsigned int numSupported = 0;
+ unsigned int numRemaining = 0;
unsigned int max;
rv = ssl3_ExtConsumeHandshakeVariable(ss, &buf, 2, b, len);
@@ -7024,7 +7236,8 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
}
/* Limit the number of schemes we read. */
- max = PR_MIN(buf.len / 2, MAX_SIGNATURE_SCHEMES);
+ numRemaining = buf.len / 2;
+ max = PR_MIN(numRemaining, MAX_SIGNATURE_SCHEMES);
if (arena) {
schemes = PORT_ArenaZNewArray(arena, SSLSignatureScheme, max);
@@ -7036,7 +7249,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
return SECFailure;
}
- for (; max; --max) {
+ for (; numRemaining && numSupported < MAX_SIGNATURE_SCHEMES; --numRemaining) {
PRUint32 tmp;
rv = ssl3_ExtConsumeHandshakeNumber(ss, &tmp, 2, &buf.data, &buf.len);
if (rv != SECSuccess) {
@@ -7045,11 +7258,11 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
return SECFailure;
}
if (ssl_IsSupportedSignatureScheme((SSLSignatureScheme)tmp)) {
- schemes[numSchemes++] = (SSLSignatureScheme)tmp;
+ schemes[numSupported++] = (SSLSignatureScheme)tmp;
}
}
- if (!numSchemes) {
+ if (!numSupported) {
if (!arena) {
PORT_Free(schemes);
}
@@ -7058,7 +7271,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
done:
*schemesOut = schemes;
- *numSchemesOut = numSchemes;
+ *numSchemesOut = numSupported;
return SECSuccess;
}
@@ -7114,6 +7327,11 @@ ssl3_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST);
goto loser; /* malformed, alert has been sent */
}
+ if (signatureSchemeCount == 0) {
+ errCode = SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM;
+ desc = handshake_failure;
+ goto alert_loser;
+ }
}
rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, &ca_list);
@@ -7239,16 +7457,25 @@ ssl3_CheckFalseStart(sslSocket *ss)
SSL_TRC(3, ("%d: SSL[%d]: no false start callback so no false start",
SSL_GETPID(), ss->fd));
} else {
- PRBool maybeFalseStart;
+ PRBool maybeFalseStart = PR_TRUE;
SECStatus rv;
+ rv = ssl_CheckServerRandom(ss);
+ if (rv != SECSuccess) {
+ SSL_TRC(3, ("%d: SSL[%d]: no false start due to possible downgrade",
+ SSL_GETPID(), ss->fd));
+ maybeFalseStart = PR_FALSE;
+ }
+
/* An attacker can control the selected ciphersuite so we only wish to
* do False Start in the case that the selected ciphersuite is
* sufficiently strong that the attack can gain no advantage.
* Therefore we always require an 80-bit cipher. */
- ssl_GetSpecReadLock(ss);
- maybeFalseStart = ss->ssl3.cwSpec->cipherDef->secret_key_size >= 10;
- ssl_ReleaseSpecReadLock(ss);
+ if (maybeFalseStart) {
+ ssl_GetSpecReadLock(ss);
+ maybeFalseStart = ss->ssl3.cwSpec->cipherDef->secret_key_size >= 10;
+ ssl_ReleaseSpecReadLock(ss);
+ }
if (!maybeFalseStart) {
SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher",
@@ -7647,6 +7874,30 @@ ssl3_KEASupportsTickets(const ssl3KEADef *kea_def)
return PR_TRUE;
}
+SECStatus
+ssl3_NegotiateCipherSuiteInner(sslSocket *ss, const SECItem *suites,
+ PRUint16 version, PRUint16 *suitep)
+{
+ unsigned int j;
+ unsigned int i;
+
+ for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
+ ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
+ SSLVersionRange vrange = { version, version };
+ if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss)) {
+ continue;
+ }
+ for (i = 0; i + 1 < suites->len; i += 2) {
+ PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1];
+ if (suite_i == suite->cipher_suite) {
+ *suitep = suite_i;
+ return SECSuccess;
+ }
+ }
+ }
+ return SECFailure;
+}
+
/* Select a cipher suite.
**
** NOTE: This suite selection algorithm should be the same as the one in
@@ -7665,24 +7916,16 @@ SECStatus
ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites,
PRBool initHashes)
{
- unsigned int j;
- unsigned int i;
+ PRUint16 selected;
+ SECStatus rv;
- for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
- ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
- SSLVersionRange vrange = { ss->version, ss->version };
- if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) {
- continue;
- }
- for (i = 0; i + 1 < suites->len; i += 2) {
- PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1];
- if (suite_i == suite->cipher_suite) {
- ss->ssl3.hs.cipher_suite = suite_i;
- return ssl3_SetupCipherSuite(ss, initHashes);
- }
- }
+ rv = ssl3_NegotiateCipherSuiteInner(ss, suites, ss->version, &selected);
+ if (rv != SECSuccess) {
+ return SECFailure;
}
- return SECFailure;
+
+ ss->ssl3.hs.cipher_suite = selected;
+ return ssl3_SetupCipherSuite(ss, initHashes);
}
/*
@@ -7814,9 +8057,12 @@ ssl3_ServerCallSNICallback(sslSocket *ss)
}
/* Need to tell the client that application has picked
* the name from the offered list and reconfigured the socket.
+ * Don't do this if we negotiated ESNI.
*/
- ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn,
- ssl_SendEmptyExtension);
+ if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_sni_xtn)) {
+ ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn,
+ ssl_SendEmptyExtension);
+ }
} else {
/* Callback returned index outside of the boundary. */
PORT_Assert((unsigned int)ret < ss->xtnData.sniNameArrSize);
@@ -7845,6 +8091,7 @@ ssl3_SelectServerCert(sslSocket *ss)
{
const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
PRCList *cursor;
+ SECStatus rv;
/* If the client didn't include the supported groups extension, assume just
* P-256 support and disable all the other ECDHE groups. This also affects
@@ -7870,30 +8117,102 @@ ssl3_SelectServerCert(sslSocket *ss)
cursor != &ss->serverCerts;
cursor = PR_NEXT_LINK(cursor)) {
sslServerCert *cert = (sslServerCert *)cursor;
- if (!SSL_CERT_IS(cert, kea_def->authKeyType)) {
- continue;
- }
- if (SSL_CERT_IS_EC(cert) &&
- !ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
- continue;
+ if (kea_def->authKeyType == ssl_auth_rsa_sign) {
+ /* We consider PSS certificates here as well for TLS 1.2. */
+ if (!SSL_CERT_IS(cert, ssl_auth_rsa_sign) &&
+ (!SSL_CERT_IS(cert, ssl_auth_rsa_pss) ||
+ ss->version < SSL_LIBRARY_VERSION_TLS_1_2)) {
+ continue;
+ }
+ } else {
+ if (!SSL_CERT_IS(cert, kea_def->authKeyType)) {
+ continue;
+ }
+ if (SSL_CERT_IS_EC(cert) &&
+ !ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
+ continue;
+ }
}
/* Found one. */
ss->sec.serverCert = cert;
- ss->sec.authType = kea_def->authKeyType;
ss->sec.authKeyBits = cert->serverKeyBits;
/* Don't pick a signature scheme if we aren't going to use it. */
if (kea_def->signKeyType == nullKey) {
+ ss->sec.authType = kea_def->authKeyType;
return SECSuccess;
}
- return ssl3_PickServerSignatureScheme(ss);
+
+ rv = ssl3_PickServerSignatureScheme(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ ss->sec.authType =
+ ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
+ return SECSuccess;
}
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
return SECFailure;
}
+static SECStatus
+ssl_GenerateServerRandom(sslSocket *ss)
+{
+ SECStatus rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (ss->version == ss->vrange.max) {
+ return SECSuccess;
+ }
+#ifdef DTLS_1_3_DRAFT_VERSION
+ if (IS_DTLS(ss)) {
+ return SECSuccess;
+ }
+#endif
+
+ /*
+ * [RFC 8446 Section 4.1.3].
+ *
+ * TLS 1.3 servers which negotiate TLS 1.2 or below in response to a
+ * ClientHello MUST set the last 8 bytes of their Random value specially in
+ * their ServerHello.
+ *
+ * If negotiating TLS 1.2, TLS 1.3 servers MUST set the last 8 bytes of
+ * their Random value to the bytes:
+ *
+ * 44 4F 57 4E 47 52 44 01
+ *
+ * If negotiating TLS 1.1 or below, TLS 1.3 servers MUST, and TLS 1.2
+ * servers SHOULD, set the last 8 bytes of their ServerHello.Random value to
+ * the bytes:
+ *
+ * 44 4F 57 4E 47 52 44 00
+ */
+ PRUint8 *downgradeSentinel =
+ ss->ssl3.hs.server_random +
+ SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
+
+ switch (ss->vrange.max) {
+ case SSL_LIBRARY_VERSION_TLS_1_3:
+ PORT_Memcpy(downgradeSentinel,
+ tls13_downgrade_random, sizeof(tls13_downgrade_random));
+ break;
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ PORT_Memcpy(downgradeSentinel,
+ tls12_downgrade_random, sizeof(tls12_downgrade_random));
+ break;
+ default:
+ /* Do not change random. */
+ break;
+ }
+
+ return SECSuccess;
+}
+
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 Client Hello message.
* Caller must hold Handshake and RecvBuf locks.
@@ -8088,56 +8407,6 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
}
- /* Generate the Server Random now so it is available
- * when we process the ClientKeyShare in TLS 1.3 */
- rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random);
- if (rv != SECSuccess) {
- errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE;
- goto loser;
- }
-
-#ifndef TLS_1_3_DRAFT_VERSION
- /*
- * [draft-ietf-tls-tls13-11 Section 6.3.1.1].
- * TLS 1.3 server implementations which respond to a ClientHello with a
- * client_version indicating TLS 1.2 or below MUST set the last eight
- * bytes of their Random value to the bytes:
- *
- * 44 4F 57 4E 47 52 44 01
- *
- * TLS 1.2 server implementations which respond to a ClientHello with a
- * client_version indicating TLS 1.1 or below SHOULD set the last eight
- * bytes of their Random value to the bytes:
- *
- * 44 4F 57 4E 47 52 44 00
- *
- * TODO(ekr@rtfm.com): Note this change was not added in the SSLv2
- * compat processing code since that will most likely be removed before
- * we ship the final version of TLS 1.3. Bug 1306672.
- */
- if (ss->vrange.max > ss->version) {
- PRUint8 *downgrade_sentinel =
- ss->ssl3.hs.server_random +
- SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
-
- switch (ss->vrange.max) {
- case SSL_LIBRARY_VERSION_TLS_1_3:
- PORT_Memcpy(downgrade_sentinel,
- tls13_downgrade_random,
- sizeof(tls13_downgrade_random));
- break;
- case SSL_LIBRARY_VERSION_TLS_1_2:
- PORT_Memcpy(downgrade_sentinel,
- tls12_downgrade_random,
- sizeof(tls12_downgrade_random));
- break;
- default:
- /* Do not change random. */
- break;
- }
- }
-#endif
-
/* If there is a cookie, then this is a second ClientHello (TLS 1.3). */
if (ssl3_FindExtension(ss, ssl_tls13_cookie_xtn)) {
ss->ssl3.hs.helloRetry = PR_TRUE;
@@ -8397,7 +8666,7 @@ ssl3_HandleClientHelloPart2(sslSocket *ss,
* The product policy won't change during the process lifetime.
* Implemented ("isPresent") shouldn't change for servers.
*/
- if (!config_match(suite, ss->ssl3.policy, &vrange, ss))
+ if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss))
break;
#else
if (!suite->enabled)
@@ -8779,7 +9048,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int leng
for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
SSLVersionRange vrange = { ss->version, ss->version };
- if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) {
+ if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss)) {
continue;
}
for (i = 0; i + 2 < suite_length; i += 3) {
@@ -8884,6 +9153,7 @@ ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry,
SECStatus rv;
SSL3ProtocolVersion version;
sslSessionID *sid = ss->sec.ci.sid;
+ const PRUint8 *random;
version = PR_MIN(ss->version, SSL_LIBRARY_VERSION_TLS_1_2);
if (IS_DTLS(ss)) {
@@ -8893,9 +9163,17 @@ ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry,
if (rv != SECSuccess) {
return SECFailure;
}
- /* Random already generated in ssl3_HandleClientHello */
- rv = sslBuffer_Append(messageBuf, helloRetry ? ssl_hello_retry_random : ss->ssl3.hs.server_random,
- SSL3_RANDOM_LENGTH);
+
+ if (helloRetry) {
+ random = ssl_hello_retry_random;
+ } else {
+ rv = ssl_GenerateServerRandom(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ random = ss->ssl3.hs.server_random;
+ }
+ rv = sslBuffer_Append(messageBuf, random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -9368,7 +9646,7 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
ss->sec.peerCert);
if (rv != SECSuccess) {
errCode = PORT_GetError();
- desc = decrypt_error;
+ desc = illegal_parameter;
goto alert_loser;
}
@@ -9501,6 +9779,23 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
return pms;
}
+static void
+ssl3_CSwapPK11SymKey(PK11SymKey **x, PK11SymKey **y, PRBool c)
+{
+ uintptr_t mask = (uintptr_t)c;
+ unsigned int i;
+ for (i = 1; i < sizeof(uintptr_t) * 8; i <<= 1) {
+ mask |= mask << i;
+ }
+ uintptr_t x_ptr = (uintptr_t)*x;
+ uintptr_t y_ptr = (uintptr_t)*y;
+ uintptr_t tmp = (x_ptr ^ y_ptr) & mask;
+ x_ptr = x_ptr ^ tmp;
+ y_ptr = y_ptr ^ tmp;
+ *x = (PK11SymKey *)x_ptr;
+ *y = (PK11SymKey *)y_ptr;
+}
+
/* Note: The Bleichenbacher attack on PKCS#1 necessitates that we NEVER
* return any indication of failure of the Client Key Exchange message,
* where that failure is caused by the content of the client's message.
@@ -9521,9 +9816,9 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
{
SECStatus rv;
SECItem enc_pms;
- PK11SymKey *tmpPms[2] = { NULL, NULL };
- PK11SlotInfo *slot;
- int useFauxPms = 0;
+ PK11SymKey *pms = NULL;
+ PK11SymKey *fauxPms = NULL;
+ PK11SlotInfo *slot = NULL;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -9544,11 +9839,6 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
}
}
-#define currentPms tmpPms[!useFauxPms]
-#define unusedPms tmpPms[useFauxPms]
-#define realPms tmpPms[1]
-#define fauxPms tmpPms[0]
-
/*
* Get as close to algorithm 2 from RFC 5246; Section 7.4.7.1
* as we can within the constraints of the PKCS#11 interface.
@@ -9603,40 +9893,33 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
* the unwrap. Rather, it is the mechanism with which the
* unwrapped pms will be used.
*/
- realPms = PK11_PubUnwrapSymKey(serverKeyPair->privKey, &enc_pms,
- CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
+ pms = PK11_PubUnwrapSymKey(serverKeyPair->privKey, &enc_pms,
+ CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
/* Temporarily use the PMS if unwrapping the real PMS fails. */
- useFauxPms |= (realPms == NULL);
+ ssl3_CSwapPK11SymKey(&pms, &fauxPms, pms == NULL);
/* Attempt to derive the MS from the PMS. This is the only way to
* check the version field in the RSA PMS. If this fails, we
* then use the faux PMS in place of the PMS. Note that this
* operation should never fail if we are using the faux PMS
* since it is correctly formatted. */
- rv = ssl3_ComputeMasterSecret(ss, currentPms, NULL);
-
- /* If we succeeded, then select the true PMS and discard the
- * FPMS. Else, select the FPMS and select the true PMS */
- useFauxPms |= (rv != SECSuccess);
+ rv = ssl3_ComputeMasterSecret(ss, pms, NULL);
- if (unusedPms) {
- PK11_FreeSymKey(unusedPms);
- }
+ /* If we succeeded, then select the true PMS, else select the FPMS. */
+ ssl3_CSwapPK11SymKey(&pms, &fauxPms, (rv != SECSuccess) & (fauxPms != NULL));
/* This step will derive the MS from the PMS, among other things. */
- rv = ssl3_InitPendingCipherSpecs(ss, currentPms, PR_TRUE);
- PK11_FreeSymKey(currentPms);
+ rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE);
+
+ /* Clear both PMS. */
+ PK11_FreeSymKey(pms);
+ PK11_FreeSymKey(fauxPms);
if (rv != SECSuccess) {
(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
}
-#undef currentPms
-#undef unusedPms
-#undef realPms
-#undef fauxPms
-
return SECSuccess;
}
@@ -10429,6 +10712,9 @@ ssl3_AuthCertificate(sslSocket *ss)
PR_TRUE, isServer);
if (rv != SECSuccess) {
errCode = PORT_GetError();
+ if (errCode == 0) {
+ errCode = SSL_ERROR_BAD_CERTIFICATE;
+ }
if (rv != SECWouldBlock) {
if (ss->handleBadCert) {
rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd);
@@ -11252,7 +11538,7 @@ ssl3_FinishHandshake(sslSocket *ss)
}
SECStatus
-ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type,
+ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType ct,
PRUint32 dtlsSeq,
const PRUint8 *b, PRUint32 length)
{
@@ -11262,7 +11548,7 @@ ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type,
PRINT_BUF(50, (ss, "Hash handshake message:", b, length));
- hdr[0] = (PRUint8)type;
+ hdr[0] = (PRUint8)ct;
hdr[1] = (PRUint8)(length >> 16);
hdr[2] = (PRUint8)(length >> 8);
hdr[3] = (PRUint8)(length);
@@ -11302,10 +11588,10 @@ ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type,
}
SECStatus
-ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
+ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType ct,
const PRUint8 *b, PRUint32 length)
{
- return ssl_HashHandshakeMessageInt(ss, type, ss->ssl3.hs.recvMessageSeq,
+ return ssl_HashHandshakeMessageInt(ss, ct, ss->ssl3.hs.recvMessageSeq,
b, length);
}
@@ -11885,7 +12171,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
PRBool isTLS;
unsigned int good;
unsigned int ivLen = 0;
- SSL3ContentType rType;
+ SSLContentType rType;
SSL3ProtocolVersion rVersion;
unsigned int minLength;
unsigned int originalLen = 0;
@@ -11959,7 +12245,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
return SECFailure;
}
- rType = (SSL3ContentType)cText->hdr[0];
+ rType = (SSLContentType)cText->hdr[0];
rVersion = ((SSL3ProtocolVersion)cText->hdr[1] << 8) |
(SSL3ProtocolVersion)cText->hdr[2];
if (cipher_def->type == type_aead) {
@@ -12071,7 +12357,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
}
SECStatus
-ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType,
+ssl3_HandleNonApplicationData(sslSocket *ss, SSLContentType rType,
DTLSEpoch epoch, sslSequenceNumber seqNum,
sslBuffer *databuf)
{
@@ -12089,20 +12375,20 @@ ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType,
** they return SECFailure or SECWouldBlock.
*/
switch (rType) {
- case content_change_cipher_spec:
+ case ssl_ct_change_cipher_spec:
rv = ssl3_HandleChangeCipherSpecs(ss, databuf);
break;
- case content_alert:
+ case ssl_ct_alert:
rv = ssl3_HandleAlert(ss, databuf);
break;
- case content_handshake:
+ case ssl_ct_handshake:
if (!IS_DTLS(ss)) {
rv = ssl3_HandleHandshake(ss, databuf);
} else {
rv = dtls_HandleHandshake(ss, epoch, seqNum, databuf);
}
break;
- case content_ack:
+ case ssl_ct_ack:
if (IS_DTLS(ss) && tls13_MaybeTls13(ss)) {
rv = dtls13_HandleAck(ss, databuf);
break;
@@ -12190,7 +12476,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
ssl3CipherSpec *spec = NULL;
PRUint16 recordSizeLimit;
PRBool outOfOrderSpec = PR_FALSE;
- SSL3ContentType rType;
+ SSLContentType rType;
sslBuffer *plaintext = &ss->gs.buf;
SSL3AlertDescription alert = internal_error;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
@@ -12208,7 +12494,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
/* We're waiting for another ClientHello, which will appear unencrypted.
* Use the content type to tell whether this should be discarded. */
if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr &&
- cText->hdr[0] == content_application_data) {
+ cText->hdr[0] == ssl_ct_application_data) {
PORT_Assert(ss->ssl3.hs.ws == wait_client_hello);
return SECSuccess;
}
@@ -12269,7 +12555,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
/* Encrypted application data records could arrive before the handshake
* completes in DTLS 1.3. These can look like valid TLS 1.2 application_data
* records in epoch 0, which is never valid. Pretend they didn't decrypt. */
- if (spec->epoch == 0 && rType == content_application_data) {
+ if (spec->epoch == 0 && rType == ssl_ct_application_data) {
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
alert = unexpected_message;
rv = SECFailure;
@@ -12304,7 +12590,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
* 0-RTT session that is resumed from a session that did negotiate it.
* We don't care about that corner case right now. */
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
- cText->hdr[0] == content_change_cipher_spec &&
+ cText->hdr[0] == ssl_ct_change_cipher_spec &&
ss->ssl3.hs.ws != idle_handshake &&
cText->buf->len == 1 &&
cText->buf->buf[0] == change_cipher_spec_choice) {
@@ -12364,7 +12650,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
/* Application data records are processed by the caller of this
** function, not by this function.
*/
- if (rType == content_application_data) {
+ if (rType == ssl_ct_application_data) {
if (ss->firstHsDone)
return SECSuccess;
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c
index f8b9a9400..52d5bb515 100644
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -327,16 +327,13 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, PRUint8 *b,
** Take an encoded key share and make a public key out of it.
*/
SECStatus
-ssl_ImportECDHKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey,
+ssl_ImportECDHKeyShare(SECKEYPublicKey *peerKey,
PRUint8 *b, PRUint32 length,
const sslNamedGroupDef *ecGroup)
{
SECStatus rv;
SECItem ecPoint = { siBuffer, NULL, 0 };
- PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
- PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
if (!length) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
return SECFailure;
@@ -616,7 +613,7 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length)
peerKey->arena = arena;
/* create public key from point data */
- rv = ssl_ImportECDHKeyShare(ss, peerKey, ec_point.data, ec_point.len,
+ rv = ssl_ImportECDHKeyShare(peerKey, ec_point.data, ec_point.len,
ecGroup);
if (rv != SECSuccess) {
/* error code is set */
diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c
index 9b6c719f8..60b5889e7 100644
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -50,6 +50,7 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
{ ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
{ ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
+ { ssl_tls13_encrypted_sni_xtn, &tls13_ServerHandleEsniXtn },
{ ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
{ 0, NULL }
};
@@ -136,6 +137,7 @@ static const sslExtensionBuilder clientHelloSendersTLS[] =
{ ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
{ ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
+ { ssl_tls13_encrypted_sni_xtn, &tls13_ClientSendEsniXtn },
{ ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn },
/* The pre_shared_key extension MUST be last. */
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
@@ -338,8 +340,6 @@ ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length)
return SECFailure; /* alert already sent */
}
- SSL_TRC(10, ("%d: SSL3[%d]: parsing extension %d",
- SSL_GETPID(), ss->fd, extension_type));
/* Check whether an extension has been sent multiple times. */
for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions);
cursor != &ss->ssl3.hs.remoteExtensions;
@@ -357,6 +357,9 @@ ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length)
return rv; /* alert already sent */
}
+ SSL_TRC(10, ("%d: SSL3[%d]: parsed extension %d len=%u",
+ SSL_GETPID(), ss->fd, extension_type, extension_data.len));
+
extension = PORT_ZNew(TLSExtension);
if (!extension) {
return SECFailure;
@@ -409,7 +412,9 @@ ssl_CallExtensionHandler(sslSocket *ss, SSLHandshakeType handshakeMessage,
/* Find extension_type in table of Hello Extension Handlers. */
for (; handler->ex_handler != NULL; ++handler) {
if (handler->ex_type == extension->type) {
- rv = (*handler->ex_handler)(ss, &ss->xtnData, &extension->data);
+ SECItem tmp = extension->data;
+
+ rv = (*handler->ex_handler)(ss, &ss->xtnData, &tmp);
break;
}
}
@@ -960,6 +965,8 @@ ssl3_DestroyExtensionData(TLSExtensionData *xtnData)
xtnData->certReqAuthorities.arena = NULL;
}
PORT_Free(xtnData->advertised);
+ ssl_FreeEphemeralKeyPair(xtnData->esniPrivateKey);
+ SECITEM_FreeItem(&xtnData->keyShareExtension, PR_FALSE);
}
/* Free everything that has been allocated and then reset back to
diff --git a/security/nss/lib/ssl/ssl3ext.h b/security/nss/lib/ssl/ssl3ext.h
index 6d77c7459..d96b4cffe 100644
--- a/security/nss/lib/ssl/ssl3ext.h
+++ b/security/nss/lib/ssl/ssl3ext.h
@@ -11,6 +11,8 @@
#include "sslencode.h"
+#define TLS13_ESNI_NONCE_SIZE 16
+
typedef enum {
sni_nametype_hostname
} SNINameType;
@@ -101,6 +103,14 @@ struct TLSExtensionDataStr {
/* The record size limit set by the peer. Our value is kept in ss->opt. */
PRUint16 recordSizeLimit;
+
+ /* ESNI working state */
+ SECItem keyShareExtension;
+ ssl3CipherSuite esniSuite;
+ sslEphemeralKeyPair *esniPrivateKey;
+ /* Pointer into |ss->esniKeys->keyShares| */
+ TLS13KeyShareEntry *peerEsniShare;
+ PRUint8 esniNonce[TLS13_ESNI_NONCE_SIZE];
};
typedef struct TLSExtensionStr {
diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c
index d1f286dc3..a2d83fa97 100644
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -15,30 +15,40 @@
#include "selfencrypt.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
+#include "tls13esni.h"
#include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */
+PRBool
+ssl_ShouldSendSNIExtension(const sslSocket *ss, const char *url)
+{
+ PRNetAddr netAddr;
+
+ /* must have a hostname */
+ if (!url || !url[0]) {
+ return PR_FALSE;
+ }
+ /* must not be an IPv4 or IPv6 address */
+ if (PR_SUCCESS == PR_StringToNetAddr(url, &netAddr)) {
+ /* is an IP address (v4 or v6) */
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
/* Format an SNI extension, using the name from the socket's URL,
* unless that name is a dotted decimal string.
* Used by client and server.
*/
SECStatus
-ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
- sslBuffer *buf, PRBool *added)
+ssl3_ClientFormatServerNameXtn(const sslSocket *ss, const char *url,
+ TLSExtensionData *xtnData,
+ sslBuffer *buf)
{
unsigned int len;
- PRNetAddr netAddr;
SECStatus rv;
- /* must have a hostname */
- if (!ss->url || !ss->url[0]) {
- return SECSuccess;
- }
- /* must not be an IPv4 or IPv6 address */
- if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) {
- /* is an IP address (v4 or v6) */
- return SECSuccess;
- }
- len = PORT_Strlen(ss->url);
+ len = PORT_Strlen(url);
/* length of server_name_list */
rv = sslBuffer_AppendNumber(buf, len + 3, 2);
if (rv != SECSuccess) {
@@ -50,7 +60,33 @@ ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECFailure;
}
/* HostName (length and value) */
- rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)ss->url, len, 2);
+ rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)url, len, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ SECStatus rv;
+
+ const char *url = ss->url;
+
+ /* We only make an ESNI private key if we are going to
+ * send ESNI. */
+ if (ss->xtnData.esniPrivateKey != NULL) {
+ url = ss->esniKeys->dummySni;
+ }
+
+ if (!ssl_ShouldSendSNIExtension(ss, url)) {
+ return SECSuccess;
+ }
+
+ rv = ssl3_ClientFormatServerNameXtn(ss, url, xtnData, buf);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -59,7 +95,6 @@ ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess;
}
-/* Handle an incoming SNI extension. */
SECStatus
ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data)
@@ -72,6 +107,13 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess; /* ignore extension */
}
+ if (ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_sni_xtn)) {
+ /* If we already have ESNI, make sure we don't overwrite
+ * the value. */
+ PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+ return SECSuccess;
+ }
+
/* Server side - consume client data and register server sender. */
/* do not parse the data if don't have user extension handling function. */
if (!ss->sniSocketConfig) {
@@ -1174,17 +1216,18 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
&decryptedTicket.len,
decryptedTicket.len);
if (rv != SECSuccess) {
- SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE);
-
- /* Fail with no ticket if we're not a recipient. Otherwise
- * it's a hard failure. */
- if (PORT_GetError() != SEC_ERROR_NOT_A_RECIPIENT) {
- SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
- return SECFailure;
+ /* Ignore decryption failure if we are doing TLS 1.3; that
+ * means the server rejects the client's resumption
+ * attempt. In TLS 1.2, however, it's a hard failure, unless
+ * it's just because we're not the recipient of the ticket. */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ||
+ PORT_GetError() == SEC_ERROR_NOT_A_RECIPIENT) {
+ SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE);
+ return SECSuccess;
}
- /* We didn't have the right key, so pretend we don't have a
- * ticket. */
+ SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+ goto loser;
}
rv = ssl_ParseSessionTicket(ss, &decryptedTicket, &parsedTicket);
diff --git a/security/nss/lib/ssl/ssl3exthandle.h b/security/nss/lib/ssl/ssl3exthandle.h
index eaf7f0081..3e9b418cf 100644
--- a/security/nss/lib/ssl/ssl3exthandle.h
+++ b/security/nss/lib/ssl/ssl3exthandle.h
@@ -91,6 +91,10 @@ SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss,
SECItem *data);
SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
/* out */ SECItem *appToken);
+PRBool ssl_ShouldSendSNIExtension(const sslSocket *ss, const char *url);
+SECStatus ssl3_ClientFormatServerNameXtn(const sslSocket *ss, const char *url,
+ TLSExtensionData *xtnData,
+ sslBuffer *buf);
SECStatus ssl3_ClientSendServerNameXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c
index 5ea7cc249..64a1878f7 100644
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -60,8 +60,8 @@ ssl3_isLikelyV3Hello(const unsigned char *buf)
}
/* Check for a typical V3 record header. */
- return (PRBool)(buf[0] >= content_change_cipher_spec &&
- buf[0] <= content_application_data &&
+ return (PRBool)(buf[0] >= ssl_ct_change_cipher_spec &&
+ buf[0] <= ssl_ct_application_data &&
buf[1] == MSB(SSL_LIBRARY_VERSION_3_0));
}
@@ -314,7 +314,7 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
contentType = gs->dtlsPacket.buf[gs->dtlsPacketOffset];
if (dtls_IsLongHeader(ss->version, contentType)) {
headerLen = 13;
- } else if (contentType == content_application_data) {
+ } else if (contentType == ssl_ct_application_data) {
headerLen = 7;
} else if ((contentType & 0xe0) == 0x20) {
headerLen = 2;
@@ -463,15 +463,15 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
SSL_DBG(("%d: SSL3[%d]: resuming handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(!IS_DTLS(ss));
- rv = ssl3_HandleNonApplicationData(ss, content_handshake,
+ rv = ssl3_HandleNonApplicationData(ss, ssl_ct_handshake,
0, 0, &ss->gs.buf);
} else {
/* State for SSLv2 client hello support. */
ssl2Gather ssl2gs = { PR_FALSE, 0 };
ssl2Gather *ssl2gs_ptr = NULL;
- /* If we're a server and waiting for a client hello, accept v2. */
- if (ss->sec.isServer && ss->ssl3.hs.ws == wait_client_hello) {
+ if (ss->sec.isServer && ss->opt.enableV2CompatibleHello &&
+ ss->ssl3.hs.ws == wait_client_hello) {
ssl2gs_ptr = &ssl2gs;
}
@@ -484,8 +484,8 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
}
if (!IS_DTLS(ss)) {
- /* If we're a server waiting for a ClientHello then pass
- * ssl2gs to support SSLv2 ClientHello messages. */
+ /* Passing a non-NULL ssl2gs here enables detection of
+ * SSLv2-compatible ClientHello messages. */
rv = ssl3_GatherData(ss, &ss->gs, flags, ssl2gs_ptr);
} else {
rv = dtls_GatherData(ss, &ss->gs, flags);
diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h
index 8e6cf2745..bfaa10d3f 100644
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -13,10 +13,8 @@
typedef PRUint16 SSL3ProtocolVersion;
/* version numbers are defined in sslproto.h */
-/* The TLS 1.3 draft version. Used to avoid negotiating
- * between incompatible pre-standard TLS 1.3 drafts.
- * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */
-#define TLS_1_3_DRAFT_VERSION 28
+/* DTLS 1.3 is still a draft. */
+#define DTLS_1_3_DRAFT_VERSION 28
typedef PRUint16 ssl3CipherSuite;
/* The cipher suites are defined in sslproto.h */
@@ -35,15 +33,6 @@ typedef PRUint16 ssl3CipherSuite;
#define MAX_FRAGMENT_LENGTH 16384
-typedef enum {
- content_change_cipher_spec = 20,
- content_alert = 21,
- content_handshake = 22,
- content_application_data = 23,
- content_alt_handshake = 24,
- content_ack = 25
-} SSL3ContentType;
-
typedef enum { change_cipher_spec_choice = 1 } SSL3ChangeCipherSpecChoice;
typedef enum { alert_warning = 1,
diff --git a/security/nss/lib/ssl/sslcert.c b/security/nss/lib/ssl/sslcert.c
index 1c3ddb0e7..878df761e 100644
--- a/security/nss/lib/ssl/sslcert.c
+++ b/security/nss/lib/ssl/sslcert.c
@@ -436,8 +436,6 @@ ssl_GetCertificateAuthTypes(CERTCertificate *cert, SSLAuthType targetAuthType)
case SEC_OID_PKCS1_RSA_ENCRYPTION:
if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
authTypes |= 1 << ssl_auth_rsa_sign;
- /* This certificate is RSA, assume that it's also PSS. */
- authTypes |= 1 << ssl_auth_rsa_pss;
}
if (cert->keyUsage & KU_KEY_ENCIPHERMENT) {
diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h
index 518a2b887..a4aa27657 100644
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -264,6 +264,10 @@ typedef enum {
SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR = (SSL_ERROR_BASE + 173),
SSL_ERROR_RX_MALFORMED_DTLS_ACK = (SSL_ERROR_BASE + 174),
SSL_ERROR_DH_KEY_TOO_LONG = (SSL_ERROR_BASE + 175),
+ SSL_ERROR_RX_MALFORMED_ESNI_KEYS = (SSL_ERROR_BASE + 176),
+ SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION = (SSL_ERROR_BASE + 177),
+ SSL_ERROR_MISSING_ESNI_EXTENSION = (SSL_ERROR_BASE + 178),
+ SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE = (SSL_ERROR_BASE + 179),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/security/nss/lib/ssl/sslexp.h b/security/nss/lib/ssl/sslexp.h
index 08654f885..f450e528d 100644
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -367,6 +367,7 @@ typedef struct SSLResumptionTokenInfoStr {
PRUint8 *alpnSelection;
PRUint32 alpnSelectionLen;
PRUint32 maxEarlyDataSize;
+ PRTime expirationTime; /* added in NSS 3.41 */
} SSLResumptionTokenInfo;
/*
@@ -452,8 +453,65 @@ typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
(PRFileDesc * _fd, PRUint32 _size), \
(fd, size))
-/* Deprecated experimental APIs */
+/* Set the ESNI key pair on a socket (server side)
+ *
+ * fd -- the socket
+ * record/recordLen -- the encoded DNS record (not base64)
+ *
+ * Important: the suites that are advertised in the record must
+ * be configured on, or this call will fail.
+ */
+#define SSL_SetESNIKeyPair(fd, \
+ privKey, record, recordLen) \
+ SSL_EXPERIMENTAL_API("SSL_SetESNIKeyPair", \
+ (PRFileDesc * _fd, \
+ SECKEYPrivateKey * _privKey, \
+ const PRUint8 *_record, unsigned int _recordLen), \
+ (fd, privKey, \
+ record, recordLen))
+/* Set the ESNI keys on a client
+ *
+ * fd -- the socket
+ * ensikeys/esniKeysLen -- the ESNI key structure (not base64)
+ * dummyESNI -- the dummy ESNI to use (if any)
+ */
+#define SSL_EnableESNI(fd, esniKeys, esniKeysLen, dummySNI) \
+ SSL_EXPERIMENTAL_API("SSL_EnableESNI", \
+ (PRFileDesc * _fd, \
+ const PRUint8 *_esniKeys, \
+ unsigned int _esniKeysLen, \
+ const char *_dummySNI), \
+ (fd, esniKeys, esniKeysLen, dummySNI))
+
+/*
+ * Generate an encoded ESNIKeys structure (presumably server side).
+ *
+ * cipherSuites -- the cipher suites that can be used
+ * cipherSuitesCount -- the number of suites in cipherSuites
+ * group -- the named group this key corresponds to
+ * pubKey -- the public key for the key pair
+ * pad -- the length to pad to
+ * notBefore/notAfter -- validity range
+ * out/outlen/maxlen -- where to output the data
+ */
+#define SSL_EncodeESNIKeys(cipherSuites, cipherSuiteCount, \
+ group, pubKey, pad, notBefore, notAfter, \
+ out, outlen, maxlen) \
+ SSL_EXPERIMENTAL_API("SSL_EncodeESNIKeys", \
+ (PRUint16 * _cipherSuites, \
+ unsigned int _cipherSuiteCount, \
+ SSLNamedGroup _group, \
+ SECKEYPublicKey *_pubKey, \
+ PRUint16 _pad, \
+ PRUint64 _notBefore, PRUint64 _notAfter, \
+ PRUint8 *_out, unsigned int *_outlen, \
+ unsigned int _maxlen), \
+ (cipherSuites, cipherSuiteCount, \
+ group, pubKey, pad, notBefore, notAfter, \
+ out, outlen, maxlen))
+
+/* Deprecated experimental APIs */
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
SEC_END_PROTOS
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index a2209e90a..35240d2fb 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -36,6 +36,10 @@
typedef struct sslSocketStr sslSocket;
typedef struct sslNamedGroupDefStr sslNamedGroupDef;
+typedef struct sslEsniKeysStr sslEsniKeys;
+typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair;
+typedef struct TLS13KeyShareEntryStr TLS13KeyShareEntry;
+
#include "sslencode.h"
#include "sslexp.h"
#include "ssl3ext.h"
@@ -230,7 +234,7 @@ typedef struct {
#define MAX_DTLS_SRTP_CIPHER_SUITES 4
/* MAX_SIGNATURE_SCHEMES allows for all the values we support. */
-#define MAX_SIGNATURE_SCHEMES 15
+#define MAX_SIGNATURE_SCHEMES 18
typedef struct sslOptionsStr {
/* If SSL_SetNextProtoNego has been called, then this contains the
@@ -266,6 +270,8 @@ typedef struct sslOptionsStr {
unsigned int enable0RttData : 1;
unsigned int enableTls13CompatMode : 1;
unsigned int enableDtlsShortHeader : 1;
+ unsigned int enableHelloDowngradeCheck : 1;
+ unsigned int enableV2CompatibleHello : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -552,16 +558,16 @@ typedef SECStatus (*sslRestartTarget)(sslSocket *);
typedef struct DTLSQueuedMessageStr {
PRCList link; /* The linked list link */
ssl3CipherSpec *cwSpec; /* The cipher spec to use, null for none */
- SSL3ContentType type; /* The message type */
+ SSLContentType type; /* The message type */
unsigned char *data; /* The data */
PRUint16 len; /* The data length */
} DTLSQueuedMessage;
-typedef struct TLS13KeyShareEntryStr {
+struct TLS13KeyShareEntryStr {
PRCList link; /* The linked list link */
const sslNamedGroupDef *group; /* The group for the entry */
SECItem key_exchange; /* The share itself */
-} TLS13KeyShareEntry;
+};
typedef struct TLS13EarlyDataStr {
PRCList link; /* The linked list link */
@@ -803,11 +809,11 @@ struct sslKeyPairStr {
PRInt32 refCount; /* use PR_Atomic calls for this. */
};
-typedef struct {
+struct sslEphemeralKeyPairStr {
PRCList link;
const sslNamedGroupDef *group;
sslKeyPair *keys;
-} sslEphemeralKeyPair;
+};
struct ssl3DHParamsStr {
SSLNamedGroup name;
@@ -1064,6 +1070,10 @@ struct sslSocketStr {
/* Whether we are doing stream or datagram mode */
SSLProtocolVariant protocolVariant;
+
+ /* The information from the ESNI keys record
+ * (also the private key for the server). */
+ sslEsniKeys *esniKeys;
};
struct sslSelfEncryptKeysStr {
@@ -1168,11 +1178,13 @@ extern int ssl_Do1stHandshake(sslSocket *ss);
extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
PRBool derive);
+extern void ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial);
extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
const char *peerID, const char *urlSvrName);
extern void ssl_FreeSID(sslSessionID *sid);
extern void ssl_DestroySID(sslSessionID *sid, PRBool freeIt);
+extern sslSessionID *ssl_ReferenceSID(sslSessionID *sid);
extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in,
int len, int flags);
@@ -1215,7 +1227,7 @@ SECStatus ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
extern PRBool ssl3_WaitingForServerSecondRound(sslSocket *ss);
extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
- SSL3ContentType type,
+ SSLContentType type,
const PRUint8 *pIn, PRInt32 nIn,
PRInt32 flags);
@@ -1387,7 +1399,7 @@ SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type);
* input into the SSL3 machinery from the actualy network reading code
*/
SECStatus ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cipher);
-SECStatus ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType,
+SECStatus ssl3_HandleNonApplicationData(sslSocket *ss, SSLContentType rType,
DTLSEpoch epoch,
sslSequenceNumber seqNum,
sslBuffer *databuf);
@@ -1497,7 +1509,7 @@ extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss,
sslKeyPair *serverKeys);
extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss);
extern SECStatus ssl_ImportECDHKeyShare(
- sslSocket *ss, SECKEYPublicKey *peerKey,
+ SECKEYPublicKey *peerKey,
PRUint8 *b, PRUint32 length, const sslNamedGroupDef *curve);
extern SECStatus ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
@@ -1562,6 +1574,12 @@ extern void ssl_FreePRSocket(PRFileDesc *fd);
* various ciphers */
extern unsigned int ssl3_config_match_init(sslSocket *);
+/* Return PR_TRUE if suite is usable. This if the suite is permitted by policy,
+ * enabled, has a certificate (as needed), has a viable key agreement method, is
+ * usable with the negotiated TLS version, and is otherwise usable. */
+PRBool ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
+ const SSLVersionRange *vrange, const sslSocket *ss);
+
/* calls for accessing wrapping keys across processes. */
extern SECStatus
ssl_GetWrappingKey(unsigned int symWrapMechIndex, unsigned int wrapKeyIndex,
@@ -1591,6 +1609,8 @@ extern SECStatus ssl_InitSessionCacheLocks(PRBool lazyInit);
extern SECStatus ssl_FreeSessionCacheLocks(void);
CK_MECHANISM_TYPE ssl3_Alg2Mech(SSLCipherAlgorithm calg);
+SECStatus ssl3_NegotiateCipherSuiteInner(sslSocket *ss, const SECItem *suites,
+ PRUint16 version, PRUint16 *suitep);
SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites,
PRBool initHashes);
SECStatus ssl3_InitHandshakeHashes(sslSocket *ss);
@@ -1638,8 +1658,12 @@ PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid,
PK11SymKey *secret);
const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
+const ssl3CipherSuiteCfg *ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite,
+ const ssl3CipherSuiteCfg *suites);
+
SECStatus ssl3_SelectServerCert(sslSocket *ss);
SECStatus ssl_PickSignatureScheme(sslSocket *ss,
+ CERTCertificate *cert,
SECKEYPublicKey *pubKey,
SECKEYPrivateKey *privKey,
const SSLSignatureScheme *peerSchemes,
@@ -1647,11 +1671,11 @@ SECStatus ssl_PickSignatureScheme(sslSocket *ss,
PRBool requireSha1);
SECOidTag ssl3_HashTypeToOID(SSLHashType hashType);
SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme);
-KeyType ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme);
+SSLAuthType ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme);
SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes);
SECStatus ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
- SSL3ContentType contentType, sslBuffer *wrBuf,
+ SSLContentType contentType, sslBuffer *wrBuf,
PRBool *needsLength);
/* Pull in DTLS functions */
@@ -1703,7 +1727,7 @@ void ssl_Trace(const char *format, ...);
void ssl_CacheExternalToken(sslSocket *ss);
SECStatus ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedTicket,
PRUint32 encodedTicketLen);
-PRBool ssl_IsResumptionTokenValid(sslSocket *ss);
+PRBool ssl_IsResumptionTokenUsable(sslSocket *ss, sslSessionID *sid);
/* Remove when stable. */
diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c
index f79c23fc7..f8fb5d50f 100644
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -234,9 +234,20 @@ ssl_FreeLockedSID(sslSessionID *sid)
void
ssl_FreeSID(sslSessionID *sid)
{
+ if (sid) {
+ LOCK_CACHE;
+ ssl_FreeLockedSID(sid);
+ UNLOCK_CACHE;
+ }
+}
+
+sslSessionID *
+ssl_ReferenceSID(sslSessionID *sid)
+{
LOCK_CACHE;
- ssl_FreeLockedSID(sid);
+ sid->references++;
UNLOCK_CACHE;
+ return sid;
}
/************************************************************************/
@@ -704,10 +715,9 @@ ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
}
PRBool
-ssl_IsResumptionTokenValid(sslSocket *ss)
+ssl_IsResumptionTokenUsable(sslSocket *ss, sslSessionID *sid)
{
PORT_Assert(ss);
- sslSessionID *sid = ss->sec.ci.sid;
PORT_Assert(sid);
// Check that the ticket didn't expire.
@@ -1093,10 +1103,12 @@ ssl_CacheExternalToken(sslSocket *ss)
PRINT_BUF(40, (ss, "SSL: encoded resumption token",
SSL_BUFFER_BASE(&encodedToken),
SSL_BUFFER_LEN(&encodedToken)));
- ss->resumptionTokenCallback(ss->fd, SSL_BUFFER_BASE(&encodedToken),
- SSL_BUFFER_LEN(&encodedToken),
- ss->resumptionTokenContext);
-
+ SECStatus rv = ss->resumptionTokenCallback(
+ ss->fd, SSL_BUFFER_BASE(&encodedToken), SSL_BUFFER_LEN(&encodedToken),
+ ss->resumptionTokenContext);
+ if (rv == SECSuccess) {
+ sid->cached = in_external_cache;
+ }
sslBuffer_Clear(&encodedToken);
}
@@ -1200,17 +1212,23 @@ ssl3_SetSIDSessionTicket(sslSessionID *sid,
PORT_Assert(newSessionTicket->ticket.data);
PORT_Assert(newSessionTicket->ticket.len != 0);
- /* if sid->u.ssl3.lock, we are updating an existing entry that is already
- * cached or was once cached, so we need to acquire and release the write
- * lock. Otherwise, this is a new session that isn't shared with anything
- * yet, so no locking is needed.
+ /* If this is in the client cache, we are updating an existing entry that is
+ * already cached or was once cached, so we need to acquire and release the
+ * write lock. Otherwise, this is a new session that isn't shared with
+ * anything yet, so no locking is needed.
*/
if (sid->u.ssl3.lock) {
+ PORT_Assert(sid->cached == in_client_cache);
PR_RWLock_Wlock(sid->u.ssl3.lock);
- if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
- SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
- PR_FALSE);
- }
+ }
+ /* If this was in the client cache, then we might have to free the old
+ * ticket. In TLS 1.3, we might get a replacement ticket if the server
+ * sends more than one ticket. */
+ if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
+ PORT_Assert(sid->cached == in_client_cache ||
+ sid->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+ SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
+ PR_FALSE);
}
PORT_Assert(!sid->u.ssl3.locked.sessionTicket.ticket.data);
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index a1d389214..c011b66a1 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -685,23 +685,6 @@ ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa)
}
/*
- * The TLS 1.2 RFC 5246, Section 7.2.1 says:
- *
- * Unless some other fatal alert has been transmitted, each party is
- * required to send a close_notify alert before closing the write side
- * of the connection. The other party MUST respond with a close_notify
- * alert of its own and close down the connection immediately,
- * discarding any pending writes. It is not required for the initiator
- * of the close to wait for the responding close_notify alert before
- * closing the read side of the connection.
- *
- * The second sentence requires that we send a close_notify alert when we
- * have received a close_notify alert. In practice, all SSL implementations
- * close the socket immediately after sending a close_notify alert (which is
- * allowed by the third sentence), so responding with a close_notify alert
- * would result in a write failure with the ECONNRESET error. This is why
- * we don't respond with a close_notify alert.
- *
* Also, in the unlikely event that the TCP pipe is full and the peer stops
* reading, the SSL3_SendAlert call in ssl_SecureClose and ssl_SecureShutdown
* may block indefinitely in blocking mode, and may fail (without retrying)
@@ -714,8 +697,7 @@ ssl_SecureClose(sslSocket *ss)
int rv;
if (!(ss->shutdownHow & ssl_SHUTDOWN_SEND) &&
- ss->firstHsDone &&
- !ss->recvdCloseNotify) {
+ ss->firstHsDone) {
/* We don't want the final alert to be Nagle delayed. */
if (!ss->delayDisabled) {
@@ -744,8 +726,7 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow)
if ((sslHow & ssl_SHUTDOWN_SEND) != 0 &&
!(ss->shutdownHow & ssl_SHUTDOWN_SEND) &&
- ss->firstHsDone &&
- !ss->recvdCloseNotify) {
+ ss->firstHsDone) {
(void)SSL3_SendAlert(ss, alert_warning, close_notify);
}
@@ -936,6 +917,25 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
firstClientWrite = ss->ssl3.hs.ws == idle_handshake;
ssl_ReleaseSSL3HandshakeLock(ss);
}
+ /* Allow the server to send 0.5 RTT data in TLS 1.3. Requesting a
+ * certificate implies that the server might condition its sending on
+ * client authentication, so force servers that do that to wait.
+ *
+ * What might not be obvious here is that this allows 0.5 RTT when doing
+ * PSK-based resumption. As a result, 0.5 RTT is always enabled when
+ * early data is accepted.
+ *
+ * This check might be more conservative than absolutely necessary.
+ * It's possible that allowing 0.5 RTT data when the server requests,
+ * but does not require client authentication is safe because we can
+ * expect the server to check for a client certificate properly. */
+ if (ss->sec.isServer &&
+ ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ !tls13_ShouldRequestClientAuth(ss)) {
+ ssl_GetSSL3HandshakeLock(ss);
+ allowEarlySend = TLS13_IN_HS_STATE(ss, wait_finished);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ }
if (!allowEarlySend && ss->handshake) {
rv = ssl_Do1stHandshake(ss);
}
@@ -971,7 +971,7 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
* 1-RTT later.
*/
ssl_GetSpecReadLock(ss);
- len = tls13_LimitEarlyData(ss, content_application_data, len);
+ len = tls13_LimitEarlyData(ss, ssl_ct_application_data, len);
ssl_ReleaseSpecReadLock(ss);
}
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index 33595ffae..ae904e29b 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -18,6 +18,8 @@
#include "private/pprio.h"
#include "nss.h"
#include "pk11pqg.h"
+#include "pk11pub.h"
+#include "tls13esni.h"
static const sslSocketOps ssl_default_ops = { /* No SSL. */
ssl_DefConnect,
@@ -82,7 +84,9 @@ static sslOptions ssl_defaults = {
.requireDHENamedGroups = PR_FALSE,
.enable0RttData = PR_FALSE,
.enableTls13CompatMode = PR_FALSE,
- .enableDtlsShortHeader = PR_FALSE
+ .enableDtlsShortHeader = PR_FALSE,
+ .enableHelloDowngradeCheck = PR_FALSE,
+ .enableV2CompatibleHello = PR_FALSE
};
/*
@@ -359,6 +363,13 @@ ssl_DupSocket(sslSocket *os)
ss->resumptionTokenCallback = os->resumptionTokenCallback;
ss->resumptionTokenContext = os->resumptionTokenContext;
+ if (os->esniKeys) {
+ ss->esniKeys = tls13_CopyESNIKeys(os->esniKeys);
+ if (!ss->esniKeys) {
+ goto loser;
+ }
+ }
+
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
if (rv != SECSuccess) {
@@ -444,6 +455,8 @@ ssl_DestroySocketContents(sslSocket *ss)
ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
+
+ tls13_DestroyESNIKeys(ss->esniKeys);
}
/*
@@ -821,6 +834,14 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
ss->opt.enableDtlsShortHeader = val;
break;
+ case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
+ ss->opt.enableHelloDowngradeCheck = val;
+ break;
+
+ case SSL_ENABLE_V2_COMPATIBLE_HELLO:
+ ss->opt.enableV2CompatibleHello = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -963,6 +984,12 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_DTLS_SHORT_HEADER:
val = ss->opt.enableDtlsShortHeader;
break;
+ case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
+ val = ss->opt.enableHelloDowngradeCheck;
+ break;
+ case SSL_ENABLE_V2_COMPATIBLE_HELLO:
+ val = ss->opt.enableV2CompatibleHello;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1089,6 +1116,12 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_DTLS_SHORT_HEADER:
val = ssl_defaults.enableDtlsShortHeader;
break;
+ case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
+ val = ssl_defaults.enableHelloDowngradeCheck;
+ break;
+ case SSL_ENABLE_V2_COMPATIBLE_HELLO:
+ val = ssl_defaults.enableV2CompatibleHello;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1284,6 +1317,14 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
ssl_defaults.enableDtlsShortHeader = val;
break;
+ case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
+ ssl_defaults.enableHelloDowngradeCheck = val;
+ break;
+
+ case SSL_ENABLE_V2_COMPATIBLE_HELLO:
+ ssl_defaults.enableV2CompatibleHello = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -3742,6 +3783,10 @@ ssl_GetKeyPairRef(sslKeyPair *keyPair)
void
ssl_FreeKeyPair(sslKeyPair *keyPair)
{
+ if (!keyPair) {
+ return;
+ }
+
PRInt32 newCount = PR_ATOMIC_DECREMENT(&keyPair->refCount);
if (!newCount) {
SECKEY_DestroyPrivateKey(keyPair->privKey);
@@ -3801,6 +3846,10 @@ ssl_CopyEphemeralKeyPair(sslEphemeralKeyPair *keyPair)
void
ssl_FreeEphemeralKeyPair(sslEphemeralKeyPair *keyPair)
{
+ if (!keyPair) {
+ return;
+ }
+
ssl_FreeKeyPair(keyPair->keys);
PR_REMOVE_LINK(&keyPair->link);
PORT_Free(keyPair);
@@ -3908,6 +3957,8 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
PR_INIT_CLIST(&ss->ssl3.hs.dtlsRcvdHandshake);
dtls_InitTimers(ss);
+ ss->esniKeys = NULL;
+
if (makeLocks) {
rv = ssl_MakeLocks(ss);
if (rv != SECSuccess)
@@ -3984,6 +4035,9 @@ struct {
EXP(SetResumptionToken),
EXP(GetResumptionTokenInfo),
EXP(DestroyResumptionTokenInfo),
+ EXP(SetESNIKeyPair),
+ EXP(EncodeESNIKeys),
+ EXP(EnableESNI),
#endif
{ "", NULL }
};
@@ -4049,6 +4103,7 @@ SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
unsigned int len)
{
sslSocket *ss = ssl_FindSocket(fd);
+ sslSessionID *sid = NULL;
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetResumptionToken",
@@ -4062,7 +4117,7 @@ SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
if (ss->firstHsDone || ss->ssl3.hs.ws != idle_handshake ||
ss->sec.isServer || len == 0 || !token) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
- goto done;
+ goto loser;
}
// We override any previously set session.
@@ -4073,41 +4128,44 @@ SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
PRINT_BUF(50, (ss, "incoming resumption token", token, len));
- ss->sec.ci.sid = ssl3_NewSessionID(ss, PR_FALSE);
- if (!ss->sec.ci.sid) {
- goto done;
+ sid = ssl3_NewSessionID(ss, PR_FALSE);
+ if (!sid) {
+ goto loser;
}
/* Populate NewSessionTicket values */
- SECStatus rv = ssl_DecodeResumptionToken(ss->sec.ci.sid, token, len);
+ SECStatus rv = ssl_DecodeResumptionToken(sid, token, len);
if (rv != SECSuccess) {
// If decoding fails, we assume the token is bad.
PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
- ssl_FreeSID(ss->sec.ci.sid);
- ss->sec.ci.sid = NULL;
- goto done;
+ goto loser;
}
- // Make sure that the token is valid.
- if (!ssl_IsResumptionTokenValid(ss)) {
- ssl_FreeSID(ss->sec.ci.sid);
- ss->sec.ci.sid = NULL;
+ // Make sure that the token is currently usable.
+ if (!ssl_IsResumptionTokenUsable(ss, sid)) {
PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
- goto done;
+ goto loser;
}
+ // Generate a new random session ID for this ticket.
+ rv = PK11_GenerateRandom(sid->u.ssl3.sessionID, SSL3_SESSIONID_BYTES);
+ if (rv != SECSuccess) {
+ goto loser; // Code set by PK11_GenerateRandom.
+ }
+ sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
/* Use the sid->cached as marker that this is from an external cache and
* we don't have to look up anything in the NSS internal cache. */
- ss->sec.ci.sid->cached = in_external_cache;
- // This has to be 2 to not free this in sendClientHello.
- ss->sec.ci.sid->references = 2;
- ss->sec.ci.sid->lastAccessTime = ssl_TimeSec();
+ sid->cached = in_external_cache;
+ sid->lastAccessTime = ssl_TimeSec();
+
+ ss->sec.ci.sid = sid;
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
return SECSuccess;
-done:
+loser:
+ ssl_FreeSID(sid);
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
@@ -4164,6 +4222,7 @@ SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
} else {
token.maxEarlyDataSize = 0;
}
+ token.expirationTime = sid.expirationTime;
token.length = PR_MIN(sizeof(SSLResumptionTokenInfo), len);
PORT_Memcpy(tokenOut, &token, token.length);
diff --git a/security/nss/lib/ssl/sslspec.c b/security/nss/lib/ssl/sslspec.c
index 7833eeab6..f2e72a4ec 100644
--- a/security/nss/lib/ssl/sslspec.c
+++ b/security/nss/lib/ssl/sslspec.c
@@ -203,7 +203,7 @@ ssl_CipherSpecAddRef(ssl3CipherSpec *spec)
SSL_GETPID(), SPEC_DIR(spec), spec, spec->refCt));
}
-static void
+void
ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial)
{
PK11_FreeSymKey(keyMaterial->key);
diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h
index bb1bec7a3..bd32a6e18 100644
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -35,6 +35,14 @@ typedef enum {
ssl_hs_message_hash = 254, /* Not a real message. */
} SSLHandshakeType;
+typedef enum {
+ ssl_ct_change_cipher_spec = 20,
+ ssl_ct_alert = 21,
+ ssl_ct_handshake = 22,
+ ssl_ct_application_data = 23,
+ ssl_ct_ack = 25
+} SSLContentType;
+
typedef struct SSL3StatisticsStr {
/* statistics from ssl3_SendClientHello (sch) */
long sch_sid_cache_hits;
@@ -446,7 +454,8 @@ typedef enum {
ssl_tls13_key_share_xtn = 51,
ssl_next_proto_nego_xtn = 13172, /* Deprecated. */
ssl_renegotiation_info_xtn = 0xff01,
- ssl_tls13_short_header_xtn = 0xff03 /* Deprecated. */
+ ssl_tls13_short_header_xtn = 0xff03, /* Deprecated. */
+ ssl_tls13_encrypted_sni_xtn = 0xffce,
} SSLExtensionType;
/* This is the old name for the supported_groups extensions. */
diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c
index 4d9170fb0..461cd2eb9 100644
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -21,6 +21,7 @@
#include "tls13hkdf.h"
#include "tls13con.h"
#include "tls13err.h"
+#include "tls13esni.h"
#include "tls13exthandle.h"
#include "tls13hashstate.h"
@@ -117,6 +118,7 @@ const char kHkdfLabelFinishedSecret[] = "finished";
const char kHkdfLabelResumptionMasterSecret[] = "res master";
const char kHkdfLabelExporterMasterSecret[] = "exp master";
const char kHkdfLabelResumption[] = "resumption";
+const char kHkdfLabelTrafficUpdate[] = "traffic upd";
const char kHkdfPurposeKey[] = "key";
const char kHkdfPurposeIv[] = "iv";
@@ -132,21 +134,6 @@ const char keylogLabelExporterSecret[] = "EXPORTER_SECRET";
PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <=
SSL_LIBRARY_VERSION_TLS_1_3);
-/* Use this instead of FATAL_ERROR when no alert shall be sent. */
-#define LOG_ERROR(ss, prError) \
- do { \
- SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \
- SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \
- PORT_SetError(prError); \
- } while (0)
-
-/* Log an error and generate an alert because something is irreparably wrong. */
-#define FATAL_ERROR(ss, prError, desc) \
- do { \
- LOG_ERROR(ss, prError); \
- tls13_FatalError(ss, prError, desc); \
- } while (0)
-
void
tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc)
{
@@ -354,16 +341,16 @@ tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
}
SECStatus
-tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef)
+tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef,
+ sslEphemeralKeyPair **keyPair)
{
SECStatus rv;
- sslEphemeralKeyPair *keyPair = NULL;
const ssl3DHParams *params;
PORT_Assert(groupDef);
switch (groupDef->keaType) {
case ssl_kea_ecdh:
- rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, &keyPair);
+ rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -371,7 +358,7 @@ tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef)
case ssl_kea_dh:
params = ssl_GetDHEParams(groupDef);
PORT_Assert(params->name != ssl_grp_ffdhe_custom);
- rv = ssl_CreateDHEKeyPair(groupDef, params, &keyPair);
+ rv = ssl_CreateDHEKeyPair(groupDef, params, keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -382,11 +369,24 @@ tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef)
return SECFailure;
}
- PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
return rv;
}
SECStatus
+tls13_AddKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef)
+{
+ sslEphemeralKeyPair *keyPair = NULL;
+ SECStatus rv;
+
+ rv = tls13_CreateKeyShare(ss, groupDef, &keyPair);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
+ return SECSuccess;
+}
+
+SECStatus
SSL_SendAdditionalKeyShares(PRFileDesc *fd, unsigned int count)
{
sslSocket *ss = ssl_FindSocket(fd);
@@ -413,20 +413,26 @@ tls13_SetupClientHello(sslSocket *ss)
NewSessionTicket *session_ticket = NULL;
sslSessionID *sid = ss->sec.ci.sid;
unsigned int numShares = 0;
+ SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
+ /* Do encrypted SNI. This may create a key share as a side effect. */
+ rv = tls13_ClientSetupESNI(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
/* Select the first enabled group.
* TODO(ekr@rtfm.com): be smarter about offering the group
* that the other side negotiated if we are resuming. */
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
- SECStatus rv;
if (!ss->namedGroupPreferences[i]) {
continue;
}
- rv = tls13_CreateKeyShare(ss, ss->namedGroupPreferences[i]);
+ rv = tls13_AddKeyShare(ss, ss->namedGroupPreferences[i]);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -455,8 +461,6 @@ tls13_SetupClientHello(sslSocket *ss)
}
if (ss->statelessResume) {
- SECStatus rv;
-
PORT_Assert(ss->sec.ci.sid);
rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
if (rv != SECSuccess) {
@@ -486,7 +490,7 @@ tls13_SetupClientHello(sslSocket *ss)
}
static SECStatus
-tls13_ImportDHEKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey,
+tls13_ImportDHEKeyShare(SECKEYPublicKey *peerKey,
PRUint8 *b, PRUint32 length,
SECKEYPublicKey *pubKey)
{
@@ -517,16 +521,20 @@ tls13_ImportDHEKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey,
return SECSuccess;
}
-static SECStatus
+SECStatus
tls13_HandleKeyShare(sslSocket *ss,
TLS13KeyShareEntry *entry,
- sslKeyPair *keyPair)
+ sslKeyPair *keyPair,
+ SSLHashType hash,
+ PK11SymKey **out)
{
PORTCheapArenaPool arena;
SECKEYPublicKey *peerKey;
CK_MECHANISM_TYPE mechanism;
PRErrorCode errorCode;
+ PK11SymKey *key;
SECStatus rv;
+ int keySize = 0;
PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
peerKey = PORT_ArenaZNew(&arena.arena, SECKEYPublicKey);
@@ -539,18 +547,19 @@ tls13_HandleKeyShare(sslSocket *ss,
switch (entry->group->keaType) {
case ssl_kea_ecdh:
- rv = ssl_ImportECDHKeyShare(ss, peerKey,
+ rv = ssl_ImportECDHKeyShare(peerKey,
entry->key_exchange.data,
entry->key_exchange.len,
entry->group);
mechanism = CKM_ECDH1_DERIVE;
break;
case ssl_kea_dh:
- rv = tls13_ImportDHEKeyShare(ss, peerKey,
+ rv = tls13_ImportDHEKeyShare(peerKey,
entry->key_exchange.data,
entry->key_exchange.len,
keyPair->pubKey);
mechanism = CKM_DH_PKCS_DERIVE;
+ keySize = peerKey->u.dh.publicValue.len;
break;
default:
PORT_Assert(0);
@@ -560,13 +569,14 @@ tls13_HandleKeyShare(sslSocket *ss,
goto loser;
}
- ss->ssl3.hs.dheSecret = PK11_PubDeriveWithKDF(
+ key = PK11_PubDeriveWithKDF(
keyPair->privKey, peerKey, PR_FALSE, NULL, NULL, mechanism,
- tls13_GetHkdfMechanism(ss), CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
- if (!ss->ssl3.hs.dheSecret) {
+ tls13_GetHkdfMechanismForHash(hash), CKA_DERIVE, keySize, CKD_NULL, NULL, NULL);
+ if (!key) {
ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
goto loser;
}
+ *out = key;
PORT_DestroyCheapArena(&arena);
return SECSuccess;
@@ -603,8 +613,8 @@ tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
secret = tls13_TrafficSecretRef(ss, direction);
rv = tls13_HkdfExpandLabel(*secret, tls13_GetHash(ss),
NULL, 0,
- kHkdfLabelApplicationTrafficSecret,
- strlen(kHkdfLabelApplicationTrafficSecret),
+ kHkdfLabelTrafficUpdate,
+ strlen(kHkdfLabelTrafficUpdate),
tls13_GetHmacMechanism(ss),
tls13_GetHashSize(ss),
&updatedSecret);
@@ -1417,30 +1427,6 @@ tls13_NegotiateKeyExchange(sslSocket *ss,
return SECSuccess;
}
-SSLAuthType
-ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
-{
- switch (scheme) {
- case ssl_sig_rsa_pkcs1_sha1:
- case ssl_sig_rsa_pkcs1_sha256:
- case ssl_sig_rsa_pkcs1_sha384:
- case ssl_sig_rsa_pkcs1_sha512:
- /* We report PSS signatures as being just RSA signatures. */
- case ssl_sig_rsa_pss_rsae_sha256:
- case ssl_sig_rsa_pss_rsae_sha384:
- case ssl_sig_rsa_pss_rsae_sha512:
- return ssl_auth_rsa_sign;
- case ssl_sig_ecdsa_secp256r1_sha256:
- case ssl_sig_ecdsa_secp384r1_sha384:
- case ssl_sig_ecdsa_secp521r1_sha512:
- case ssl_sig_ecdsa_sha1:
- return ssl_auth_ecdsa;
- default:
- PORT_Assert(0);
- }
- return ssl_auth_null;
-}
-
SECStatus
tls13_SelectServerCert(sslSocket *ss)
{
@@ -1469,6 +1455,7 @@ tls13_SelectServerCert(sslSocket *ss)
}
rv = ssl_PickSignatureScheme(ss,
+ cert->serverCert,
cert->serverKeyPair->pubKey,
cert->serverKeyPair->privKey,
ss->xtnData.sigSchemes,
@@ -2047,7 +2034,7 @@ tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare)
tls13_SetKeyExchangeType(ss, peerShare->group);
/* Generate our key */
- rv = tls13_CreateKeyShare(ss, peerShare->group);
+ rv = tls13_AddKeyShare(ss, peerShare->group);
if (rv != SECSuccess) {
return rv;
}
@@ -2067,7 +2054,9 @@ tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare)
return SECFailure; /* Error code set already. */
}
- rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys);
+ rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys,
+ tls13_GetHash(ss),
+ &ss->ssl3.hs.dheSecret);
return rv; /* Error code set already. */
}
@@ -2334,6 +2323,13 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECSuccess;
}
+PRBool
+tls13_ShouldRequestClientAuth(sslSocket *ss)
+{
+ return ss->opt.requestCertificate &&
+ ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk;
+}
+
static SECStatus
tls13_SendEncryptedServerSequence(sslSocket *ss)
{
@@ -2365,7 +2361,7 @@ tls13_SendEncryptedServerSequence(sslSocket *ss)
return SECFailure; /* error code is set. */
}
- if (ss->opt.requestCertificate) {
+ if (tls13_ShouldRequestClientAuth(ss)) {
rv = tls13_SendCertificateRequest(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code is set. */
@@ -2484,9 +2480,11 @@ tls13_SendServerHelloSequence(sslSocket *ss)
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
- TLS13_SET_HS_STATE(ss,
- ss->opt.requestCertificate ? wait_client_cert
- : wait_finished);
+ if (tls13_ShouldRequestClientAuth(ss)) {
+ TLS13_SET_HS_STATE(ss, wait_client_cert);
+ } else {
+ TLS13_SET_HS_STATE(ss, wait_finished);
+ }
}
ss->ssl3.hs.serverHelloTime = ssl_TimeUsec();
@@ -2512,6 +2510,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
}
if (ss->statelessResume) {
+ PORT_Assert(sid->version >= SSL_LIBRARY_VERSION_TLS_1_3);
if (tls13_GetHash(ss) !=
tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO,
@@ -2657,7 +2656,9 @@ tls13_HandleServerKeyShare(sslSocket *ss)
PORT_Assert(ssl_NamedGroupEnabled(ss, entry->group));
- rv = tls13_HandleKeyShare(ss, entry, keyPair->keys);
+ rv = tls13_HandleKeyShare(ss, entry, keyPair->keys,
+ tls13_GetHash(ss),
+ &ss->ssl3.hs.dheSecret);
if (rv != SECSuccess)
return SECFailure; /* Error code set by caller. */
@@ -3213,6 +3214,21 @@ tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec)
SSL_GETPID(), ss->fd, spec, spec->recordVersion));
}
+SSLAEADCipher
+tls13_GetAead(const ssl3BulkCipherDef *cipherDef)
+{
+ switch (cipherDef->calg) {
+ case ssl_calg_aes_gcm:
+ return tls13_AESGCM;
+ case ssl_calg_chacha20:
+ return tls13_ChaCha20Poly1305;
+ default:
+ PORT_Assert(PR_FALSE);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return NULL;
+ }
+}
+
static SECStatus
tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
{
@@ -3236,16 +3252,9 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
SSL_GETPID(), ss->fd, suite));
spec->cipherDef = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite));
- switch (spec->cipherDef->calg) {
- case ssl_calg_aes_gcm:
- spec->aead = tls13_AESGCM;
- break;
- case ssl_calg_chacha20:
- spec->aead = tls13_ChaCha20Poly1305;
- break;
- default:
- PORT_Assert(0);
- return SECFailure;
+ spec->aead = tls13_GetAead(spec->cipherDef);
+ if (!spec->aead) {
+ return SECFailure;
}
if (spec->epoch == TrafficKeyEarlyApplicationData) {
@@ -3427,9 +3436,31 @@ loser:
return SECFailure;
}
+TLS13KeyShareEntry *
+tls13_CopyKeyShareEntry(TLS13KeyShareEntry *o)
+{
+ TLS13KeyShareEntry *n;
+
+ PORT_Assert(o);
+ n = PORT_ZNew(TLS13KeyShareEntry);
+ if (!n) {
+ return NULL;
+ }
+
+ if (SECSuccess != SECITEM_CopyItem(NULL, &n->key_exchange, &o->key_exchange)) {
+ PORT_Free(n);
+ return NULL;
+ }
+ n->group = o->group;
+ return n;
+}
+
void
tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *offer)
{
+ if (!offer) {
+ return;
+ }
SECITEM_ZfreeItem(&offer->key_exchange, PR_FALSE);
PORT_ZFree(offer, sizeof(*offer));
}
@@ -3550,7 +3581,7 @@ tls13_AESGCM(ssl3KeyMaterial *keys,
CK_GCM_PARAMS gcmParams;
unsigned char nonce[12];
- PORT_Assert(additionalDataLen > 8);
+ PORT_Assert(additionalDataLen >= 8);
memset(&gcmParams, 0, sizeof(gcmParams));
gcmParams.pIv = nonce;
gcmParams.ulIvLen = sizeof(nonce);
@@ -3627,7 +3658,23 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
ss->xtnData.nextProto.data = NULL;
ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT;
}
- rv = ssl3_HandleExtensions(ss, &b, &length, ssl_hs_encrypted_extensions);
+
+ rv = ssl3_ParseExtensions(ss, &b, &length);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Error code set below */
+ }
+
+ /* If we sent ESNI, check the nonce. */
+ if (ss->xtnData.esniPrivateKey) {
+ PORT_Assert(ssl3_ExtensionAdvertised(ss, ssl_tls13_encrypted_sni_xtn));
+ rv = tls13_ClientCheckEsniXtn(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ /* Handle the rest of the extensions. */
+ rv = ssl3_HandleParsedExtensions(ss, ssl_hs_encrypted_extensions);
if (rv != SECSuccess) {
return SECFailure; /* Error code set below */
}
@@ -4025,6 +4072,7 @@ tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey,
PK11_FreeSymKey(secret);
PK11_DestroyContext(hmacCtx, PR_TRUE);
+ PRINT_BUF(50, (ss, "finished value", output, outputLenUint));
return SECSuccess;
abort:
@@ -4189,7 +4237,7 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- if (!ss->opt.requestCertificate &&
+ if (!tls13_ShouldRequestClientAuth(ss) &&
(ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) {
dtls_ReceivedFirstMessageInFlight(ss);
}
@@ -4679,7 +4727,8 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* Replace a previous session ticket when
* we receive a second NewSessionTicket message. */
- if (ss->sec.ci.sid->cached == in_client_cache) {
+ if (ss->sec.ci.sid->cached == in_client_cache ||
+ ss->sec.ci.sid->cached == in_external_cache) {
/* Create a new session ID. */
sslSessionID *sid = ssl3_NewSessionID(ss, PR_FALSE);
if (!sid) {
@@ -4758,7 +4807,8 @@ static const struct {
{ ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
{ ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello,
hello_retry_request) },
- { ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) }
+ { ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) },
+ { ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) }
};
tls13ExtensionStatus
@@ -4834,11 +4884,11 @@ tls13_FormatAdditionalData(
}
PRInt32
-tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend)
+tls13_LimitEarlyData(sslSocket *ss, SSLContentType type, PRInt32 toSend)
{
PRInt32 reduced;
- PORT_Assert(type == content_application_data);
+ PORT_Assert(type == ssl_ct_application_data);
PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
PORT_Assert(!ss->firstHsDone);
if (ss->ssl3.cwSpec->epoch != TrafficKeyEarlyApplicationData) {
@@ -4858,7 +4908,7 @@ tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend)
SECStatus
tls13_ProtectRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec,
- SSL3ContentType type,
+ SSLContentType type,
const PRUint8 *pIn,
PRUint32 contentLen,
sslBuffer *wrBuf)
@@ -4899,7 +4949,7 @@ tls13_ProtectRecord(sslSocket *ss,
*(SSL_BUFFER_NEXT(wrBuf) + contentLen) = type;
/* Create the header (ugly that we have to do it twice). */
- rv = ssl_InsertRecordHeader(ss, cwSpec, content_application_data,
+ rv = ssl_InsertRecordHeader(ss, cwSpec, ssl_ct_application_data,
&buf, &needsLength);
if (rv != SECSuccess) {
return SECFailure;
@@ -4951,7 +5001,7 @@ tls13_UnprotectRecord(sslSocket *ss,
ssl3CipherSpec *spec,
SSL3Ciphertext *cText,
sslBuffer *plaintext,
- SSL3ContentType *innerType,
+ SSLContentType *innerType,
SSL3AlertDescription *alert)
{
const ssl3BulkCipherDef *cipher_def = spec->cipherDef;
@@ -4966,26 +5016,26 @@ tls13_UnprotectRecord(sslSocket *ss,
SSL_GETPID(), ss->fd, spec, spec->epoch, spec->phase,
cText->seqNum, cText->buf->len));
- /* We can perform this test in variable time because the record's total
- * length and the ciphersuite are both public knowledge. */
- if (cText->buf->len < cipher_def->tag_size) {
- SSL_TRC(3,
- ("%d: TLS13[%d]: record too short to contain valid AEAD data",
- SSL_GETPID(), ss->fd));
- PORT_SetError(SSL_ERROR_BAD_MAC_READ);
- return SECFailure;
- }
-
/* Verify that the content type is right, even though we overwrite it.
* Also allow the DTLS short header in TLS 1.3. */
- if (!(cText->hdr[0] == content_application_data ||
+ if (!(cText->hdr[0] == ssl_ct_application_data ||
(IS_DTLS(ss) &&
ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
(cText->hdr[0] & 0xe0) == 0x20))) {
SSL_TRC(3,
("%d: TLS13[%d]: record has invalid exterior type=%2.2x",
SSL_GETPID(), ss->fd, cText->hdr[0]));
- /* Do we need a better error here? */
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE);
+ *alert = unexpected_message;
+ return SECFailure;
+ }
+
+ /* We can perform this test in variable time because the record's total
+ * length and the ciphersuite are both public knowledge. */
+ if (cText->buf->len < cipher_def->tag_size) {
+ SSL_TRC(3,
+ ("%d: TLS13[%d]: record too short to contain valid AEAD data",
+ SSL_GETPID(), ss->fd));
PORT_SetError(SSL_ERROR_BAD_MAC_READ);
return SECFailure;
}
@@ -5054,12 +5104,12 @@ tls13_UnprotectRecord(sslSocket *ss,
}
/* Record the type. */
- *innerType = (SSL3ContentType)plaintext->buf[plaintext->len - 1];
+ *innerType = (SSLContentType)plaintext->buf[plaintext->len - 1];
--plaintext->len;
/* Check that we haven't received too much 0-RTT data. */
if (spec->epoch == TrafficKeyEarlyApplicationData &&
- *innerType == content_application_data) {
+ *innerType == ssl_ct_application_data) {
if (plaintext->len > spec->earlyDataRemaining) {
*alert = unexpected_message;
PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA);
@@ -5242,9 +5292,11 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
ss->ssl3.hs.zeroRttState = ssl_0rtt_done;
- TLS13_SET_HS_STATE(ss,
- ss->opt.requestCertificate ? wait_client_cert
- : wait_finished);
+ if (tls13_ShouldRequestClientAuth(ss)) {
+ TLS13_SET_HS_STATE(ss, wait_client_cert);
+ } else {
+ TLS13_SET_HS_STATE(ss, wait_finished);
+ }
return SECSuccess;
}
@@ -5283,11 +5335,12 @@ tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf)
}
PRUint16
-tls13_EncodeDraftVersion(SSL3ProtocolVersion version)
+tls13_EncodeDraftVersion(SSL3ProtocolVersion version, SSLProtocolVariant variant)
{
-#ifdef TLS_1_3_DRAFT_VERSION
- if (version == SSL_LIBRARY_VERSION_TLS_1_3) {
- return 0x7f00 | TLS_1_3_DRAFT_VERSION;
+#ifdef DTLS_1_3_DRAFT_VERSION
+ if (version == SSL_LIBRARY_VERSION_TLS_1_3 &&
+ variant == ssl_variant_datagram) {
+ return 0x7f00 | DTLS_1_3_DRAFT_VERSION;
}
#endif
return (PRUint16)version;
@@ -5297,7 +5350,6 @@ SECStatus
tls13_ClientReadSupportedVersion(sslSocket *ss)
{
PRUint32 temp;
- SSL3ProtocolVersion v;
TLSExtension *versionExtension;
SECItem it;
SECStatus rv;
@@ -5319,29 +5371,15 @@ tls13_ClientReadSupportedVersion(sslSocket *ss)
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter);
return SECFailure;
}
- v = (SSL3ProtocolVersion)temp;
- /* You cannot negotiate < TLS 1.3 with supported_versions. */
- if (v < SSL_LIBRARY_VERSION_TLS_1_3) {
+ if (temp != tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3,
+ ss->protocolVariant)) {
+ /* You cannot negotiate < TLS 1.3 with supported_versions. */
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter);
return SECFailure;
}
-#ifdef TLS_1_3_DRAFT_VERSION
- if (temp == SSL_LIBRARY_VERSION_TLS_1_3) {
- FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
- return SECFailure;
- }
- if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) {
- v = SSL_LIBRARY_VERSION_TLS_1_3;
- } else {
- v = (SSL3ProtocolVersion)temp;
- }
-#else
- v = (SSL3ProtocolVersion)temp;
-#endif
-
- ss->version = v;
+ ss->version = SSL_LIBRARY_VERSION_TLS_1_3;
return SECSuccess;
}
@@ -5365,7 +5403,7 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions)
return SECFailure;
}
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
- PRUint16 wire = tls13_EncodeDraftVersion(version);
+ PRUint16 wire = tls13_EncodeDraftVersion(version, ss->protocolVariant);
unsigned long offset;
for (offset = 0; offset < versions.len; offset += 2) {
diff --git a/security/nss/lib/ssl/tls13con.h b/security/nss/lib/ssl/tls13con.h
index f35b20023..f3b2cb390 100644
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -28,7 +28,7 @@ typedef enum {
SECStatus tls13_UnprotectRecord(
sslSocket *ss, ssl3CipherSpec *spec,
SSL3Ciphertext *cText, sslBuffer *plaintext,
- SSL3ContentType *innerType,
+ SSLContentType *innerType,
SSL3AlertDescription *alert);
#if defined(WIN32)
@@ -64,7 +64,7 @@ void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
SSL3AlertDescription desc);
SECStatus tls13_SetupClientHello(sslSocket *ss);
SECStatus tls13_MaybeDo0RTTHandshake(sslSocket *ss);
-PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend);
+PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSLContentType type, PRInt32 toSend);
PRBool tls13_AllowPskCipher(const sslSocket *ss,
const ssl3CipherSuiteDef *cipher_def);
PRBool tls13_PskSuiteEnabled(sslSocket *ss);
@@ -85,26 +85,36 @@ SECStatus tls13_ConstructHelloRetryRequest(sslSocket *ss,
sslBuffer *buffer);
SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *b,
PRUint32 length);
+SECStatus tls13_HandleKeyShare(sslSocket *ss,
+ TLS13KeyShareEntry *entry,
+ sslKeyPair *keyPair,
+ SSLHashType hash,
+ PK11SymKey **out);
+TLS13KeyShareEntry *tls13_CopyKeyShareEntry(TLS13KeyShareEntry *o);
void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry);
void tls13_DestroyKeyShares(PRCList *list);
-SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef);
+SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef,
+ sslEphemeralKeyPair **keyPair);
+SECStatus tls13_AddKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef);
void tls13_DestroyEarlyData(PRCList *list);
SECStatus tls13_SetAlertCipherSpec(sslSocket *ss);
tls13ExtensionStatus tls13_ExtensionStatus(PRUint16 extension,
SSLHandshakeType message);
SECStatus tls13_ProtectRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec,
- SSL3ContentType type,
+ SSLContentType type,
const PRUint8 *pIn,
PRUint32 contentLen,
sslBuffer *wrBuf);
PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len);
SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
-PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
+PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version,
+ SSLProtocolVariant variant);
SECStatus tls13_ClientReadSupportedVersion(sslSocket *ss);
SECStatus tls13_NegotiateVersion(sslSocket *ss,
const TLSExtension *supported_versions);
+PRBool tls13_ShouldRequestClientAuth(sslSocket *ss);
PRBool tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid);
void tls13_AntiReplayRollover(PRTime now);
@@ -119,6 +129,22 @@ SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request,
PRBool buffer);
SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate);
PRBool tls13_MaybeTls13(sslSocket *ss);
+SSLAEADCipher tls13_GetAead(const ssl3BulkCipherDef *cipherDef);
void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
+/* Use this instead of FATAL_ERROR when no alert shall be sent. */
+#define LOG_ERROR(ss, prError) \
+ do { \
+ SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \
+ SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \
+ PORT_SetError(prError); \
+ } while (0)
+
+/* Log an error and generate an alert because something is irreparably wrong. */
+#define FATAL_ERROR(ss, prError, desc) \
+ do { \
+ LOG_ERROR(ss, prError); \
+ tls13_FatalError(ss, prError, desc); \
+ } while (0)
+
#endif /* __tls13con_h_ */
diff --git a/security/nss/lib/ssl/tls13esni.c b/security/nss/lib/ssl/tls13esni.c
new file mode 100644
index 000000000..e2328769b
--- /dev/null
+++ b/security/nss/lib/ssl/tls13esni.c
@@ -0,0 +1,844 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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/. */
+
+#define TLS13_ESNI_VERSION 0xff01
+
+/*
+ * struct {
+ * uint16 version;
+ * uint8 checksum[4];
+ * KeyShareEntry keys<4..2^16-1>;
+ * CipherSuite cipher_suites<2..2^16-2>;
+ * uint16 padded_length;
+ * uint64 not_before;
+ * uint64 not_after;
+ * Extension extensions<0..2^16-1>;
+ * } ESNIKeys;
+ */
+#include "nss.h"
+#include "pk11func.h"
+#include "ssl.h"
+#include "sslproto.h"
+#include "sslimpl.h"
+#include "ssl3exthandle.h"
+#include "tls13esni.h"
+#include "tls13exthandle.h"
+#include "tls13hkdf.h"
+
+const char kHkdfPurposeEsniKey[] = "esni key";
+const char kHkdfPurposeEsniIv[] = "esni iv";
+
+void
+tls13_DestroyESNIKeys(sslEsniKeys *keys)
+{
+ if (!keys) {
+ return;
+ }
+ SECITEM_FreeItem(&keys->data, PR_FALSE);
+ PORT_Free((void *)keys->dummySni);
+ tls13_DestroyKeyShares(&keys->keyShares);
+ ssl_FreeEphemeralKeyPair(keys->privKey);
+ SECITEM_FreeItem(&keys->suites, PR_FALSE);
+ PORT_ZFree(keys, sizeof(sslEsniKeys));
+}
+
+sslEsniKeys *
+tls13_CopyESNIKeys(sslEsniKeys *okeys)
+{
+ sslEsniKeys *nkeys;
+ SECStatus rv;
+
+ PORT_Assert(okeys);
+
+ nkeys = PORT_ZNew(sslEsniKeys);
+ if (!nkeys) {
+ return NULL;
+ }
+ PR_INIT_CLIST(&nkeys->keyShares);
+ rv = SECITEM_CopyItem(NULL, &nkeys->data, &okeys->data);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (okeys->dummySni) {
+ nkeys->dummySni = PORT_Strdup(okeys->dummySni);
+ if (!nkeys->dummySni) {
+ goto loser;
+ }
+ }
+ for (PRCList *cur_p = PR_LIST_HEAD(&okeys->keyShares);
+ cur_p != &okeys->keyShares;
+ cur_p = PR_NEXT_LINK(cur_p)) {
+ TLS13KeyShareEntry *copy = tls13_CopyKeyShareEntry(
+ (TLS13KeyShareEntry *)cur_p);
+ if (!copy) {
+ goto loser;
+ }
+ PR_APPEND_LINK(&copy->link, &nkeys->keyShares);
+ }
+ if (okeys->privKey) {
+ nkeys->privKey = ssl_CopyEphemeralKeyPair(okeys->privKey);
+ if (!nkeys->privKey) {
+ goto loser;
+ }
+ }
+ rv = SECITEM_CopyItem(NULL, &nkeys->suites, &okeys->suites);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ nkeys->paddedLength = okeys->paddedLength;
+ nkeys->notBefore = okeys->notBefore;
+ nkeys->notAfter = okeys->notAfter;
+ return nkeys;
+
+loser:
+ tls13_DestroyESNIKeys(nkeys);
+ return NULL;
+}
+
+/* Checksum is a 4-byte array. */
+static SECStatus
+tls13_ComputeESNIKeysChecksum(const PRUint8 *buf, unsigned int len,
+ PRUint8 *checksum)
+{
+ SECItem copy;
+ SECStatus rv;
+ PRUint8 sha256[32];
+
+ rv = SECITEM_MakeItem(NULL, &copy, buf, len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Stomp the checksum. */
+ PORT_Memset(copy.data + 2, 0, 4);
+
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(ssl_hash_sha256),
+ sha256,
+ copy.data, copy.len);
+ SECITEM_FreeItem(&copy, PR_FALSE);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ PORT_Memcpy(checksum, sha256, 4);
+ return SECSuccess;
+}
+
+static SECStatus
+tls13_DecodeESNIKeys(SECItem *data, sslEsniKeys **keysp)
+{
+ SECStatus rv;
+ sslReadBuffer tmp;
+ PRUint64 tmpn;
+ sslEsniKeys *keys;
+ PRUint8 checksum[4];
+ sslReader rdr = SSL_READER(data->data, data->len);
+
+ rv = sslRead_ReadNumber(&rdr, 2, &tmpn);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ if (tmpn != TLS13_ESNI_VERSION) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
+ return SECFailure;
+ }
+ keys = PORT_ZNew(sslEsniKeys);
+ if (!keys) {
+ return SECFailure;
+ }
+ PR_INIT_CLIST(&keys->keyShares);
+
+ /* Make a copy. */
+ rv = SECITEM_CopyItem(NULL, &keys->data, data);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = tls13_ComputeESNIKeysChecksum(data->data, data->len, checksum);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Read and check checksum. */
+ rv = sslRead_Read(&rdr, 4, &tmp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ if (0 != NSS_SecureMemcmp(tmp.buf, checksum, 4)) {
+ goto loser;
+ }
+
+ /* Parse the key shares. */
+ rv = sslRead_ReadVariable(&rdr, 2, &tmp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ sslReader rdr2 = SSL_READER(tmp.buf, tmp.len);
+ while (SSL_READER_REMAINING(&rdr2)) {
+ TLS13KeyShareEntry *ks = NULL;
+
+ rv = tls13_DecodeKeyShareEntry(&rdr2, &ks);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ if (ks) {
+ PR_APPEND_LINK(&ks->link, &keys->keyShares);
+ }
+ }
+
+ /* Parse cipher suites. */
+ rv = sslRead_ReadVariable(&rdr, 2, &tmp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ /* This can't be odd. */
+ if (tmp.len & 1) {
+ goto loser;
+ }
+ rv = SECITEM_MakeItem(NULL, &keys->suites, (PRUint8 *)tmp.buf, tmp.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Padded Length */
+ rv = sslRead_ReadNumber(&rdr, 2, &tmpn);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ keys->paddedLength = (PRUint16)tmpn;
+
+ /* Not Before */
+ rv = sslRead_ReadNumber(&rdr, 8, &keys->notBefore);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Not After */
+ rv = sslRead_ReadNumber(&rdr, 8, &keys->notAfter);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Extensions, which we ignore. */
+ rv = sslRead_ReadVariable(&rdr, 2, &tmp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Check that this is empty. */
+ if (SSL_READER_REMAINING(&rdr) > 0) {
+ goto loser;
+ }
+
+ *keysp = keys;
+ return SECSuccess;
+
+loser:
+ tls13_DestroyESNIKeys(keys);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
+
+ return SECFailure;
+}
+
+/* Encode an ESNI keys structure. We only allow one key
+ * share. */
+SECStatus
+SSLExp_EncodeESNIKeys(PRUint16 *cipherSuites, unsigned int cipherSuiteCount,
+ SSLNamedGroup group, SECKEYPublicKey *pubKey,
+ PRUint16 pad, PRUint64 notBefore, PRUint64 notAfter,
+ PRUint8 *out, unsigned int *outlen, unsigned int maxlen)
+{
+ unsigned int savedOffset;
+ SECStatus rv;
+ sslBuffer b = SSL_BUFFER_EMPTY;
+
+ rv = sslBuffer_AppendNumber(&b, TLS13_ESNI_VERSION, 2);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = sslBuffer_Skip(&b, 4, &savedOffset);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Length of vector. */
+ rv = sslBuffer_AppendNumber(
+ &b, tls13_SizeOfKeyShareEntry(pubKey), 2);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Our one key share. */
+ rv = tls13_EncodeKeyShareEntry(&b, group, pubKey);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Cipher suites. */
+ rv = sslBuffer_AppendNumber(&b, cipherSuiteCount * 2, 2);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ for (unsigned int i = 0; i < cipherSuiteCount; i++) {
+ rv = sslBuffer_AppendNumber(&b, cipherSuites[i], 2);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
+ /* Padding Length. Fixed for now. */
+ rv = sslBuffer_AppendNumber(&b, pad, 2);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Start time. */
+ rv = sslBuffer_AppendNumber(&b, notBefore, 8);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* End time. */
+ rv = sslBuffer_AppendNumber(&b, notAfter, 8);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* No extensions. */
+ rv = sslBuffer_AppendNumber(&b, 0, 2);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = tls13_ComputeESNIKeysChecksum(SSL_BUFFER_BASE(&b),
+ SSL_BUFFER_LEN(&b),
+ SSL_BUFFER_BASE(&b) + 2);
+ if (rv != SECSuccess) {
+ PORT_Assert(PR_FALSE);
+ goto loser;
+ }
+
+ if (SSL_BUFFER_LEN(&b) > maxlen) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+ PORT_Memcpy(out, SSL_BUFFER_BASE(&b), SSL_BUFFER_LEN(&b));
+ *outlen = SSL_BUFFER_LEN(&b);
+
+ sslBuffer_Clear(&b);
+ return SECSuccess;
+loser:
+ sslBuffer_Clear(&b);
+ return SECFailure;
+}
+
+SECStatus
+SSLExp_SetESNIKeyPair(PRFileDesc *fd,
+ SECKEYPrivateKey *privKey,
+ const PRUint8 *record, unsigned int recordLen)
+{
+ sslSocket *ss;
+ SECStatus rv;
+ sslEsniKeys *keys = NULL;
+ SECKEYPublicKey *pubKey = NULL;
+ SECItem data = { siBuffer, CONST_CAST(PRUint8, record), recordLen };
+ PLArenaPool *arena = NULL;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in %s",
+ SSL_GETPID(), fd, __FUNCTION__));
+ return SECFailure;
+ }
+
+ rv = tls13_DecodeESNIKeys(&data, &keys);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Check the cipher suites. */
+ (void)ssl3_config_match_init(ss);
+ /* Make sure the cipher suite is OK. */
+ SSLVersionRange vrange = { SSL_LIBRARY_VERSION_TLS_1_3,
+ SSL_LIBRARY_VERSION_TLS_1_3 };
+
+ sslReader csrdr = SSL_READER(keys->suites.data,
+ keys->suites.len);
+ while (SSL_READER_REMAINING(&csrdr)) {
+ PRUint64 asuite;
+
+ rv = sslRead_ReadNumber(&csrdr, 2, &asuite);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ const ssl3CipherSuiteCfg *suiteCfg =
+ ssl_LookupCipherSuiteCfg(asuite, ss->cipherSuites);
+ if (!ssl3_config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) {
+ /* Illegal suite. */
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+ }
+
+ if (PR_CLIST_IS_EMPTY(&keys->keyShares)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+ if (PR_PREV_LINK(&keys->keyShares) != PR_NEXT_LINK(&keys->keyShares)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+ TLS13KeyShareEntry *entry = (TLS13KeyShareEntry *)PR_LIST_HEAD(
+ &keys->keyShares);
+ if (entry->group->keaType != ssl_kea_ecdh) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ goto loser;
+ }
+ pubKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
+ if (!pubKey) {
+ goto loser;
+ }
+ pubKey->arena = arena;
+ arena = NULL; /* From here, this will be destroyed with the pubkey. */
+ /* Dummy PKCS11 values because this key isn't on a slot. */
+ pubKey->pkcs11Slot = NULL;
+ pubKey->pkcs11ID = CK_INVALID_HANDLE;
+ rv = ssl_ImportECDHKeyShare(pubKey,
+ entry->key_exchange.data,
+ entry->key_exchange.len,
+ entry->group);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ privKey = SECKEY_CopyPrivateKey(privKey);
+ if (!privKey) {
+ goto loser;
+ }
+ keys->privKey = ssl_NewEphemeralKeyPair(entry->group, privKey, pubKey);
+ if (!keys->privKey) {
+ goto loser;
+ }
+ pubKey = NULL;
+ ss->esniKeys = keys;
+ return SECSuccess;
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ SECKEY_DestroyPublicKey(pubKey);
+ tls13_DestroyESNIKeys(keys);
+ return SECFailure;
+}
+
+SECStatus
+SSLExp_EnableESNI(PRFileDesc *fd,
+ const PRUint8 *esniKeys,
+ unsigned int esniKeysLen,
+ const char *dummySNI)
+{
+ sslSocket *ss;
+ sslEsniKeys *keys = NULL;
+ SECItem data = { siBuffer, CONST_CAST(PRUint8, esniKeys), esniKeysLen };
+ SECStatus rv;
+
+ ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in %s",
+ SSL_GETPID(), fd, __FUNCTION__));
+ return SECFailure;
+ }
+
+ rv = tls13_DecodeESNIKeys(&data, &keys);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (dummySNI) {
+ keys->dummySni = PORT_Strdup(dummySNI);
+ if (!keys->dummySni) {
+ tls13_DestroyESNIKeys(keys);
+ return SECFailure;
+ }
+ }
+
+ /* Delete in case it was set before. */
+ tls13_DestroyESNIKeys(ss->esniKeys);
+ ss->esniKeys = keys;
+
+ return SECSuccess;
+}
+
+/*
+ * struct {
+ * opaque record_digest<0..2^16-1>;
+ * KeyShareEntry esni_key_share;
+ * Random client_hello_random;
+ * } ESNIContents;
+ */
+SECStatus
+tls13_ComputeESNIKeys(const sslSocket *ss,
+ TLS13KeyShareEntry *entry,
+ sslKeyPair *keyPair,
+ const ssl3CipherSuiteDef *suite,
+ const PRUint8 *esniKeysHash,
+ const PRUint8 *keyShareBuf,
+ unsigned int keyShareBufLen,
+ const PRUint8 *clientRandom,
+ ssl3KeyMaterial *keyMat)
+{
+ PK11SymKey *Z = NULL;
+ PK11SymKey *Zx = NULL;
+ SECStatus ret = SECFailure;
+ PRUint8 esniContentsBuf[256]; /* Just big enough. */
+ sslBuffer esniContents = SSL_BUFFER(esniContentsBuf);
+ PRUint8 hash[64];
+ const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suite);
+ size_t keySize = cipherDef->key_size;
+ size_t ivSize = cipherDef->iv_size +
+ cipherDef->explicit_nonce_size; /* This isn't always going to
+ * work, but it does for
+ * AES-GCM */
+ unsigned int hashSize = tls13_GetHashSizeForHash(suite->prf_hash);
+ SECStatus rv;
+
+ rv = tls13_HandleKeyShare(CONST_CAST(sslSocket, ss), entry, keyPair,
+ suite->prf_hash, &Z);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = tls13_HkdfExtract(NULL, Z, suite->prf_hash, &Zx);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Encode ESNIContents. */
+ rv = sslBuffer_AppendVariable(&esniContents,
+ esniKeysHash, hashSize, 2);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = sslBuffer_Append(&esniContents, keyShareBuf, keyShareBufLen);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = sslBuffer_Append(&esniContents, clientRandom, SSL3_RANDOM_LENGTH);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ PORT_Assert(hashSize <= sizeof(hash));
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(suite->prf_hash),
+ hash,
+ SSL_BUFFER_BASE(&esniContents),
+ SSL_BUFFER_LEN(&esniContents));
+ ;
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = tls13_HkdfExpandLabel(Zx, suite->prf_hash,
+ hash, hashSize,
+ kHkdfPurposeEsniKey, strlen(kHkdfPurposeEsniKey),
+ ssl3_Alg2Mech(cipherDef->calg),
+ keySize,
+ &keyMat->key);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = tls13_HkdfExpandLabelRaw(Zx, suite->prf_hash,
+ hash, hashSize,
+ kHkdfPurposeEsniIv, strlen(kHkdfPurposeEsniIv),
+ keyMat->iv, ivSize);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ ret = SECSuccess;
+
+loser:
+ PK11_FreeSymKey(Z);
+ PK11_FreeSymKey(Zx);
+ return ret;
+}
+
+/* Set up ESNI. This generates a private key as a side effect. */
+SECStatus
+tls13_ClientSetupESNI(sslSocket *ss)
+{
+ ssl3CipherSuite suite;
+ sslEphemeralKeyPair *keyPair;
+ size_t i;
+ PRCList *cur;
+ SECStatus rv;
+ TLS13KeyShareEntry *share;
+ const sslNamedGroupDef *group = NULL;
+ PRTime now = PR_Now() / PR_USEC_PER_SEC;
+
+ if (!ss->esniKeys) {
+ return SECSuccess;
+ }
+
+ if ((ss->esniKeys->notBefore > now) || (ss->esniKeys->notAfter < now)) {
+ return SECSuccess;
+ }
+
+ /* If we're not sending SNI, don't send ESNI. */
+ if (!ssl_ShouldSendSNIExtension(ss, ss->url)) {
+ return SECSuccess;
+ }
+
+ /* Pick the group. */
+ for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
+ for (cur = PR_NEXT_LINK(&ss->esniKeys->keyShares);
+ cur != &ss->esniKeys->keyShares;
+ cur = PR_NEXT_LINK(cur)) {
+ if (!ss->namedGroupPreferences[i]) {
+ continue;
+ }
+ share = (TLS13KeyShareEntry *)cur;
+ if (share->group->name == ss->namedGroupPreferences[i]->name) {
+ group = ss->namedGroupPreferences[i];
+ break;
+ }
+ }
+ }
+
+ if (!group) {
+ /* No compatible group. */
+ return SECSuccess;
+ }
+
+ rv = ssl3_NegotiateCipherSuiteInner(ss, &ss->esniKeys->suites,
+ SSL_LIBRARY_VERSION_TLS_1_3, &suite);
+ if (rv != SECSuccess) {
+ return SECSuccess;
+ }
+
+ rv = tls13_CreateKeyShare(ss, group, &keyPair);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ ss->xtnData.esniPrivateKey = keyPair;
+ ss->xtnData.esniSuite = suite;
+ ss->xtnData.peerEsniShare = share;
+
+ return SECSuccess;
+}
+
+/*
+ * struct {
+ * CipherSuite suite;
+ * KeyShareEntry key_share;
+ * opaque record_digest<0..2^16-1>;
+ * opaque encrypted_sni<0..2^16-1>;
+ * } ClientEncryptedSNI;
+ *
+ * struct {
+ * ServerNameList sni;
+ * opaque zeros[ESNIKeys.padded_length - length(sni)];
+ * } PaddedServerNameList;
+ *
+ * struct {
+ * uint8 nonce[16];
+ * PaddedServerNameList realSNI;
+ * } ClientESNIInner;
+ */
+SECStatus
+tls13_FormatEsniAADInput(sslBuffer *aadInput,
+ PRUint8 *keyShare, unsigned int keyShareLen)
+{
+ SECStatus rv;
+
+ /* 8 bytes of 0 for the sequence number. */
+ rv = sslBuffer_AppendNumber(aadInput, 0, 8);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Key share. */
+ PORT_Assert(keyShareLen > 0);
+ rv = sslBuffer_Append(aadInput, keyShare, keyShareLen);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+static SECStatus
+tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite,
+ const ssl3CipherSuiteDef **suiteDefp,
+ SSLAEADCipher *aeadp)
+{
+ SECStatus rv;
+ const ssl3CipherSuiteDef *suiteDef;
+ SSLAEADCipher aead;
+
+ /* Check against the suite list for ESNI */
+ PRBool csMatch = PR_FALSE;
+ sslReader csrdr = SSL_READER(ss->esniKeys->suites.data,
+ ss->esniKeys->suites.len);
+ while (SSL_READER_REMAINING(&csrdr)) {
+ PRUint64 asuite;
+
+ rv = sslRead_ReadNumber(&csrdr, 2, &asuite);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ if (asuite == suite) {
+ csMatch = PR_TRUE;
+ break;
+ }
+ }
+ if (!csMatch) {
+ return SECFailure;
+ }
+
+ suiteDef = ssl_LookupCipherSuiteDef(suite);
+ PORT_Assert(suiteDef);
+ if (!suiteDef) {
+ return SECFailure;
+ }
+ aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef));
+ if (!aead) {
+ return SECFailure;
+ }
+
+ *suiteDefp = suiteDef;
+ *aeadp = aead;
+ return SECSuccess;
+}
+
+SECStatus
+tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
+ PRUint8 *out, int *outLen, int maxLen)
+{
+ sslReader rdr = SSL_READER(in, inLen);
+ PRUint64 suite;
+ const ssl3CipherSuiteDef *suiteDef;
+ SSLAEADCipher aead = NULL;
+ TLSExtension *keyShareExtension;
+ TLS13KeyShareEntry *entry = NULL;
+ ssl3KeyMaterial keyMat = { NULL };
+
+ sslBuffer aadInput = SSL_BUFFER_EMPTY;
+ const PRUint8 *keyShareBuf;
+ sslReadBuffer buf;
+ unsigned int keyShareBufLen;
+ PRUint8 hash[64];
+ SECStatus rv;
+
+ /* Read the cipher suite. */
+ rv = sslRead_ReadNumber(&rdr, 2, &suite);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Find the AEAD */
+ rv = tls13_ServerGetEsniAEAD(ss, suite, &suiteDef, &aead);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Note where the KeyShare starts. */
+ keyShareBuf = SSL_READER_CURRENT(&rdr);
+ rv = tls13_DecodeKeyShareEntry(&rdr, &entry);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ keyShareBufLen = SSL_READER_CURRENT(&rdr) - keyShareBuf;
+ if (!entry || entry->group->name != ss->esniKeys->privKey->group->name) {
+ goto loser;
+ }
+
+ /* The hash of the ESNIKeys structure. */
+ rv = sslRead_ReadVariable(&rdr, 2, &buf);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Check that the hash matches. */
+ unsigned int hashLen = tls13_GetHashSizeForHash(suiteDef->prf_hash);
+ PORT_Assert(hashLen <= sizeof(hash));
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(suiteDef->prf_hash),
+ hash,
+ ss->esniKeys->data.data, ss->esniKeys->data.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ if (buf.len != hashLen) {
+ /* This is malformed. */
+ goto loser;
+ }
+ if (0 != NSS_SecureMemcmp(hash, buf.buf, hashLen)) {
+ goto loser;
+ }
+
+ rv = tls13_ComputeESNIKeys(ss, entry,
+ ss->esniKeys->privKey->keys,
+ suiteDef,
+ hash, keyShareBuf, keyShareBufLen,
+ ((sslSocket *)ss)->ssl3.hs.client_random,
+ &keyMat);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Read the ciphertext. */
+ rv = sslRead_ReadVariable(&rdr, 2, &buf);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Check that this is empty. */
+ if (SSL_READER_REMAINING(&rdr) > 0) {
+ goto loser;
+ }
+
+ /* Find the key share extension. */
+ keyShareExtension = ssl3_FindExtension(CONST_CAST(sslSocket, ss),
+ ssl_tls13_key_share_xtn);
+ if (!keyShareExtension) {
+ goto loser;
+ }
+ rv = tls13_FormatEsniAADInput(&aadInput,
+ keyShareExtension->data.data,
+ keyShareExtension->data.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = aead(&keyMat, PR_TRUE /* Decrypt */,
+ out, outLen, maxLen,
+ buf.buf, buf.len,
+ SSL_BUFFER_BASE(&aadInput),
+ SSL_BUFFER_LEN(&aadInput));
+ sslBuffer_Clear(&aadInput);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ ssl_DestroyKeyMaterial(&keyMat);
+ tls13_DestroyKeyShareEntry(entry);
+ return SECSuccess;
+
+loser:
+ FATAL_ERROR(CONST_CAST(sslSocket, ss), SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter);
+ ssl_DestroyKeyMaterial(&keyMat); /* Safe because zeroed. */
+ if (entry) {
+ tls13_DestroyKeyShareEntry(entry);
+ }
+ return SECFailure;
+}
diff --git a/security/nss/lib/ssl/tls13esni.h b/security/nss/lib/ssl/tls13esni.h
new file mode 100644
index 000000000..6c52c9952
--- /dev/null
+++ b/security/nss/lib/ssl/tls13esni.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is PRIVATE to SSL.
+ *
+ * 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 __tls13esni_h_
+#define __tls13esni_h_
+
+struct sslEsniKeysStr {
+ SECItem data; /* The encoded record. */
+ sslEphemeralKeyPair *privKey;
+ const char *dummySni;
+ PRCList keyShares; /* List of TLS13KeyShareEntry */
+ SECItem suites;
+ PRUint16 paddedLength;
+ PRUint64 notBefore;
+ PRUint64 notAfter;
+};
+
+SECStatus SSLExp_SetESNIKeyPair(PRFileDesc *fd,
+ SECKEYPrivateKey *privKey,
+ const PRUint8 *record, unsigned int recordLen);
+
+SECStatus SSLExp_EnableESNI(PRFileDesc *fd, const PRUint8 *esniKeys,
+ unsigned int esniKeysLen, const char *dummySNI);
+SECStatus SSLExp_EncodeESNIKeys(PRUint16 *cipherSuites, unsigned int cipherSuiteCount,
+ SSLNamedGroup group, SECKEYPublicKey *pubKey,
+ PRUint16 pad, PRUint64 notBefore, PRUint64 notAfter,
+ PRUint8 *out, unsigned int *outlen, unsigned int maxlen);
+sslEsniKeys *tls13_CopyESNIKeys(sslEsniKeys *okeys);
+void tls13_DestroyESNIKeys(sslEsniKeys *keys);
+SECStatus tls13_ClientSetupESNI(sslSocket *ss);
+SECStatus tls13_ComputeESNIKeys(const sslSocket *ss,
+ TLS13KeyShareEntry *entry,
+ sslKeyPair *keyPair,
+ const ssl3CipherSuiteDef *suite,
+ const PRUint8 *esniKeysHash,
+ const PRUint8 *keyShareBuf,
+ unsigned int keyShareBufLen,
+ const PRUint8 *clientRandom,
+ ssl3KeyMaterial *keyMat);
+SECStatus tls13_FormatEsniAADInput(sslBuffer *aadInput,
+ PRUint8 *keyShare, unsigned int keyShareLen);
+
+SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
+ PRUint8 *out, int *outLen, int maxLen);
+
+#endif
diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c
index 1ab8a8e59..8ed18f69c 100644
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -12,6 +12,7 @@
#include "pk11pub.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
+#include "tls13esni.h"
#include "tls13exthandle.h"
SECStatus
@@ -71,7 +72,7 @@ tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
*
* opaque point <1..2^8-1>;
*/
-static PRUint32
+PRUint32
tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey)
{
/* Size = NamedGroup(2) + length(2) + opaque<?> share */
@@ -86,14 +87,14 @@ tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey)
return 0;
}
-static SECStatus
-tls13_EncodeKeyShareEntry(sslBuffer *buf, const sslEphemeralKeyPair *keyPair)
+SECStatus
+tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group,
+ SECKEYPublicKey *pubKey)
{
SECStatus rv;
- SECKEYPublicKey *pubKey = keyPair->keys->pubKey;
unsigned int size = tls13_SizeOfKeyShareEntry(pubKey);
- rv = sslBuffer_AppendNumber(buf, keyPair->group->name, 2);
+ rv = sslBuffer_AppendNumber(buf, group, 2);
if (rv != SECSuccess)
return rv;
rv = sslBuffer_AppendNumber(buf, size - 4, 2);
@@ -123,6 +124,7 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
{
SECStatus rv;
PRCList *cursor;
+ unsigned int extStart;
unsigned int lengthOffset;
if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
@@ -134,6 +136,8 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn",
SSL_GETPID(), ss->fd));
+ extStart = SSL_BUFFER_LEN(buf);
+
/* Save the offset to the length. */
rv = sslBuffer_Skip(buf, 2, &lengthOffset);
if (rv != SECSuccess) {
@@ -144,7 +148,9 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
cursor != &ss->ephemeralKeyPairs;
cursor = PR_NEXT_LINK(cursor)) {
sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor;
- rv = tls13_EncodeKeyShareEntry(buf, keyPair);
+ rv = tls13_EncodeKeyShareEntry(buf,
+ keyPair->group->name,
+ keyPair->keys->pubKey);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -154,50 +160,62 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECFailure;
}
+ rv = SECITEM_MakeItem(NULL, &xtnData->keyShareExtension,
+ SSL_BUFFER_BASE(buf) + extStart,
+ SSL_BUFFER_LEN(buf) - extStart);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
*added = PR_TRUE;
return SECSuccess;
}
-static SECStatus
-tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data)
+SECStatus
+tls13_DecodeKeyShareEntry(sslReader *rdr, TLS13KeyShareEntry **ksp)
{
SECStatus rv;
- PRUint32 group;
+ PRUint64 group;
const sslNamedGroupDef *groupDef;
TLS13KeyShareEntry *ks = NULL;
- SECItem share = { siBuffer, NULL, 0 };
+ sslReadBuffer share;
- rv = ssl3_ExtConsumeHandshakeNumber(ss, &group, 2, &data->data, &data->len);
+ rv = sslRead_ReadNumber(rdr, 2, &group);
if (rv != SECSuccess) {
- PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
goto loser;
}
groupDef = ssl_LookupNamedGroup(group);
- rv = ssl3_ExtConsumeHandshakeVariable(ss, &share, 2, &data->data,
- &data->len);
+ rv = sslRead_ReadVariable(rdr, 2, &share);
if (rv != SECSuccess) {
goto loser;
}
+
+ /* This has to happen here because we want to consume
+ * the entire entry even if the group is unknown
+ * or disabled. */
/* If the group is disabled, continue. */
if (!groupDef) {
return SECSuccess;
}
ks = PORT_ZNew(TLS13KeyShareEntry);
- if (!ks)
+ if (!ks) {
goto loser;
+ }
ks->group = groupDef;
- rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share);
- if (rv != SECSuccess)
+ rv = SECITEM_MakeItem(NULL, &ks->key_exchange,
+ share.buf, share.len);
+ if (rv != SECSuccess) {
goto loser;
+ }
- PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares);
+ *ksp = ks;
return SECSuccess;
loser:
- if (ks)
- tls13_DestroyKeyShareEntry(ks);
+ tls13_DestroyKeyShareEntry(ks);
+
return SECFailure;
}
/* Handle an incoming KeyShare extension at the client and copy to
@@ -209,6 +227,7 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
{
SECStatus rv;
PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
+ TLS13KeyShareEntry *ks = NULL;
PORT_Assert(!ss->sec.isServer);
@@ -221,16 +240,20 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension",
SSL_GETPID(), ss->fd));
- rv = tls13_HandleKeyShareEntry(ss, xtnData, data);
- if (rv != SECSuccess) {
+ sslReader rdr = SSL_READER(data->data, data->len);
+ rv = tls13_DecodeKeyShareEntry(&rdr, &ks);
+ if ((rv != SECSuccess) || !ks) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
return SECFailure;
}
- if (data->len) {
+ if (SSL_READER_REMAINING(&rdr)) {
+ tls13_DestroyKeyShareEntry(ks);
PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
return SECFailure;
}
+ PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares);
return SECSuccess;
}
@@ -273,7 +296,7 @@ tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData,
ssl_FreeEphemeralKeyPairs(CONST_CAST(sslSocket, ss));
/* And replace with our new share. */
- rv = tls13_CreateKeyShare(CONST_CAST(sslSocket, ss), group);
+ rv = tls13_AddKeyShare(CONST_CAST(sslSocket, ss), group);
if (rv != SECSuccess) {
ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
@@ -315,12 +338,24 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
goto loser;
}
- while (data->len) {
- rv = tls13_HandleKeyShareEntry(ss, xtnData, data);
- if (rv != SECSuccess)
+ sslReader rdr = SSL_READER(data->data, data->len);
+ while (SSL_READER_REMAINING(&rdr)) {
+ TLS13KeyShareEntry *ks = NULL;
+ rv = tls13_DecodeKeyShareEntry(&rdr, &ks);
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
goto loser;
+ }
+ if (ks) {
+ /* |ks| == NULL if this is an unknown group. */
+ PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares);
+ }
}
+ /* Keep track of negotiated extensions. */
+ xtnData->negotiated[xtnData->numNegotiated++] =
+ ssl_tls13_key_share_xtn;
+
return SECSuccess;
loser:
@@ -342,7 +377,8 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs);
- rv = tls13_EncodeKeyShareEntry(buf, keyPair);
+ rv = tls13_EncodeKeyShareEntry(buf, keyPair->group->name,
+ keyPair->keys->pubKey);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -396,6 +432,7 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
xtnData->lastXtnOffset = buf->len - 4;
PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
+ PORT_Assert(ss->sec.ci.sid->version >= SSL_LIBRARY_VERSION_TLS_1_3);
/* Send a single ticket identity. */
session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket;
@@ -751,7 +788,9 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
}
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
- rv = sslBuffer_AppendNumber(buf, tls13_EncodeDraftVersion(version), 2);
+ PRUint16 wire = tls13_EncodeDraftVersion(version,
+ ss->protocolVariant);
+ rv = sslBuffer_AppendNumber(buf, wire, 2);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -779,8 +818,9 @@ tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension",
SSL_GETPID(), ss->fd));
- rv = sslBuffer_AppendNumber(
- buf, tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2);
+ PRUint16 ver = tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3,
+ ss->protocolVariant);
+ rv = sslBuffer_AppendNumber(buf, ver, 2);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -1056,3 +1096,276 @@ tls13_ServerSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
*added = PR_TRUE;
return SECSuccess;
}
+
+SECStatus
+tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ SECStatus rv;
+ PRUint8 sniBuf[1024];
+ PRUint8 hash[64];
+ sslBuffer sni = SSL_BUFFER(sniBuf);
+ const ssl3CipherSuiteDef *suiteDef;
+ ssl3KeyMaterial keyMat;
+ SSLAEADCipher aead;
+ PRUint8 outBuf[1024];
+ int outLen;
+ unsigned int sniStart;
+ unsigned int sniLen;
+ sslBuffer aadInput = SSL_BUFFER_EMPTY;
+ unsigned int keyShareBufStart;
+ unsigned int keyShareBufLen;
+
+ PORT_Memset(&keyMat, 0, sizeof(keyMat));
+
+ if (!ss->xtnData.esniPrivateKey) {
+ return SECSuccess;
+ }
+
+ /* nonce */
+ rv = PK11_GenerateRandom(
+ (unsigned char *)xtnData->esniNonce, sizeof(xtnData->esniNonce));
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ rv = sslBuffer_Append(&sni, xtnData->esniNonce, sizeof(xtnData->esniNonce));
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* sni */
+ sniStart = SSL_BUFFER_LEN(&sni);
+ rv = ssl3_ClientFormatServerNameXtn(ss, ss->url, xtnData, &sni);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ sniLen = SSL_BUFFER_LEN(&sni) - sniStart;
+ /* Padding. */
+ if (ss->esniKeys->paddedLength > sniLen) {
+ unsigned int paddingRequired = ss->esniKeys->paddedLength - sniLen;
+ while (paddingRequired--) {
+ rv = sslBuffer_AppendNumber(&sni, 0, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ }
+
+ suiteDef = ssl_LookupCipherSuiteDef(xtnData->esniSuite);
+ PORT_Assert(suiteDef);
+ if (!suiteDef) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef));
+ if (!aead) {
+ return SECFailure;
+ }
+
+ /* Format the first part of the extension so we have the
+ * encoded KeyShareEntry. */
+ rv = sslBuffer_AppendNumber(buf, xtnData->esniSuite, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ keyShareBufStart = SSL_BUFFER_LEN(buf);
+ rv = tls13_EncodeKeyShareEntry(buf,
+ xtnData->esniPrivateKey->group->name,
+ xtnData->esniPrivateKey->keys->pubKey);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ keyShareBufLen = SSL_BUFFER_LEN(buf) - keyShareBufStart;
+
+ if (tls13_GetHashSizeForHash(suiteDef->prf_hash) > sizeof(hash)) {
+ PORT_Assert(PR_FALSE);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(suiteDef->prf_hash),
+ hash,
+ ss->esniKeys->data.data,
+ ss->esniKeys->data.len);
+ if (rv != SECSuccess) {
+ PORT_Assert(PR_FALSE);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(buf, hash,
+ tls13_GetHashSizeForHash(suiteDef->prf_hash), 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Compute the ESNI keys. */
+ rv = tls13_ComputeESNIKeys(ss, xtnData->peerEsniShare,
+ xtnData->esniPrivateKey->keys,
+ suiteDef,
+ hash,
+ SSL_BUFFER_BASE(buf) + keyShareBufStart,
+ keyShareBufLen,
+ CONST_CAST(PRUint8, ss->ssl3.hs.client_random),
+ &keyMat);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = tls13_FormatEsniAADInput(&aadInput,
+ xtnData->keyShareExtension.data,
+ xtnData->keyShareExtension.len);
+ if (rv != SECSuccess) {
+ ssl_DestroyKeyMaterial(&keyMat);
+ return SECFailure;
+ }
+ /* Now encrypt. */
+ rv = aead(&keyMat, PR_FALSE /* Encrypt */,
+ outBuf, &outLen, sizeof(outBuf),
+ SSL_BUFFER_BASE(&sni),
+ SSL_BUFFER_LEN(&sni),
+ SSL_BUFFER_BASE(&aadInput),
+ SSL_BUFFER_LEN(&aadInput));
+ ssl_DestroyKeyMaterial(&keyMat);
+ sslBuffer_Clear(&aadInput);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Encode the rest. */
+ rv = sslBuffer_AppendVariable(buf, outBuf, outLen, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ *added = PR_TRUE;
+ return SECSuccess;
+}
+
+static SECStatus
+tls13_ServerSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ SECStatus rv;
+
+ rv = sslBuffer_Append(buf, xtnData->esniNonce, sizeof(xtnData->esniNonce));
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ *added = PR_TRUE;
+ return SECSuccess;
+}
+
+SECStatus
+tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ SECItem *data)
+{
+ sslReadBuffer buf;
+ PRUint8 *plainText = NULL;
+ int ptLen;
+ SECStatus rv;
+
+ /* If we are doing < TLS 1.3, then ignore this. */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return SECSuccess;
+ }
+
+ if (!ss->esniKeys) {
+ /* Apparently we used to be configured for ESNI, but
+ * no longer. This violates the spec, or the client is
+ * broken. */
+ return SECFailure;
+ }
+
+ plainText = PORT_ZAlloc(data->len);
+ if (!plainText) {
+ return SECFailure;
+ }
+ rv = tls13_ServerDecryptEsniXtn(ss, data->data, data->len,
+ plainText, &ptLen, data->len);
+ if (rv) {
+ goto loser;
+ }
+
+ /* Read out the interior extension. */
+ sslReader sniRdr = SSL_READER(plainText, ptLen);
+
+ rv = sslRead_Read(&sniRdr, sizeof(xtnData->esniNonce), &buf);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_Memcpy(xtnData->esniNonce, buf.buf, sizeof(xtnData->esniNonce));
+
+ /* We need to capture the whole block with the length. */
+ SECItem sniItem = { siBuffer, (unsigned char *)SSL_READER_CURRENT(&sniRdr), 0 };
+ rv = sslRead_ReadVariable(&sniRdr, 2, &buf);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ sniItem.len = buf.len + 2;
+
+ /* Check the padding. Note we don't need to do this in constant time
+ * because it's inside the AEAD boundary. */
+ /* TODO(ekr@rtfm.com): check that the padding is the right length. */
+ PRUint64 tmp;
+ while (SSL_READER_REMAINING(&sniRdr)) {
+ rv = sslRead_ReadNumber(&sniRdr, 1, &tmp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (tmp != 0) {
+ goto loser;
+ }
+ }
+
+ rv = ssl3_HandleServerNameXtn(ss, xtnData, &sniItem);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = ssl3_RegisterExtensionSender(ss, xtnData,
+ ssl_tls13_encrypted_sni_xtn,
+ tls13_ServerSendEsniXtn);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Keep track of negotiated extensions. */
+ xtnData->negotiated[xtnData->numNegotiated++] =
+ ssl_tls13_encrypted_sni_xtn;
+
+ PORT_ZFree(plainText, data->len);
+ return SECSuccess;
+loser:
+ PORT_ZFree(plainText, data->len);
+ return SECFailure;
+}
+
+/* Function to check the extension. We don't install a handler here
+ * because we need to check for the presence of the extension as
+ * well and it's easier to do it in one place. */
+SECStatus
+tls13_ClientCheckEsniXtn(sslSocket *ss)
+{
+ TLSExtension *esniExtension =
+ ssl3_FindExtension(ss, ssl_tls13_encrypted_sni_xtn);
+ if (!esniExtension) {
+ FATAL_ERROR(ss, SSL_ERROR_MISSING_ESNI_EXTENSION, missing_extension);
+ return SECFailure;
+ }
+
+ if (esniExtension->data.len != sizeof(ss->xtnData.esniNonce)) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter);
+ return SECFailure;
+ }
+
+ if (0 != NSS_SecureMemcmp(esniExtension->data.data,
+ ss->xtnData.esniNonce,
+ sizeof(ss->xtnData.esniNonce))) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
diff --git a/security/nss/lib/ssl/tls13exthandle.h b/security/nss/lib/ssl/tls13exthandle.h
index edce94d83..dd64b44ff 100644
--- a/security/nss/lib/ssl/tls13exthandle.h
+++ b/security/nss/lib/ssl/tls13exthandle.h
@@ -84,5 +84,14 @@ SECStatus tls13_ServerSendHrrKeyShareXtn(const sslSocket *ss,
SECStatus tls13_ServerSendHrrCookieXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
+SECStatus tls13_DecodeKeyShareEntry(sslReader *rdr, TLS13KeyShareEntry **ksp);
+PRUint32 tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey);
+SECStatus tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group,
+ SECKEYPublicKey *pubKey);
+SECStatus tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added);
+SECStatus tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ SECItem *data);
+SECStatus tls13_ClientCheckEsniXtn(sslSocket *ss);
#endif
diff --git a/security/nss/lib/util/nssutil.def b/security/nss/lib/util/nssutil.def
index 26e438ba6..8c233f7d3 100644
--- a/security/nss/lib/util/nssutil.def
+++ b/security/nss/lib/util/nssutil.def
@@ -328,3 +328,9 @@ SECITEM_MakeItem;
;+ local:
;+ *;
;+};
+;+NSSUTIL_3.39 { # NSS Utilities 3.39 release
+;+ global:
+NSSUTIL_AddNSSFlagToModuleSpec;
+;+ local:
+;+ *;
+;+};
diff --git a/security/nss/lib/util/nssutil.h b/security/nss/lib/util/nssutil.h
index 2749abaa1..62511eafe 100644
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -19,9 +19,9 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
-#define NSSUTIL_VERSION "3.38"
+#define NSSUTIL_VERSION "3.41"
#define NSSUTIL_VMAJOR 3
-#define NSSUTIL_VMINOR 38
+#define NSSUTIL_VMINOR 41
#define NSSUTIL_VPATCH 0
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_FALSE
diff --git a/security/nss/lib/util/pkcs11p.h b/security/nss/lib/util/pkcs11p.h
index 2e904ee50..1c9201350 100644
--- a/security/nss/lib/util/pkcs11p.h
+++ b/security/nss/lib/util/pkcs11p.h
@@ -13,7 +13,10 @@
* though it's still needed. put in a central file to help merging..
*/
-#if defined(_WIN32)
+#if defined(_WIN32) || defined(_WINDOWS)
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wpragma-pack"
+#endif
#ifdef _MSC_VER
#pragma warning(disable : 4103)
#endif
diff --git a/security/nss/lib/util/pkcs11u.h b/security/nss/lib/util/pkcs11u.h
index be949bcd4..64ec2fdb5 100644
--- a/security/nss/lib/util/pkcs11u.h
+++ b/security/nss/lib/util/pkcs11u.h
@@ -11,7 +11,10 @@
* reset any packing set by pkcs11p.h
*/
-#if defined(_WIN32)
+#if defined(_WIN32) || defined(_WINDOWS)
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wpragma-pack"
+#endif
#ifdef _MSC_VER
#pragma warning(disable : 4103)
#endif
diff --git a/security/nss/lib/util/pkcs11uri.c b/security/nss/lib/util/pkcs11uri.c
index 94b00171e..c29521080 100644
--- a/security/nss/lib/util/pkcs11uri.c
+++ b/security/nss/lib/util/pkcs11uri.c
@@ -674,7 +674,7 @@ PK11URI_ParseURI(const char *string)
const char *p = string;
SECStatus ret;
- if (strncmp("pkcs11:", p, 7) != 0) {
+ if (PORT_Strncasecmp("pkcs11:", p, 7) != 0) {
return NULL;
}
p += 7;
diff --git a/security/nss/lib/util/pkcs1sig.c b/security/nss/lib/util/pkcs1sig.c
index 502119aa5..68588c7f8 100644
--- a/security/nss/lib/util/pkcs1sig.c
+++ b/security/nss/lib/util/pkcs1sig.c
@@ -15,13 +15,6 @@ struct pkcs1PrefixStr {
PRUint8 *data;
};
-typedef struct pkcs1PrefixesStr pkcs1Prefixes;
-struct pkcs1PrefixesStr {
- unsigned int digestLen;
- pkcs1Prefix prefixWithParams;
- pkcs1Prefix prefixWithoutParams;
-};
-
/* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on
* the possible prefix encodings as explained below.
*/
@@ -101,9 +94,8 @@ _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
PRBool unsafeAllowMissingParameters)
{
SECOidData *hashOid;
- pkcs1Prefixes pp;
- const pkcs1Prefix *expectedPrefix;
- SECStatus rv, rv2, rv3;
+ pkcs1Prefix prefix;
+ SECStatus rv;
if (!digest || !digest->data ||
!dataRecoveredFromSignature || !dataRecoveredFromSignature->data) {
@@ -117,17 +109,9 @@ _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
return SECFailure;
}
- pp.digestLen = digest->len;
- pp.prefixWithParams.data = NULL;
- pp.prefixWithoutParams.data = NULL;
+ prefix.data = NULL;
- rv2 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithParams, PR_TRUE);
- rv3 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithoutParams, PR_FALSE);
-
- rv = SECSuccess;
- if (rv2 != SECSuccess || rv3 != SECSuccess) {
- rv = SECFailure;
- }
+ rv = encodePrefix(hashOid, digest->len, &prefix, PR_TRUE);
if (rv == SECSuccess) {
/* We don't attempt to avoid timing attacks on these comparisons because
@@ -135,34 +119,39 @@ _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
* operation.
*/
- if (dataRecoveredFromSignature->len ==
- pp.prefixWithParams.len + pp.digestLen) {
- expectedPrefix = &pp.prefixWithParams;
- } else if (unsafeAllowMissingParameters &&
- dataRecoveredFromSignature->len ==
- pp.prefixWithoutParams.len + pp.digestLen) {
- expectedPrefix = &pp.prefixWithoutParams;
- } else {
- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
- rv = SECFailure;
+ if (dataRecoveredFromSignature->len != prefix.len + digest->len) {
+ PRBool lengthMismatch = PR_TRUE;
+#ifdef NSS_PKCS1_AllowMissingParameters
+ if (unsafeAllowMissingParameters) {
+ if (prefix.data) {
+ PORT_Free(prefix.data);
+ prefix.data = NULL;
+ }
+ rv = encodePrefix(hashOid, digest->len, &prefix, PR_FALSE);
+ if (rv != SECSuccess ||
+ dataRecoveredFromSignature->len == prefix.len + digest->len) {
+ lengthMismatch = PR_FALSE;
+ }
+ }
+#endif
+ if (lengthMismatch) {
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ rv = SECFailure;
+ }
}
}
if (rv == SECSuccess) {
- if (memcmp(dataRecoveredFromSignature->data, expectedPrefix->data,
- expectedPrefix->len) ||
- memcmp(dataRecoveredFromSignature->data + expectedPrefix->len,
- digest->data, digest->len)) {
+ if (memcmp(dataRecoveredFromSignature->data, prefix.data, prefix.len) ||
+ memcmp(dataRecoveredFromSignature->data + prefix.len, digest->data,
+ digest->len)) {
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
rv = SECFailure;
}
}
- if (pp.prefixWithParams.data) {
- PORT_Free(pp.prefixWithParams.data);
- }
- if (pp.prefixWithoutParams.data) {
- PORT_Free(pp.prefixWithoutParams.data);
+ if (prefix.data) {
+ PORT_Free(prefix.data);
}
return rv;
diff --git a/security/nss/lib/util/secder.h b/security/nss/lib/util/secder.h
index dbc35807d..1b487d193 100644
--- a/security/nss/lib/util/secder.h
+++ b/security/nss/lib/util/secder.h
@@ -34,6 +34,9 @@ SEC_BEGIN_PROTOS
extern SECStatus DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *t,
void *src);
+/*
+** This function is deprecated.
+*/
extern SECStatus DER_Lengths(SECItem *item, int *header_len_p,
PRUint32 *contents_len_p);
diff --git a/security/nss/lib/util/secitem.c b/security/nss/lib/util/secitem.c
index 1e505a9af..cd6996178 100644
--- a/security/nss/lib/util/secitem.c
+++ b/security/nss/lib/util/secitem.c
@@ -76,10 +76,10 @@ loser:
}
SECStatus
-SECITEM_MakeItem(PLArenaPool *arena, SECItem *dest, unsigned char *data,
+SECITEM_MakeItem(PLArenaPool *arena, SECItem *dest, const unsigned char *data,
unsigned int len)
{
- SECItem it = { siBuffer, data, len };
+ SECItem it = { siBuffer, (unsigned char *)data, len };
return SECITEM_CopyItem(arena, dest, &it);
}
diff --git a/security/nss/lib/util/secitem.h b/security/nss/lib/util/secitem.h
index 4fb123938..f7a8241b5 100644
--- a/security/nss/lib/util/secitem.h
+++ b/security/nss/lib/util/secitem.h
@@ -41,7 +41,7 @@ extern SECItem *SECITEM_AllocItem(PLArenaPool *arena, SECItem *item,
* always siBuffer.
*/
extern SECStatus SECITEM_MakeItem(PLArenaPool *arena, SECItem *dest,
- unsigned char *data, unsigned int len);
+ const unsigned char *data, unsigned int len);
/*
** This is a legacy function containing bugs. It doesn't update item->len,
diff --git a/security/nss/lib/util/secoid.c b/security/nss/lib/util/secoid.c
index a05621c59..06b0cbcc4 100644
--- a/security/nss/lib/util/secoid.c
+++ b/security/nss/lib/util/secoid.c
@@ -122,7 +122,9 @@ const char __nss_util_version[] = "Version: NSS " NSSUTIL_VERSION _DEBUG_STRING;
#define VERISIGN 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45
-#define PKIX 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07
+#define INTERNET_SECURITY_MECH 0x2b, 0x06, 0x01, 0x05, 0x05
+
+#define PKIX INTERNET_SECURITY_MECH, 0x07
#define PKIX_CERT_EXTENSIONS PKIX, 1
#define PKIX_POLICY_QUALIFIERS PKIX, 2
#define PKIX_KEY_USAGE PKIX, 3
@@ -360,6 +362,7 @@ CONST_OID x509FreshestCRL[] = { ID_CE_OID, 46 };
CONST_OID x509InhibitAnyPolicy[] = { ID_CE_OID, 54 };
CONST_OID x509CertificatePoliciesAnyPolicy[] = { ID_CE_OID, 32, 0 };
+CONST_OID x509ExtKeyUsageAnyUsage[] = { ID_CE_OID, 37, 0 };
CONST_OID x509AuthInfoAccess[] = { PKIX_CERT_EXTENSIONS, 1 };
CONST_OID x509SubjectInfoAccess[] = { PKIX_CERT_EXTENSIONS, 11 };
@@ -454,8 +457,13 @@ CONST_OID pkixExtendedKeyUsageCodeSign[] = { PKIX_KEY_USAGE, 3 };
CONST_OID pkixExtendedKeyUsageEMailProtect[] = { PKIX_KEY_USAGE, 4 };
CONST_OID pkixExtendedKeyUsageTimeStamp[] = { PKIX_KEY_USAGE, 8 };
CONST_OID pkixOCSPResponderExtendedKeyUsage[] = { PKIX_KEY_USAGE, 9 };
+/* 17 replaces 5 + 6 + 7 (declared obsolete in RFC 4945) */
+CONST_OID pkixExtendedKeyUsageIPsecIKE[] = { PKIX_KEY_USAGE, 17 };
CONST_OID msExtendedKeyUsageTrustListSigning[] = { MS_CRYPTO_EKU, 1 };
+CONST_OID ipsecIKEEnd[] = { INTERNET_SECURITY_MECH, 0x08, 0x02, 0x01 };
+CONST_OID ipsecIKEIntermediate[] = { INTERNET_SECURITY_MECH, 0x08, 0x02, 0x02 };
+
/* OIDs for Netscape defined algorithms */
CONST_OID netscapeSMimeKEA[] = { NETSCAPE_ALGS, 0x01 };
@@ -1754,6 +1762,22 @@ const static SECOidData oids[SEC_OID_TOTAL] = {
"Curve25519", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
ODE(SEC_OID_TLS13_KEA_ANY,
"TLS 1.3 fake key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+
+ OD(x509ExtKeyUsageAnyUsage, SEC_OID_X509_ANY_EXT_KEY_USAGE,
+ "Any Extended Key Usage",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD(pkixExtendedKeyUsageIPsecIKE,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_IKE,
+ "IPsec IKE Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD(ipsecIKEEnd,
+ SEC_OID_IPSEC_IKE_END,
+ "IPsec IKE End",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD(ipsecIKEIntermediate,
+ SEC_OID_IPSEC_IKE_INTERMEDIATE,
+ "IPsec IKE Intermediate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
};
/* PRIVATE EXTENDED SECOID Table
diff --git a/security/nss/lib/util/secoidt.h b/security/nss/lib/util/secoidt.h
index 0a40f29fd..c77aeb19f 100644
--- a/security/nss/lib/util/secoidt.h
+++ b/security/nss/lib/util/secoidt.h
@@ -494,6 +494,11 @@ typedef enum {
SEC_OID_TLS13_KEA_ANY = 356,
+ SEC_OID_X509_ANY_EXT_KEY_USAGE = 357,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_IKE = 358,
+ SEC_OID_IPSEC_IKE_END = 359,
+ SEC_OID_IPSEC_IKE_INTERMEDIATE = 360,
+
SEC_OID_TOTAL
} SECOidTag;
diff --git a/security/nss/lib/util/secport.c b/security/nss/lib/util/secport.c
index e5bd4c1bb..ae979ebad 100644
--- a/security/nss/lib/util/secport.c
+++ b/security/nss/lib/util/secport.c
@@ -199,9 +199,6 @@ PORT_Strdup(const char *str)
void
PORT_SetError(int value)
{
-#ifdef DEBUG_jp96085
- PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
-#endif
PR_SetError(value, 0);
return;
}
diff --git a/security/nss/lib/util/utilpars.c b/security/nss/lib/util/utilpars.c
index e7435bfcc..f9b807f7e 100644
--- a/security/nss/lib/util/utilpars.c
+++ b/security/nss/lib/util/utilpars.c
@@ -913,6 +913,92 @@ NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters,
return NSSUTIL_MkModuleSpecEx(dllName, commonName, parameters, NSS, NULL);
}
+/************************************************************************
+ * add a single flag to the Flags= section inside the spec's NSS= section */
+char *
+NSSUTIL_AddNSSFlagToModuleSpec(char *spec, char *addFlag)
+{
+ const char *prefix = "flags=";
+ const size_t prefixLen = strlen(prefix);
+ char *lib = NULL, *name = NULL, *param = NULL, *nss = NULL, *conf = NULL;
+ char *nss2 = NULL, *result = NULL;
+ SECStatus rv;
+
+ rv = NSSUTIL_ArgParseModuleSpecEx(spec, &lib, &name, &param, &nss, &conf);
+ if (rv != SECSuccess) {
+ return NULL;
+ }
+
+ if (nss && NSSUTIL_ArgHasFlag("flags", addFlag, nss)) {
+ /* It's already there, nothing to do! */
+ PORT_Free(lib);
+ PORT_Free(name);
+ PORT_Free(param);
+ PORT_Free(nss);
+ PORT_Free(conf);
+ return PORT_Strdup(spec);
+ }
+
+ if (!nss || !strlen(nss)) {
+ nss2 = PORT_Alloc(prefixLen + strlen(addFlag) + 1);
+ PORT_Strcpy(nss2, prefix);
+ PORT_Strcat(nss2, addFlag);
+ } else {
+ const char *iNss = nss;
+ PRBool alreadyAdded = PR_FALSE;
+ size_t maxSize = strlen(nss) + strlen(addFlag) + prefixLen + 2; /* space and null terminator */
+ nss2 = PORT_Alloc(maxSize);
+ *nss2 = 0;
+ while (*iNss) {
+ iNss = NSSUTIL_ArgStrip(iNss);
+ if (PORT_Strncasecmp(iNss, prefix, prefixLen) == 0) {
+ /* We found an existing Flags= section. */
+ char *oldFlags;
+ const char *valPtr;
+ int valSize;
+ valPtr = iNss + prefixLen;
+ oldFlags = NSSUTIL_ArgFetchValue(valPtr, &valSize);
+ iNss = valPtr + valSize;
+ PORT_Strcat(nss2, prefix);
+ PORT_Strcat(nss2, oldFlags);
+ PORT_Strcat(nss2, ",");
+ PORT_Strcat(nss2, addFlag);
+ PORT_Strcat(nss2, " ");
+ PORT_Free(oldFlags);
+ alreadyAdded = PR_TRUE;
+ iNss = NSSUTIL_ArgStrip(iNss);
+ PORT_Strcat(nss2, iNss); /* remainder of input */
+ break;
+ } else {
+ /* Append this other name=value pair and continue. */
+ const char *startOfNext = NSSUTIL_ArgSkipParameter(iNss);
+ PORT_Strncat(nss2, iNss, (startOfNext - iNss));
+ if (nss2[strlen(nss2) - 1] != ' ') {
+ PORT_Strcat(nss2, " ");
+ }
+ iNss = startOfNext;
+ }
+ iNss = NSSUTIL_ArgStrip(iNss);
+ }
+ if (!alreadyAdded) {
+ /* nss wasn't empty, and it didn't contain a Flags section. We can
+ * assume that other content from nss has already been added to
+ * nss2, which means we already have a trailing space separator. */
+ PORT_Strcat(nss2, prefix);
+ PORT_Strcat(nss2, addFlag);
+ }
+ }
+
+ result = NSSUTIL_MkModuleSpecEx(lib, name, param, nss2, conf);
+ PORT_Free(lib);
+ PORT_Free(name);
+ PORT_Free(param);
+ PORT_Free(nss);
+ PORT_Free(nss2);
+ PORT_Free(conf);
+ return result;
+}
+
#define NSSUTIL_ARG_FORTEZZA_FLAG "FORTEZZA"
/******************************************************************************
* Parse the cipher flags from the NSS parameter
diff --git a/security/nss/lib/util/utilpars.h b/security/nss/lib/util/utilpars.h
index 1b0b1ff1c..289fdca97 100644
--- a/security/nss/lib/util/utilpars.h
+++ b/security/nss/lib/util/utilpars.h
@@ -46,6 +46,7 @@ char *NSSUTIL_MkModuleSpec(char *dllName, char *commonName,
char *parameters, char *NSS);
char *NSSUTIL_MkModuleSpecEx(char *dllName, char *commonName,
char *parameters, char *NSS, char *config);
+char *NSSUTIL_AddNSSFlagToModuleSpec(char *spec, char *addFlag);
void NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers,
const char *cipherList);
char *NSSUTIL_MkNSSString(char **slotStrings, int slotCount, PRBool internal,