Commit 90ecf505 authored by Robert Relyea's avatar Robert Relyea

# Bug 1252891 Implement certUsageIPSec as defined in RFC 4945

Patch by Kai
r=rrelyea
parent 7d6ed6e7
......@@ -741,6 +741,9 @@ ValidateCert(CERTCertDBHandle *handle, char *name, char *date,
case 'V':
usage = certificateUsageSSLServer;
break;
case 'I':
usage = certificateUsageIPsec;
break;
case 'S':
usage = certificateUsageEmailSigner;
break;
......@@ -1706,6 +1709,7 @@ luV(enum usage_level ul, const char *command)
FPS "%-20s Specify certificate usage:\n", " -u certusage");
FPS "%-25s C \t SSL Client\n", "");
FPS "%-25s V \t SSL Server\n", "");
FPS "%-25s I \t IPsec\n", "");
FPS "%-25s L \t SSL CA\n", "");
FPS "%-25s A \t Any CA\n", "");
FPS "%-25s Y \t Verify CA\n", "");
......
......@@ -288,7 +288,8 @@ addCertToDB(certDBEntryCert *certEntry, dbRestoreInfo *info,
/* If user chooses so, ignore expired certificates. */
allowOverride = (PRBool)((oldCert->keyUsage == certUsageSSLServer) ||
(oldCert->keyUsage == certUsageSSLServerWithStepUp));
(oldCert->keyUsage == certUsageSSLServerWithStepUp) ||
(oldCert->keyUsage == certUsageIPsec));
validity = CERT_CheckCertValidTimes(oldCert, PR_Now(), allowOverride);
/* If cert expired and user wants to delete it, ignore it. */
if ((validity != secCertTimeValid) &&
......
......@@ -133,6 +133,8 @@ long_usage(char *progname)
"%-17s c SSL Client\n", "");
PR_fprintf(pr_stderr,
"%-17s s SSL Server\n", "");
PR_fprintf(pr_stderr,
"%-17s I IPsec\n", "");
PR_fprintf(pr_stderr,
"%-17s e Email Recipient\n", "");
PR_fprintf(pr_stderr,
......@@ -908,6 +910,9 @@ cert_usage_from_char(const char *cert_usage_str, SECCertUsage *cert_usage)
case 's':
*cert_usage = certUsageSSLServer;
break;
case 'I':
*cert_usage = certUsageIPsec;
break;
case 'e':
*cert_usage = certUsageEmailRecipient;
break;
......
......@@ -117,6 +117,7 @@ Usage(char *progName)
fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " ");
fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " ");
fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " ");
fprintf(stderr, "%-25s 12 - certUsageIPsec\n", " ");
exit(-1);
}
......
......@@ -115,6 +115,7 @@ Usage(void)
fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " ");
fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " ");
fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " ");
fprintf(stderr, "%-25s 12 - certUsageIPsec\n", " ");
exit(-1);
}
......
......@@ -64,7 +64,8 @@ Usage(const char *progName)
"\t-t\t\t Following cert is explicitly trusted (overrides db trust).\n"
"\t-u usage \t 0=SSL client, 1=SSL server, 2=SSL StepUp, 3=SSL CA,\n"
"\t\t\t 4=Email signer, 5=Email recipient, 6=Object signer,\n"
"\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA\n"
"\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA,\n"
"\t\t\t 12=IPsec\n"
"\t-T\t\t Trust both explicit trust anchors (-t) and the database.\n"
"\t\t\t (Default is to only trust certificates marked -t, if there are any,\n"
"\t\t\t or to trust the database if there are certificates marked -t.)\n"
......
......@@ -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;
......
......@@ -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);
......
......@@ -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.
......
......@@ -289,6 +289,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 +583,7 @@ cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert,
switch (certUsage) {
case certUsageSSLClient:
case certUsageSSLServer:
case certUsageIPsec:
case certUsageSSLCA:
case certUsageSSLServerWithStepUp:
case certUsageEmailSigner:
......@@ -645,7 +650,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 +992,7 @@ CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
switch (certUsage) {
case certUsageSSLClient:
case certUsageSSLServer:
case certUsageIPsec:
case certUsageSSLCA:
case certUsageSSLServerWithStepUp:
case certUsageEmailSigner:
......@@ -1171,6 +1178,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 +1355,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 +1369,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 +1386,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 +1419,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 +1531,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 +1545,7 @@ cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert,
case certUsageSSLClient:
case certUsageSSLServer:
case certUsageSSLServerWithStepUp:
case certUsageIPsec:
case certUsageSSLCA:
case certUsageEmailSigner:
case certUsageEmailRecipient:
......@@ -1633,6 +1658,7 @@ CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
* certUsageSSLClient
* certUsageSSLServer
* certUsageSSLServerWithStepUp
* certUsageIPsec
* certUsageEmailSigner
* certUsageEmailRecipient
* certUsageObjectSigner
......
......@@ -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);
......
......@@ -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
......
......@@ -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;
......
......@@ -351,6 +351,12 @@ create_cert_req()
EXT_DATA="y
-1
y
"
else
CA_FLAG="-2"
EXT_DATA="n
-1
y
"
fi
......@@ -1258,6 +1264,12 @@ process_scenario()
rm ${AIA_FILES}
}
# process ipsec.cfg separately
chains_ipsec()
{
process_scenario "ipsec.cfg"
}
# process ocspd.cfg separately
chains_ocspd()
{
......@@ -1279,6 +1291,7 @@ chains_main()
do
[ `echo ${LINE} | cut -b 1` != "#" ] || continue
[ ${LINE} != 'ipsec.cfg' ] || continue
[ ${LINE} != 'ocspd.cfg' ] || continue
[ ${LINE} != 'method.cfg' ] || continue
......@@ -1292,6 +1305,7 @@ chains_init
VERIFY_CLASSIC_ENGINE_TOO=
chains_ocspd
VERIFY_CLASSIC_ENGINE_TOO=1
chains_ipsec
chains_run_httpserv get
chains_method
chains_stop_httpserv
......
# 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/.
scenario IPsec
entity Root
type Root
entity CA1
type Intermediate
issuer Root
entity NoKU
type EE
issuer CA1
entity DigSig
type EE
issuer CA1
ku digitalSignature
entity NonRep
type EE
issuer CA1
ku nonRepudiation
entity DigSigNonRepAndExtra
type EE
issuer CA1
ku digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
entity NoMatch
type EE
issuer CA1
ku keyEncipherment,dataEncipherment,keyAgreement
db All
import Root::C,,
import CA1:Root:
verify NoKU:CA1
usage 12
result pass
verify DigSig:CA1
usage 12
result pass
verify NonRep:CA1
usage 12
result pass
verify DigSigNonRepAndExtra:CA1
usage 12
result pass
verify NoMatch:CA1
usage 12
result fail
......@@ -22,3 +22,4 @@ ocsp.cfg
crldp.cfg
trustanchors.cfg
nameconstraints.cfg
ipsec.cfg
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment