Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
# Bug 1252891 Implement certUsageIPSec as defined in RFC 4945
Patch by Kai
r=rrelyea
  • Loading branch information
rjrelyea committed Nov 9, 2018
1 parent 7d6ed6e commit 90ecf50
Show file tree
Hide file tree
Showing 16 changed files with 245 additions and 9 deletions.
4 changes: 4 additions & 0 deletions cmd/certutil/certutil.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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", "");
Expand Down
3 changes: 2 additions & 1 deletion cmd/dbck/dbrecover.c
Expand Up @@ -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) &&
Expand Down
5 changes: 5 additions & 0 deletions cmd/ocspclnt/ocspclnt.c
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions cmd/p7verify/p7verify.c
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions cmd/smimetools/cmsutil.c
Expand Up @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/vfychain/vfychain.c
Expand Up @@ -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"
Expand Down
77 changes: 77 additions & 0 deletions lib/certdb/certdb.c
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions lib/certdb/certi.h
Expand Up @@ -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);

Expand Down
6 changes: 4 additions & 2 deletions lib/certdb/certt.h
Expand Up @@ -447,7 +447,8 @@ typedef enum SECCertUsageEnum {
certUsageVerifyCA = 8,
certUsageProtectedObjectSigner = 9,
certUsageStatusResponder = 10,
certUsageAnyCA = 11
certUsageAnyCA = 11,
certUsageIPsec = 12
} SECCertUsage;

typedef PRInt64 SECCertificateUsage;
Expand All @@ -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.
Expand Down
32 changes: 29 additions & 3 deletions lib/certhigh/certvfy.c
Expand Up @@ -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;
Expand Down Expand Up @@ -579,6 +583,7 @@ cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert,
switch (certUsage) {
case certUsageSSLClient:
case certUsageSSLServer:
case certUsageIPsec:
case certUsageSSLCA:
case certUsageSSLServerWithStepUp:
case certUsageEmailSigner:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -986,6 +992,7 @@ CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert,
switch (certUsage) {
case certUsageSSLClient:
case certUsageSSLServer:
case certUsageIPsec:
case certUsageSSLCA:
case certUsageSSLServerWithStepUp:
case certUsageEmailSigner:
Expand Down Expand Up @@ -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 ? */
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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);
Expand Down Expand Up @@ -1408,7 +1419,19 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
LOG_ERROR(log, cert, 0, requiredKeyUsage);
INVALID_USAGE();
}
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);
}
Expand Down Expand Up @@ -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);
Expand All @@ -1521,6 +1545,7 @@ cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert,
case certUsageSSLClient:
case certUsageSSLServer:
case certUsageSSLServerWithStepUp:
case certUsageIPsec:
case certUsageSSLCA:
case certUsageEmailSigner:
case certUsageEmailRecipient:
Expand Down Expand Up @@ -1633,6 +1658,7 @@ CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
* certUsageSSLClient
* certUsageSSLServer
* certUsageSSLServerWithStepUp
* certUsageIPsec
* certUsageEmailSigner
* certUsageEmailRecipient
* certUsageObjectSigner
Expand Down
12 changes: 11 additions & 1 deletion lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
Expand Up @@ -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);
Expand Down Expand Up @@ -3001,9 +3002,18 @@ PKIX_PL_Cert_VerifyCertAndKeyType(
if (CERT_CheckKeyUsage(cert->nssCert, requiredKeyUsage) != SECSuccess) {
PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED);
}
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);
PKIX_RETURN(CERT);
Expand Down

0 comments on commit 90ecf50

Please sign in to comment.