Fixes and cleanups for processing peer certificates:

* Fix with `WOLFSSL_ALT_CERT_CHAINS` to resolve issue with using a trusted intermediate to validate a partial chain. With the alt cert chain enabled a CA may fail with only `ASN_NO_SIGNER_E` and the connection is allowed if the peer's certificate validates to a trusted CA. Eliminates overly complex 1 deep error alternate chain detection logic. Resolves ZD 4525.
* Refactor and cleanup of ProcessPeerPerts to combine duplicate code and improve code commenting.
* Fix for CA path len check in `ParseCertRelative` to always check for self-signed case (was previously only in NO_SKID case).
* Improvement to include self-signed flag in the DecodedCert struct.
This commit is contained in:
David Garske
2018-12-21 08:20:04 -08:00
parent 3e31115654
commit 9733076fe0
3 changed files with 325 additions and 423 deletions

View File

@@ -30,7 +30,13 @@
/* /*
* WOLFSSL_SMALL_CERT_VERIFY: * WOLFSSL_SMALL_CERT_VERIFY:
* Verify the certificate signature without using DecodedCert. Doubles up * Verify the certificate signature without using DecodedCert. Doubles up
* on some code but allows smaller dynamic memory usage. * on some code but allows smaller peak heap memory usage.
* Cannot be used with WOLFSSL_NONBLOCK_OCSP.
* WOLFSSL_ALT_CERT_CHAINS:
* Allows CA's to be presented by peer, but not part of a valid chain.
* Default wolfSSL behavior is to require validation of all presented peer
* certificates. This also allows loading intermediate CA's as trusted
* and ignoring no signer failures for CA's up the chain to root.
*/ */
#ifndef WOLFCRYPT_ONLY #ifndef WOLFCRYPT_ONLY
@@ -8546,13 +8552,10 @@ typedef struct ProcPeerCertArgs {
int count; int count;
int certIdx; int certIdx;
int lastErr; int lastErr;
#ifdef WOLFSSL_ALT_CERT_CHAINS
int lastCaErr;
#endif
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
byte ctxSz; byte ctxSz;
#endif #endif
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) #ifdef OPENSSL_EXTRA
char untrustedDepth; char untrustedDepth;
#endif #endif
word16 fatal:1; word16 fatal:1;
@@ -8779,10 +8782,187 @@ static void FreeProcPeerCertArgs(WOLFSSL* ssl, void* pArgs)
} }
} }
static int ProcessPeerCertParse(WOLFSSL* ssl, ProcPeerCertArgs* args,
int certType, int verify, byte** pSubjectHash, int* pAlreadySigner)
{
int ret = 0;
buffer* cert;
byte* subjectHash = NULL;
int alreadySigner = 0;
#ifdef WOLFSSL_SMALL_CERT_VERIFY
int sigRet = 0;
#endif
if (ssl == NULL || args == NULL)
return BAD_FUNC_ARG;
/* check to make sure certificate index is valid */
if (args->certIdx > args->count)
return BUFFER_E;
/* check if returning from non-blocking OCSP */
/* skip this section because cert is already initialized and parsed */
#ifdef WOLFSSL_NONBLOCK_OCSP
if (args->lastErr == OCSP_WANT_READ) {
args->lastErr = 0; /* clear error */
return 0;
}
#endif
#ifdef WOLFSSL_TRUST_PEER_CERT
/* we have trusted peer */
if (args->haveTrustPeer) {
return 0;
}
#endif
/* get certificate buffer */
cert = &args->certs[args->certIdx];
#ifdef WOLFSSL_SMALL_CERT_VERIFY
if (verify == VERIFY) {
/* for small cert verify, release decoded cert during signature check to
reduce peak memory usage */
if (args->dCert != NULL) {
if (args->dCertInit) {
FreeDecodedCert(args->dCert);
args->dCertInit = 0;
}
XFREE(args->dCert, ssl->heap, DYNAMIC_TYPE_DCERT);
args->dCert = NULL;
}
/* perform cert parsing and signature check */
sigRet = CheckCertSignature(cert->buffer, cert->length,
ssl->heap, ssl->ctx->cm);
/* fail on errors here after the ParseCertRelative call, so dCert is populated */
/* verify name only in ParseCertRelative below, signature check done */
verify = VERIFY_NAME;
}
#endif /* WOLFSSL_SMALL_CERT_VERIFY */
/* make sure the decoded cert structure is allocated and initialized */
if (!args->dCertInit) {
#ifdef WOLFSSL_SMALL_CERT_VERIFY
if (args->dCert == NULL) {
args->dCert = (DecodedCert*)XMALLOC(
sizeof(DecodedCert), ssl->heap,
DYNAMIC_TYPE_DCERT);
if (args->dCert == NULL) {
return MEMORY_E;
}
}
#endif
InitDecodedCert(args->dCert, cert->buffer, cert->length, ssl->heap);
args->dCertInit = 1;
args->dCert->sigCtx.devId = ssl->devId;
#ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl;
#endif
#ifdef HAVE_PK_CALLBACKS
/* setup the PK callback context */
ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
if (ret != 0)
return ret;
#endif
}
/* Parse Certificate */
ret = ParseCertRelative(args->dCert, certType, verify, ssl->ctx->cm);
if (ret == 0) {
/* get subject and determine if already loaded */
#ifndef NO_SKID
if (args->dCert->extAuthKeyIdSet)
subjectHash = args->dCert->extSubjKeyId;
else
#endif
subjectHash = args->dCert->subjectHash;
alreadySigner = AlreadySigner(ssl->ctx->cm, subjectHash);
}
#ifdef WOLFSSL_SMALL_CERT_VERIFY
/* get signature check failures from above */
if (ret == 0)
ret = sigRet;
#endif
if (pSubjectHash)
*pSubjectHash = subjectHash;
if (pAlreadySigner)
*pAlreadySigner = alreadySigner;
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_PENDING_E) {
ret = wolfSSL_AsyncPush(ssl,
args->dCert->sigCtx.asyncDev);
}
#endif
return ret;
}
/* Check key sizes for certs. Is redundant check since
ProcessBuffer also performs this check. */
static int ProcessPeerCertCheckKey(WOLFSSL* ssl, ProcPeerCertArgs* args)
{
int ret = 0;
if (ssl->options.verifyNone) {
return ret;
}
switch (args->dCert->keyOID) {
#ifndef NO_RSA
case RSAk:
if (ssl->options.minRsaKeySz < 0 ||
args->dCert->pubKeySize <
(word16)ssl->options.minRsaKeySz) {
WOLFSSL_MSG(
"RSA key size in cert chain error");
ret = RSA_KEY_SIZE_E;
}
break;
#endif /* !NO_RSA */
#ifdef HAVE_ECC
case ECDSAk:
if (ssl->options.minEccKeySz < 0 ||
args->dCert->pubKeySize <
(word16)ssl->options.minEccKeySz) {
WOLFSSL_MSG(
"ECC key size in cert chain error");
ret = ECC_KEY_SIZE_E;
}
break;
#endif /* HAVE_ECC */
#ifdef HAVE_ED25519
case ED25519k:
if (ssl->options.minEccKeySz < 0 ||
ED25519_KEY_SIZE <
(word16)ssl->options.minEccKeySz) {
WOLFSSL_MSG(
"ECC key size in cert chain error");
ret = ECC_KEY_SIZE_E;
}
break;
#endif /* HAVE_ED25519 */
default:
WOLFSSL_MSG("Key size not checked");
/* key not being checked for size if not in
switch */
break;
}
return ret;
}
int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
word32 totalSz) word32 totalSz)
{ {
int ret = 0, sigRet = 0; int ret = 0;
#ifdef WOLFSSL_ASYNC_CRYPT #ifdef WOLFSSL_ASYNC_CRYPT
ProcPeerCertArgs* args = (ProcPeerCertArgs*)ssl->async.args; ProcPeerCertArgs* args = (ProcPeerCertArgs*)ssl->async.args;
typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1];
@@ -8794,11 +8974,8 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#else #else
ProcPeerCertArgs args[1]; ProcPeerCertArgs args[1];
#endif #endif
byte* subjectHash = NULL;
buffer* cert; int alreadySigner = 0;
#ifdef WOLFSSL_TRUST_PEER_CERT
byte haveTrustPeer = 0; /* was cert verified by loaded trusted peer cert */
#endif
WOLFSSL_ENTER("ProcessPeerCerts"); WOLFSSL_ENTER("ProcessPeerCerts");
@@ -8931,6 +9108,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
} }
XMEMSET(args->certs, 0, sizeof(buffer) * MAX_CHAIN_DEPTH); XMEMSET(args->certs, 0, sizeof(buffer) * MAX_CHAIN_DEPTH);
#endif /* OPENSSL_EXTRA */ #endif /* OPENSSL_EXTRA */
/* Certificate List */ /* Certificate List */
if ((args->idx - args->begin) + OPAQUE24_LEN > totalSz) { if ((args->idx - args->begin) + OPAQUE24_LEN > totalSz) {
ERROR_OUT(BUFFER_ERROR, exit_ppc); ERROR_OUT(BUFFER_ERROR, exit_ppc);
@@ -9012,7 +9190,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
} /* while (listSz) */ } /* while (listSz) */
args->count = args->totalCerts; args->count = args->totalCerts;
args->certIdx = 0; args->certIdx = 0; /* select peer cert (first one) */
args->dCertInit = 0; args->dCertInit = 0;
#ifndef WOLFSSL_SMALL_CERT_VERIFY #ifndef WOLFSSL_SMALL_CERT_VERIFY
@@ -9031,343 +9209,129 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
case TLS_ASYNC_BUILD: case TLS_ASYNC_BUILD:
{ {
if (args->count > 0) { if (args->count > 0) {
#ifdef WOLFSSL_TRUST_PEER_CERT
/* check for trusted peer and get untrustedDepth */
#if defined(WOLFSSL_TRUST_PEER_CERT) || defined(OPENSSL_EXTRA)
if (args->certIdx == 0) { if (args->certIdx == 0) {
/* if using trusted peer certs check before verify chain #ifdef WOLFSSL_TRUST_PEER_CERT
and CA test */
TrustedPeerCert* tp; TrustedPeerCert* tp;
int matchType = WC_MATCH_NAME;
cert = &args->certs[args->certIdx];
if (!args->dCertInit) {
#ifdef WOLFSSL_SMALL_CERT_VERIFY
if (args->dCert == NULL) {
args->dCert = (DecodedCert*)XMALLOC(
sizeof(DecodedCert), ssl->heap,
DYNAMIC_TYPE_DCERT);
if (args->dCert == NULL) {
ERROR_OUT(MEMORY_E, exit_ppc);
}
}
#endif #endif
InitDecodedCert(args->dCert, ret = ProcessPeerCertParse(ssl, args, CERT_TYPE, NO_VERIFY,
cert->buffer, cert->length, ssl->heap); &subjectHash, &alreadySigner);
args->dCert->sigCtx.devId = ssl->devId; /* setup async dev */
#ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl;
#endif
args->dCertInit = 1;
#ifdef HAVE_PK_CALLBACKS
ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
if (ret != 0)
goto exit_ppc;
#endif
}
ret = ParseCertRelative(args->dCert, CERT_TYPE, 0,
ssl->ctx->cm);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_PENDING_E) {
ret = wolfSSL_AsyncPush(ssl,
args->dCert->sigCtx.asyncDev);
goto exit_ppc;
}
#endif
if (ret != 0) if (ret != 0)
goto exit_ppc; goto exit_ppc;
#ifdef OPENSSL_EXTRA
/* Determine untrusted depth */
if (!alreadySigner) {
args->untrustedDepth = 1;
}
#endif
#ifdef WOLFSSL_TRUST_PEER_CERT
#ifndef NO_SKID #ifndef NO_SKID
if (args->dCert->extAuthKeyIdSet) { if (args->dCert->extAuthKeyIdSet)
tp = GetTrustedPeer(ssl->ctx->cm, matchType = WC_MATCH_SKID;
args->dCert->extSubjKeyId, WC_MATCH_SKID); #endif
} tp = GetTrustedPeer(ssl->ctx->cm, subjectHash, matchType);
else { /* if the cert has no SKID try to match by name */
tp = GetTrustedPeer(ssl->ctx->cm,
args->dCert->subjectHash, WC_MATCH_NAME);
}
#else /* NO_SKID */
tp = GetTrustedPeer(ssl->ctx->cm, args->dCert->subjectHash,
WC_MATCH_NAME);
#endif /* NO SKID */
WOLFSSL_MSG("Checking for trusted peer cert"); WOLFSSL_MSG("Checking for trusted peer cert");
if (tp == NULL) { if (tp && MatchTrustedPeer(tp, args->dCert)) {
/* no trusted peer cert */
WOLFSSL_MSG("No matching trusted peer cert. "
"Checking CAs");
FreeDecodedCert(args->dCert);
args->dCertInit = 0;
#ifdef OPENSSL_EXTRA
args->untrustedDepth = 1;
#endif
} else if (MatchTrustedPeer(tp, args->dCert)){
WOLFSSL_MSG("Found matching trusted peer cert"); WOLFSSL_MSG("Found matching trusted peer cert");
haveTrustPeer = 1; args->haveTrustPeer = 1;
} else { }
else if (tp == NULL) {
/* no trusted peer cert */
WOLFSSL_MSG("No matching trusted peer cert. Checking CAs");
}
else {
WOLFSSL_MSG("Trusted peer cert did not match!"); WOLFSSL_MSG("Trusted peer cert did not match!");
FreeDecodedCert(args->dCert);
args->dCertInit = 0;
#ifdef OPENSSL_EXTRA
args->untrustedDepth = 1;
#endif
} }
} if (!args->haveTrustPeer)
#endif /* WOLFSSL_TRUST_PEER_CERT */
#ifdef OPENSSL_EXTRA
#ifdef WOLFSSL_TRUST_PEER_CERT
else
#endif #endif
if (args->certIdx == 0) { {
byte* subjectHash; /* free cert if not trusted peer */
cert = &args->certs[args->certIdx];
if (!args->dCertInit) {
#ifdef WOLFSSL_SMALL_CERT_VERIFY
if (args->dCert == NULL) {
args->dCert = (DecodedCert*)XMALLOC(
sizeof(DecodedCert), ssl->heap,
DYNAMIC_TYPE_DCERT);
if (args->dCert == NULL) {
ERROR_OUT(MEMORY_E, exit_ppc);
}
}
#endif
InitDecodedCert(args->dCert,
cert->buffer, cert->length, ssl->heap);
args->dCert->sigCtx.devId = ssl->devId;
#ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl;
#endif
args->dCertInit = 1;
#ifdef HAVE_PK_CALLBACKS
ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
if (ret != 0)
goto exit_ppc;
#endif
}
ret = ParseCertRelative(args->dCert, CERT_TYPE, 0,
ssl->ctx->cm);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_PENDING_E) {
ret = wolfSSL_AsyncPush(ssl,
args->dCert->sigCtx.asyncDev);
goto exit_ppc;
}
#endif
if (ret != 0) {
goto exit_ppc;
}
#ifndef NO_SKID
subjectHash = args->dCert->extSubjKeyId;
#else
subjectHash = args->dCert->subjectHash;
#endif
if (!AlreadySigner(ssl->ctx->cm, subjectHash))
args->untrustedDepth = 1;
FreeDecodedCert(args->dCert); FreeDecodedCert(args->dCert);
args->dCertInit = 0; args->dCertInit = 0;
} }
#endif }
#endif /* WOLFSSL_TRUST_PEER_CERT || OPENSSL_EXTRA */
/* verify up to peer's first */ /* check certificate up to peer's first */
/* do not verify chain if trusted peer cert found */ /* do not verify chain if trusted peer cert found */
while (args->count > 1 while (args->count > 1
#ifdef WOLFSSL_TRUST_PEER_CERT #ifdef WOLFSSL_TRUST_PEER_CERT
&& !haveTrustPeer && !args->haveTrustPeer
#endif /* WOLFSSL_TRUST_PEER_CERT */ #endif /* WOLFSSL_TRUST_PEER_CERT */
) { ) {
byte *subjectHash; /* select last certificate */
args->certIdx = args->count - 1; args->certIdx = args->count - 1;
cert = &args->certs[args->certIdx];
#ifdef WOLFSSL_SMALL_CERT_VERIFY ret = ProcessPeerCertParse(ssl, args, CERT_TYPE,
sigRet = 0; !ssl->options.verifyNone ? VERIFY : NO_VERIFY,
&subjectHash, &alreadySigner);
if (!ssl->options.verifyNone) {
if (args->dCert != NULL) {
if (args->dCertInit) {
FreeDecodedCert(args->dCert);
args->dCertInit = 0;
}
XFREE(args->dCert, ssl->heap, DYNAMIC_TYPE_DCERT);
args->dCert = NULL;
}
sigRet = CheckCertSignature(cert->buffer, cert->length,
ssl->heap, ssl->ctx->cm);
}
#endif
if (!args->dCertInit) {
#ifdef WOLFSSL_SMALL_CERT_VERIFY
if (args->dCert == NULL) {
args->dCert = (DecodedCert*)XMALLOC(
sizeof(DecodedCert), ssl->heap,
DYNAMIC_TYPE_DCERT);
if (args->dCert == NULL) {
ERROR_OUT(MEMORY_E, exit_ppc);
}
}
#endif
InitDecodedCert(args->dCert,
cert->buffer, cert->length, ssl->heap);
args->dCert->sigCtx.devId = ssl->devId; /* setup async dev */
#ifdef WOLFSSL_ASYNC_CRYPT #ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl; if (ret == WC_PENDING_E)
#endif
args->dCertInit = 1;
#ifdef HAVE_PK_CALLBACKS
ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
if (ret != 0)
goto exit_ppc; goto exit_ppc;
#endif #endif
if (ret == 0) {
ret = ProcessPeerCertCheckKey(ssl, args);
} }
/* check if returning from non-blocking OCSP */ if (ret == 0 && args->dCert->isCA == 0) {
#ifdef WOLFSSL_NONBLOCK_OCSP
if (args->lastErr != OCSP_WANT_READ)
{
#endif
#ifndef WOLFSSL_SMALL_CERT_VERIFY
sigRet = ParseCertRelative(args->dCert, CERT_TYPE,
!ssl->options.verifyNone, ssl->ctx->cm);
#else
ret = ParseCertRelative(args->dCert, CERT_TYPE,
!ssl->options.verifyNone ? VERIFY_NAME : NO_VERIFY,
ssl->ctx->cm);
if (ret != 0) {
sigRet = ret;
ret = 0;
}
#endif
#ifdef WOLFSSL_ASYNC_CRYPT
if (sigRet == WC_PENDING_E) {
ret = wolfSSL_AsyncPush(ssl,
args->dCert->sigCtx.asyncDev);
goto exit_ppc;
}
#endif
#ifndef NO_SKID
subjectHash = args->dCert->extSubjKeyId;
#else
subjectHash = args->dCert->subjectHash;
#endif
/* Check key sizes for certs. Is redundent check since
ProcessBuffer also performs this check. */
if (!ssl->options.verifyNone) {
switch (args->dCert->keyOID) {
#ifndef NO_RSA
case RSAk:
if (ssl->options.minRsaKeySz < 0 ||
args->dCert->pubKeySize <
(word16)ssl->options.minRsaKeySz) {
WOLFSSL_MSG(
"RSA key size in cert chain error");
sigRet = RSA_KEY_SIZE_E;
}
break;
#endif /* !NO_RSA */
#ifdef HAVE_ECC
case ECDSAk:
if (ssl->options.minEccKeySz < 0 ||
args->dCert->pubKeySize <
(word16)ssl->options.minEccKeySz) {
WOLFSSL_MSG(
"ECC key size in cert chain error");
sigRet = ECC_KEY_SIZE_E;
}
break;
#endif /* HAVE_ECC */
#ifdef HAVE_ED25519
case ED25519k:
if (ssl->options.minEccKeySz < 0 ||
ED25519_KEY_SIZE <
(word16)ssl->options.minEccKeySz) {
WOLFSSL_MSG(
"ECC key size in cert chain error");
sigRet = ECC_KEY_SIZE_E;
}
break;
#endif /* HAVE_ED25519 */
default:
WOLFSSL_MSG("Key size not checked");
/* key not being checked for size if not in
switch */
break;
} /* switch (dCert->keyOID) */
} /* if (!ssl->options.verifyNone) */
if (sigRet == 0 && args->dCert->isCA == 0) {
WOLFSSL_MSG("Chain cert is not a CA, not adding as one"); WOLFSSL_MSG("Chain cert is not a CA, not adding as one");
} }
else if (sigRet == 0 && ssl->options.verifyNone) { else if (ret == 0 && ssl->options.verifyNone) {
WOLFSSL_MSG("Chain cert not verified by option, not adding as CA"); WOLFSSL_MSG("Chain cert not verified by option, "
"not adding as CA");
} }
else if (sigRet == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) { else if (ret == 0) {
buffer* cert = &args->certs[args->certIdx];
/* Is valid CA */
#if defined(SESSION_CERTS) && defined(WOLFSSL_ALT_CERT_CHAINS)
/* if using alternate chain, store the cert used */
if (ssl->options.usingAltCertChain) {
AddSessionCertToChain(&ssl->session.altChain,
cert->buffer, cert->length);
}
#endif /* SESSION_CERTS && WOLFSSL_ALT_CERT_CHAINS */
#ifdef OPENSSL_EXTRA
if (args->certIdx > args->untrustedDepth) {
args->untrustedDepth = (char)args->certIdx + 1;
}
#endif
if (!alreadySigner) {
DerBuffer* add = NULL; DerBuffer* add = NULL;
ret = AllocDer(&add, cert->length, CA_TYPE, ssl->heap); ret = AllocDer(&add, cert->length, CA_TYPE, ssl->heap);
if (ret < 0) if (ret < 0)
goto exit_ppc; goto exit_ppc;
WOLFSSL_MSG("Adding CA from chain");
XMEMCPY(add->buffer, cert->buffer, cert->length); XMEMCPY(add->buffer, cert->buffer, cert->length);
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) /* CA already verified above in ParseCertRelative */
if (args->certIdx > args->untrustedDepth) WOLFSSL_MSG("Adding CA from chain");
args->untrustedDepth = (char)args->certIdx + 1;
#endif
/* already verified above */
ret = AddCA(ssl->ctx->cm, &add, WOLFSSL_CHAIN_CA, 0); ret = AddCA(ssl->ctx->cm, &add, WOLFSSL_CHAIN_CA, 0);
if (ret == 1) { if (ret == WOLFSSL_SUCCESS) {
ret = 0; /* WOLFSSL_SUCCESS for external */ ret = 0;
} }
#ifdef WOLFSSL_ALT_CERT_CHAINS
/* if the previous CA cert failed, clear last error */
if (args->lastCaErr != 0) {
WOLFSSL_MSG("Using alternate cert chain");
ssl->options.usingAltCertChain = 1;
/* clear last CA fail since CA cert was validated */
if (!args->verifyErr)
args->lastCaErr = 0;
#ifdef SESSION_CERTS
AddSessionCertToChain(&ssl->session.altChain,
cert->buffer, cert->length);
#endif /* SESSION_CERTS */
} }
#endif else {
WOLFSSL_MSG("Verified CA from chain and already had it");
} }
else if (sigRet != 0) { }
else {
WOLFSSL_MSG("Failed to verify CA from chain"); WOLFSSL_MSG("Failed to verify CA from chain");
#ifdef OPENSSL_EXTRA #ifdef OPENSSL_EXTRA
ssl->peerVerifyRet = X509_V_ERR_INVALID_CA; ssl->peerVerifyRet = X509_V_ERR_INVALID_CA;
#endif #endif
} }
else {
WOLFSSL_MSG("Verified CA from chain and already had it");
}
#ifdef WOLFSSL_NONBLOCK_OCSP
}
else {
args->lastErr = 0; /* clear last error */
}
#endif
#if defined(HAVE_OCSP) || defined(HAVE_CRL) #if defined(HAVE_OCSP) || defined(HAVE_CRL)
if (ret == 0 && sigRet == 0) { if (ret == 0) {
int doCrlLookup = 1; int doCrlLookup = 1;
#ifdef HAVE_OCSP #ifdef HAVE_OCSP
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
@@ -9414,39 +9378,41 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
} }
#endif /* HAVE_CRL */ #endif /* HAVE_CRL */
(void)doCrlLookup; (void)doCrlLookup;
if (ret != 0)
sigRet = ret;
} }
#endif /* HAVE_OCSP || HAVE_CRL */ #endif /* HAVE_OCSP || HAVE_CRL */
#ifdef WOLFSSL_ALT_CERT_CHAINS
/* For alternate cert chain, its okay for a CA cert to fail
with ASN_NO_SIGNER_E here. The "alternate" certificate
chain mode only requires that the peer certificate
validate to a trusted CA */
if (ret != 0) {
if (ret == ASN_NO_SIGNER_E) {
if (!ssl->options.usingAltCertChain) {
WOLFSSL_MSG("Trying alternate cert chain");
ssl->options.usingAltCertChain = 1;
}
ret = 0; /* clear error and continue */
}
}
#endif /* WOLFSSL_ALT_CERT_CHAINS */
/* Do verify callback */ /* Do verify callback */
sigRet = DoVerifyCallback(ssl, sigRet, args); ret = DoVerifyCallback(ssl, ret, args);
/* Handle error codes */ /* Handle error codes */
#ifdef WOLFSSL_ALT_CERT_CHAINS if (ret != 0 && args->lastErr == 0) {
if (args->lastCaErr == 0) { args->lastErr = ret; /* save error from last time */
/* capture CA error and proceed to next cert */ ret = 0; /* reset error */
args->lastCaErr = sigRet;
sigRet = 0;
}
else {
args->lastErr = args->lastCaErr;
}
#endif
if (sigRet != 0 && args->lastErr == 0) {
args->lastErr = sigRet; /* save error from last time */
sigRet = 0; /* reset error */
} }
FreeDecodedCert(args->dCert); FreeDecodedCert(args->dCert);
args->dCertInit = 0; args->dCertInit = 0;
args->count--; args->count--;
} /* while (count > 0 && !haveTrustPeer) */ } /* while (count > 0 && !args->haveTrustPeer) */
} /* if (count > 0) */ } /* if (count > 0) */
if (sigRet != 0)
ret = sigRet;
/* Check for error */ /* Check for error */
if (ret != 0) { if (ret != 0) {
goto exit_ppc; goto exit_ppc;
@@ -9463,81 +9429,25 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (args->count > 0) { if (args->count > 0) {
WOLFSSL_MSG("Verifying Peer's cert"); WOLFSSL_MSG("Verifying Peer's cert");
/* select peer cert (first one) */
args->certIdx = 0; args->certIdx = 0;
cert = &args->certs[args->certIdx];
#ifdef WOLFSSL_SMALL_CERT_VERIFY ret = ProcessPeerCertParse(ssl, args, CERT_TYPE,
sigRet = 0; !ssl->options.verifyNone ? VERIFY : NO_VERIFY,
&subjectHash, &alreadySigner);
if (!ssl->options.verifyNone) {
if (args->dCert != NULL) {
if (args->dCertInit) {
FreeDecodedCert(args->dCert);
args->dCertInit = 0;
}
XFREE(args->dCert, ssl->heap, DYNAMIC_TYPE_DCERT);
args->dCert = NULL;
}
sigRet = CheckCertSignature(cert->buffer, cert->length,
ssl->heap, ssl->ctx->cm);
}
#endif
if (!args->dCertInit) {
if (args->dCert == NULL) {
args->dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert),
ssl->heap, DYNAMIC_TYPE_DCERT);
if (args->dCert == NULL) {
ERROR_OUT(MEMORY_E, exit_ppc);
}
}
InitDecodedCert(args->dCert,
cert->buffer, cert->length, ssl->heap);
args->dCert->sigCtx.devId = ssl->devId; /* setup async dev */
#ifdef WOLFSSL_ASYNC_CRYPT #ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl; if (ret == WC_PENDING_E)
#endif
args->dCertInit = 1;
#ifdef HAVE_PK_CALLBACKS
ret = InitSigPkCb(ssl, &args->dCert->sigCtx);
if (ret != 0)
goto exit_ppc; goto exit_ppc;
#endif #endif
} if (ret == 0) {
#ifdef WOLFSSL_TRUST_PEER_CERT
if (!haveTrustPeer)
#endif
{
/* only parse if not already present in dCert from above */
#ifndef WOLFSSL_SMALL_CERT_VERIFY
sigRet = ParseCertRelative(args->dCert, CERT_TYPE,
!ssl->options.verifyNone, ssl->ctx->cm);
#else
ret = ParseCertRelative(args->dCert, CERT_TYPE,
!ssl->options.verifyNone ? VERIFY_NAME : NO_VERIFY,
ssl->ctx->cm);
if (ret != 0) {
sigRet = ret;
ret = 0;
}
#endif
#ifdef WOLFSSL_ASYNC_CRYPT
if (sigRet == WC_PENDING_E) {
ret = wolfSSL_AsyncPush(ssl,
args->dCert->sigCtx.asyncDev);
goto exit_ppc;
}
#endif
}
if (sigRet == 0) {
WOLFSSL_MSG("Verified Peer's cert"); WOLFSSL_MSG("Verified Peer's cert");
#ifdef OPENSSL_EXTRA #ifdef OPENSSL_EXTRA
ssl->peerVerifyRet = X509_V_OK; ssl->peerVerifyRet = X509_V_OK;
#endif #endif
#if defined(SESSION_CERTS) && defined(WOLFSSL_ALT_CERT_CHAINS) #if defined(SESSION_CERTS) && defined(WOLFSSL_ALT_CERT_CHAINS)
/* if using alternate chain, store the cert used */
if (ssl->options.usingAltCertChain) { if (ssl->options.usingAltCertChain) {
buffer* cert = &args->certs[args->certIdx];
AddSessionCertToChain(&ssl->session.altChain, AddSessionCertToChain(&ssl->session.altChain,
cert->buffer, cert->length); cert->buffer, cert->length);
} }
@@ -9546,20 +9456,15 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
/* check if fatal error */ /* check if fatal error */
if (args->verifyErr) { if (args->verifyErr) {
args->fatal = 1; args->fatal = 1;
if (sigRet == 0) { if (ret == 0) {
sigRet = args->lastErr; ret = args->lastErr;
} }
#ifdef WOLFSSL_ALT_CERT_CHAINS
if (sigRet == 0) {
sigRet = args->lastCaErr;
}
#endif
} }
else { else {
args->fatal = 0; args->fatal = 0;
} }
} }
else if (sigRet == ASN_PARSE_E || sigRet == BUFFER_E) { else if (ret == ASN_PARSE_E || ret == BUFFER_E) {
WOLFSSL_MSG("Got Peer cert ASN PARSE or BUFFER ERROR"); WOLFSSL_MSG("Got Peer cert ASN PARSE or BUFFER ERROR");
#ifdef OPENSSL_EXTRA #ifdef OPENSSL_EXTRA
SendAlert(ssl, alert_fatal, bad_certificate); SendAlert(ssl, alert_fatal, bad_certificate);
@@ -9599,7 +9504,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
WOLFSSL_MSG( WOLFSSL_MSG(
"Peer sent different cert during scr, fatal"); "Peer sent different cert during scr, fatal");
args->fatal = 1; args->fatal = 1;
sigRet = SCR_DIFFERENT_CERT_E; ret = SCR_DIFFERENT_CERT_E;
} }
} }
@@ -9612,8 +9517,6 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#endif /* HAVE_SECURE_RENEGOTIATION */ #endif /* HAVE_SECURE_RENEGOTIATION */
} /* if (count > 0) */ } /* if (count > 0) */
if (sigRet != 0)
ret = sigRet;
/* Check for error */ /* Check for error */
if (args->fatal && ret != 0) { if (args->fatal && ret != 0) {
goto exit_ppc; goto exit_ppc;
@@ -10017,7 +9920,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ret = args->lastErr; ret = args->lastErr;
} }
#ifdef OPENSSL_EXTRA #if defined(OPENSSL_EXTRA)
if (args->untrustedDepth > ssl->options.verifyDepth) { if (args->untrustedDepth > ssl->options.verifyDepth) {
ssl->peerVerifyRet = X509_V_ERR_CERT_CHAIN_TOO_LONG; ssl->peerVerifyRet = X509_V_ERR_CERT_CHAIN_TOO_LONG;
ret = MAX_CHAIN_ERROR; ret = MAX_CHAIN_ERROR;
@@ -22151,7 +22054,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif #endif
} }
/* Signtaure length will be written later, when we're sure what it is */ /* Signature length will be written later, when we're sure what it is */
#ifdef HAVE_FUZZER #ifdef HAVE_FUZZER
if (ssl->fuzzerCb) { if (ssl->fuzzerCb) {

View File

@@ -44,8 +44,6 @@ ASN Options:
Only enabled for OCSP. Only enabled for OCSP.
* WOLFSSL_NO_OCSP_ISSUER_CHECK: Can be defined for backwards compatibility to * WOLFSSL_NO_OCSP_ISSUER_CHECK: Can be defined for backwards compatibility to
disable checking of OCSP subject hash with issuer hash. disable checking of OCSP subject hash with issuer hash.
* WOLFSSL_ALT_CERT_CHAINS: Allows matching multiple CA's to validate
chain based on issuer and public key (includes signature confirmation)
* WOLFSSL_SMALL_CERT_VERIFY: Verify the certificate signature without using * WOLFSSL_SMALL_CERT_VERIFY: Verify the certificate signature without using
DecodedCert. Doubles up on some code but allows smaller dynamic memory DecodedCert. Doubles up on some code but allows smaller dynamic memory
usage. usage.
@@ -4223,6 +4221,8 @@ void FreeNameSubtrees(Base_entry* names, void* heap)
void FreeDecodedCert(DecodedCert* cert) void FreeDecodedCert(DecodedCert* cert)
{ {
if (cert == NULL)
return;
if (cert->subjectCNStored == 1) if (cert->subjectCNStored == 1)
XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN); XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN);
if (cert->pubKeyStored == 1) if (cert->pubKeyStored == 1)
@@ -5385,7 +5385,7 @@ int ValidateDate(const byte* date, byte format, int dateType)
GetTime(&diffMM, date, &i); GetTime(&diffMM, date, &i);
timeDiff = diffSign * (diffHH*60 + diffMM) * 60 ; timeDiff = diffSign * (diffHH*60 + diffMM) * 60 ;
} else if (date[i] != 'Z') { } else if (date[i] != 'Z') {
WOLFSSL_MSG("UTCtime, niether Zulu or time differential") ; WOLFSSL_MSG("UTCtime, neither Zulu or time differential") ;
return 0; return 0;
} }
@@ -5614,6 +5614,11 @@ int DecodeToKey(DecodedCert* cert, int verify)
WOLFSSL_MSG("Got Subject Name"); WOLFSSL_MSG("Got Subject Name");
/* Determine if self signed */
cert->selfSigned = XMEMCMP(cert->issuerHash,
cert->subjectHash,
KEYID_SIZE) == 0 ? 1 : 0;
if ( (ret = GetKey(cert)) < 0) if ( (ret = GetKey(cert)) < 0)
return ret; return ret;
@@ -7664,8 +7669,7 @@ Signer* GetCAByName(void* signers, byte* hash)
#endif /* WOLFCRYPT_ONLY || NO_CERTS */ #endif /* WOLFCRYPT_ONLY || NO_CERTS */
#if (defined(WOLFSSL_ALT_CERT_CHAINS) || \ #if defined(WOLFSSL_NO_TRUSTED_CERTS_VERIFY) && !defined(NO_SKID)
defined(WOLFSSL_NO_TRUSTED_CERTS_VERIFY)) && !defined(NO_SKID)
static Signer* GetCABySubjectAndPubKey(DecodedCert* cert, void* cm) static Signer* GetCABySubjectAndPubKey(DecodedCert* cert, void* cm)
{ {
Signer* ca = NULL; Signer* ca = NULL;
@@ -7955,7 +7959,6 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
int badDate = 0; int badDate = 0;
int criticalExt = 0; int criticalExt = 0;
word32 confirmOID; word32 confirmOID;
int selfSigned = 0;
if (cert == NULL) { if (cert == NULL) {
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
@@ -8033,34 +8036,29 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
} }
} }
#endif /* WOLFSSL_NO_TRUSTED_CERTS_VERIFY */ #endif /* WOLFSSL_NO_TRUSTED_CERTS_VERIFY */
/* alt lookup using subject and public key */
#ifdef WOLFSSL_ALT_CERT_CHAINS
if (cert->ca == NULL)
cert->ca = GetCABySubjectAndPubKey(cert, cm);
#endif
#else #else
cert->ca = GetCA(cm, cert->issuerHash); cert->ca = GetCA(cm, cert->issuerHash);
if (XMEMCMP(cert->issuerHash, cert->subjectHash, KEYID_SIZE) == 0)
selfSigned = 1;
#endif /* !NO_SKID */ #endif /* !NO_SKID */
WOLFSSL_MSG("About to verify certificate signature"); WOLFSSL_MSG("About to verify certificate signature");
if (cert->ca) { if (cert->ca) {
/* Check if cert is CA type and has path length set */
if (cert->isCA && cert->ca->pathLengthSet) { if (cert->isCA && cert->ca->pathLengthSet) {
if (selfSigned) { /* Check root CA (self-signed) has path length > 0 */
if (cert->selfSigned) {
if (cert->ca->pathLength != 0) { if (cert->ca->pathLength != 0) {
WOLFSSL_MSG("Root CA with path length > 0"); WOLFSSL_MSG("Root CA with path length > 0");
return ASN_PATHLEN_INV_E; return ASN_PATHLEN_INV_E;
} }
} }
else { else {
/* Check path lengths are valid between two CA's */
if (cert->ca->pathLength == 0) { if (cert->ca->pathLength == 0) {
WOLFSSL_MSG("CA with path length 0 signing a CA"); WOLFSSL_MSG("CA with path length 0 signing a CA");
return ASN_PATHLEN_INV_E; return ASN_PATHLEN_INV_E;
} }
else if (cert->pathLength >= cert->ca->pathLength) { else if (cert->pathLength >= cert->ca->pathLength) {
WOLFSSL_MSG("CA signing CA with longer path length"); WOLFSSL_MSG("CA signing CA with longer path length");
return ASN_PATHLEN_INV_E; return ASN_PATHLEN_INV_E;
} }

View File

@@ -855,6 +855,7 @@ struct DecodedCert {
byte extBasicConstSet : 1; byte extBasicConstSet : 1;
byte extSubjAltNameSet : 1; byte extSubjAltNameSet : 1;
byte inhibitAnyOidSet : 1; byte inhibitAnyOidSet : 1;
byte selfSigned : 1; /* Indicates subject and issuer are same */
#ifdef WOLFSSL_SEP #ifdef WOLFSSL_SEP
byte extCertPolicySet : 1; byte extCertPolicySet : 1;
#endif #endif