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:
parent
3e31115654
commit
9733076fe0
717
src/internal.c
717
src/internal.c
@ -30,7 +30,13 @@
|
||||
/*
|
||||
* WOLFSSL_SMALL_CERT_VERIFY:
|
||||
* 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
|
||||
@ -8546,13 +8552,10 @@ typedef struct ProcPeerCertArgs {
|
||||
int count;
|
||||
int certIdx;
|
||||
int lastErr;
|
||||
#ifdef WOLFSSL_ALT_CERT_CHAINS
|
||||
int lastCaErr;
|
||||
#endif
|
||||
#ifdef WOLFSSL_TLS13
|
||||
byte ctxSz;
|
||||
#endif
|
||||
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
|
||||
#ifdef OPENSSL_EXTRA
|
||||
char untrustedDepth;
|
||||
#endif
|
||||
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,
|
||||
word32 totalSz)
|
||||
{
|
||||
int ret = 0, sigRet = 0;
|
||||
int ret = 0;
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
ProcPeerCertArgs* args = (ProcPeerCertArgs*)ssl->async.args;
|
||||
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
|
||||
ProcPeerCertArgs args[1];
|
||||
#endif
|
||||
|
||||
buffer* cert;
|
||||
#ifdef WOLFSSL_TRUST_PEER_CERT
|
||||
byte haveTrustPeer = 0; /* was cert verified by loaded trusted peer cert */
|
||||
#endif
|
||||
byte* subjectHash = NULL;
|
||||
int alreadySigner = 0;
|
||||
|
||||
WOLFSSL_ENTER("ProcessPeerCerts");
|
||||
|
||||
@ -8931,6 +9108,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
}
|
||||
XMEMSET(args->certs, 0, sizeof(buffer) * MAX_CHAIN_DEPTH);
|
||||
#endif /* OPENSSL_EXTRA */
|
||||
|
||||
/* Certificate List */
|
||||
if ((args->idx - args->begin) + OPAQUE24_LEN > totalSz) {
|
||||
ERROR_OUT(BUFFER_ERROR, exit_ppc);
|
||||
@ -9012,16 +9190,16 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
} /* while (listSz) */
|
||||
|
||||
args->count = args->totalCerts;
|
||||
args->certIdx = 0;
|
||||
args->certIdx = 0; /* select peer cert (first one) */
|
||||
|
||||
args->dCertInit = 0;
|
||||
#ifndef WOLFSSL_SMALL_CERT_VERIFY
|
||||
#ifndef WOLFSSL_SMALL_CERT_VERIFY
|
||||
args->dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
|
||||
DYNAMIC_TYPE_DCERT);
|
||||
if (args->dCert == NULL) {
|
||||
ERROR_OUT(MEMORY_E, exit_ppc);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Advance state and proceed */
|
||||
ssl->options.asyncState = TLS_ASYNC_BUILD;
|
||||
@ -9031,343 +9209,129 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
case TLS_ASYNC_BUILD:
|
||||
{
|
||||
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 using trusted peer certs check before verify chain
|
||||
and CA test */
|
||||
#ifdef WOLFSSL_TRUST_PEER_CERT
|
||||
TrustedPeerCert* tp;
|
||||
|
||||
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; /* 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;
|
||||
}
|
||||
int matchType = WC_MATCH_NAME;
|
||||
#endif
|
||||
|
||||
ret = ProcessPeerCertParse(ssl, args, CERT_TYPE, NO_VERIFY,
|
||||
&subjectHash, &alreadySigner);
|
||||
if (ret != 0)
|
||||
goto exit_ppc;
|
||||
|
||||
#ifndef NO_SKID
|
||||
if (args->dCert->extAuthKeyIdSet) {
|
||||
tp = GetTrustedPeer(ssl->ctx->cm,
|
||||
args->dCert->extSubjKeyId, WC_MATCH_SKID);
|
||||
#ifdef OPENSSL_EXTRA
|
||||
/* Determine untrusted depth */
|
||||
if (!alreadySigner) {
|
||||
args->untrustedDepth = 1;
|
||||
}
|
||||
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 */
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_TRUST_PEER_CERT
|
||||
#ifndef NO_SKID
|
||||
if (args->dCert->extAuthKeyIdSet)
|
||||
matchType = WC_MATCH_SKID;
|
||||
#endif
|
||||
tp = GetTrustedPeer(ssl->ctx->cm, subjectHash, matchType);
|
||||
WOLFSSL_MSG("Checking for trusted peer cert");
|
||||
|
||||
if (tp == NULL) {
|
||||
/* 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)){
|
||||
if (tp && MatchTrustedPeer(tp, args->dCert)) {
|
||||
WOLFSSL_MSG("Found matching trusted peer cert");
|
||||
haveTrustPeer = 1;
|
||||
} else {
|
||||
args->haveTrustPeer = 1;
|
||||
}
|
||||
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!");
|
||||
}
|
||||
if (!args->haveTrustPeer)
|
||||
#endif
|
||||
{
|
||||
/* free cert if not trusted peer */
|
||||
FreeDecodedCert(args->dCert);
|
||||
args->dCertInit = 0;
|
||||
#ifdef OPENSSL_EXTRA
|
||||
args->untrustedDepth = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* WOLFSSL_TRUST_PEER_CERT */
|
||||
#ifdef OPENSSL_EXTRA
|
||||
#ifdef WOLFSSL_TRUST_PEER_CERT
|
||||
else
|
||||
#endif
|
||||
if (args->certIdx == 0) {
|
||||
byte* subjectHash;
|
||||
cert = &args->certs[args->certIdx];
|
||||
#endif /* WOLFSSL_TRUST_PEER_CERT || OPENSSL_EXTRA */
|
||||
|
||||
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);
|
||||
args->dCertInit = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* verify up to peer's first */
|
||||
/* check certificate up to peer's first */
|
||||
/* do not verify chain if trusted peer cert found */
|
||||
while (args->count > 1
|
||||
#ifdef WOLFSSL_TRUST_PEER_CERT
|
||||
&& !haveTrustPeer
|
||||
&& !args->haveTrustPeer
|
||||
#endif /* WOLFSSL_TRUST_PEER_CERT */
|
||||
) {
|
||||
byte *subjectHash;
|
||||
|
||||
/* select last certificate */
|
||||
args->certIdx = args->count - 1;
|
||||
cert = &args->certs[args->certIdx];
|
||||
|
||||
#ifdef WOLFSSL_SMALL_CERT_VERIFY
|
||||
sigRet = 0;
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
/* check if returning from non-blocking OCSP */
|
||||
#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
|
||||
ret = ProcessPeerCertParse(ssl, args, CERT_TYPE,
|
||||
!ssl->options.verifyNone ? VERIFY : NO_VERIFY,
|
||||
&subjectHash, &alreadySigner);
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
if (sigRet == WC_PENDING_E) {
|
||||
ret = wolfSSL_AsyncPush(ssl,
|
||||
args->dCert->sigCtx.asyncDev);
|
||||
if (ret == WC_PENDING_E)
|
||||
goto exit_ppc;
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
ret = ProcessPeerCertCheckKey(ssl, args);
|
||||
}
|
||||
#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) {
|
||||
if (ret == 0 && args->dCert->isCA == 0) {
|
||||
WOLFSSL_MSG("Chain cert is not a CA, not adding as one");
|
||||
}
|
||||
else if (sigRet == 0 && ssl->options.verifyNone) {
|
||||
WOLFSSL_MSG("Chain cert not verified by option, not adding as CA");
|
||||
else if (ret == 0 && ssl->options.verifyNone) {
|
||||
WOLFSSL_MSG("Chain cert not verified by option, "
|
||||
"not adding as CA");
|
||||
}
|
||||
else if (sigRet == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) {
|
||||
DerBuffer* add = NULL;
|
||||
ret = AllocDer(&add, cert->length, CA_TYPE, ssl->heap);
|
||||
if (ret < 0)
|
||||
goto exit_ppc;
|
||||
else if (ret == 0) {
|
||||
buffer* cert = &args->certs[args->certIdx];
|
||||
|
||||
WOLFSSL_MSG("Adding CA from chain");
|
||||
|
||||
XMEMCPY(add->buffer, cert->buffer, cert->length);
|
||||
|
||||
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX)
|
||||
if (args->certIdx > args->untrustedDepth)
|
||||
args->untrustedDepth = (char)args->certIdx + 1;
|
||||
#endif
|
||||
|
||||
/* already verified above */
|
||||
ret = AddCA(ssl->ctx->cm, &add, WOLFSSL_CHAIN_CA, 0);
|
||||
if (ret == 1) {
|
||||
ret = 0; /* WOLFSSL_SUCCESS for external */
|
||||
}
|
||||
|
||||
#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
|
||||
/* 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 */
|
||||
}
|
||||
#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;
|
||||
ret = AllocDer(&add, cert->length, CA_TYPE, ssl->heap);
|
||||
if (ret < 0)
|
||||
goto exit_ppc;
|
||||
|
||||
XMEMCPY(add->buffer, cert->buffer, cert->length);
|
||||
|
||||
/* CA already verified above in ParseCertRelative */
|
||||
WOLFSSL_MSG("Adding CA from chain");
|
||||
ret = AddCA(ssl->ctx->cm, &add, WOLFSSL_CHAIN_CA, 0);
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("Verified CA from chain and already had it");
|
||||
}
|
||||
}
|
||||
else if (sigRet != 0) {
|
||||
else {
|
||||
WOLFSSL_MSG("Failed to verify CA from chain");
|
||||
#ifdef OPENSSL_EXTRA
|
||||
ssl->peerVerifyRet = X509_V_ERR_INVALID_CA;
|
||||
#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 (ret == 0 && sigRet == 0) {
|
||||
if (ret == 0) {
|
||||
int doCrlLookup = 1;
|
||||
#ifdef HAVE_OCSP
|
||||
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
|
||||
@ -9414,39 +9378,41 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
}
|
||||
#endif /* HAVE_CRL */
|
||||
(void)doCrlLookup;
|
||||
|
||||
if (ret != 0)
|
||||
sigRet = ret;
|
||||
}
|
||||
#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 */
|
||||
sigRet = DoVerifyCallback(ssl, sigRet, args);
|
||||
ret = DoVerifyCallback(ssl, ret, args);
|
||||
|
||||
/* Handle error codes */
|
||||
#ifdef WOLFSSL_ALT_CERT_CHAINS
|
||||
if (args->lastCaErr == 0) {
|
||||
/* capture CA error and proceed to next cert */
|
||||
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 */
|
||||
if (ret != 0 && args->lastErr == 0) {
|
||||
args->lastErr = ret; /* save error from last time */
|
||||
ret = 0; /* reset error */
|
||||
}
|
||||
|
||||
FreeDecodedCert(args->dCert);
|
||||
args->dCertInit = 0;
|
||||
args->count--;
|
||||
} /* while (count > 0 && !haveTrustPeer) */
|
||||
} /* while (count > 0 && !args->haveTrustPeer) */
|
||||
} /* if (count > 0) */
|
||||
|
||||
if (sigRet != 0)
|
||||
ret = sigRet;
|
||||
/* Check for error */
|
||||
if (ret != 0) {
|
||||
goto exit_ppc;
|
||||
@ -9463,81 +9429,25 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
if (args->count > 0) {
|
||||
WOLFSSL_MSG("Verifying Peer's cert");
|
||||
|
||||
/* select peer cert (first one) */
|
||||
args->certIdx = 0;
|
||||
cert = &args->certs[args->certIdx];
|
||||
|
||||
#ifdef WOLFSSL_SMALL_CERT_VERIFY
|
||||
sigRet = 0;
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_TRUST_PEER_CERT
|
||||
if (!haveTrustPeer)
|
||||
ret = ProcessPeerCertParse(ssl, args, CERT_TYPE,
|
||||
!ssl->options.verifyNone ? VERIFY : NO_VERIFY,
|
||||
&subjectHash, &alreadySigner);
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
if (ret == WC_PENDING_E)
|
||||
goto exit_ppc;
|
||||
#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) {
|
||||
if (ret == 0) {
|
||||
WOLFSSL_MSG("Verified Peer's cert");
|
||||
#ifdef OPENSSL_EXTRA
|
||||
ssl->peerVerifyRet = X509_V_OK;
|
||||
#endif
|
||||
#if defined(SESSION_CERTS) && defined(WOLFSSL_ALT_CERT_CHAINS)
|
||||
/* if using alternate chain, store the cert used */
|
||||
if (ssl->options.usingAltCertChain) {
|
||||
buffer* cert = &args->certs[args->certIdx];
|
||||
AddSessionCertToChain(&ssl->session.altChain,
|
||||
cert->buffer, cert->length);
|
||||
}
|
||||
@ -9546,20 +9456,15 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
/* check if fatal error */
|
||||
if (args->verifyErr) {
|
||||
args->fatal = 1;
|
||||
if (sigRet == 0) {
|
||||
sigRet = args->lastErr;
|
||||
if (ret == 0) {
|
||||
ret = args->lastErr;
|
||||
}
|
||||
#ifdef WOLFSSL_ALT_CERT_CHAINS
|
||||
if (sigRet == 0) {
|
||||
sigRet = args->lastCaErr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
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");
|
||||
#ifdef OPENSSL_EXTRA
|
||||
SendAlert(ssl, alert_fatal, bad_certificate);
|
||||
@ -9599,7 +9504,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
WOLFSSL_MSG(
|
||||
"Peer sent different cert during scr, fatal");
|
||||
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 */
|
||||
} /* if (count > 0) */
|
||||
|
||||
if (sigRet != 0)
|
||||
ret = sigRet;
|
||||
/* Check for error */
|
||||
if (args->fatal && ret != 0) {
|
||||
goto exit_ppc;
|
||||
@ -10017,7 +9920,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
ret = args->lastErr;
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_EXTRA
|
||||
#if defined(OPENSSL_EXTRA)
|
||||
if (args->untrustedDepth > ssl->options.verifyDepth) {
|
||||
ssl->peerVerifyRet = X509_V_ERR_CERT_CHAIN_TOO_LONG;
|
||||
ret = MAX_CHAIN_ERROR;
|
||||
@ -22151,7 +22054,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#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
|
||||
if (ssl->fuzzerCb) {
|
||||
|
@ -44,8 +44,6 @@ ASN Options:
|
||||
Only enabled for OCSP.
|
||||
* WOLFSSL_NO_OCSP_ISSUER_CHECK: Can be defined for backwards compatibility to
|
||||
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
|
||||
DecodedCert. Doubles up on some code but allows smaller dynamic memory
|
||||
usage.
|
||||
@ -4223,6 +4221,8 @@ void FreeNameSubtrees(Base_entry* names, void* heap)
|
||||
|
||||
void FreeDecodedCert(DecodedCert* cert)
|
||||
{
|
||||
if (cert == NULL)
|
||||
return;
|
||||
if (cert->subjectCNStored == 1)
|
||||
XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN);
|
||||
if (cert->pubKeyStored == 1)
|
||||
@ -5385,7 +5385,7 @@ int ValidateDate(const byte* date, byte format, int dateType)
|
||||
GetTime(&diffMM, date, &i);
|
||||
timeDiff = diffSign * (diffHH*60 + diffMM) * 60 ;
|
||||
} else if (date[i] != 'Z') {
|
||||
WOLFSSL_MSG("UTCtime, niether Zulu or time differential") ;
|
||||
WOLFSSL_MSG("UTCtime, neither Zulu or time differential") ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5614,6 +5614,11 @@ int DecodeToKey(DecodedCert* cert, int verify)
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
@ -7664,8 +7669,7 @@ Signer* GetCAByName(void* signers, byte* hash)
|
||||
|
||||
#endif /* WOLFCRYPT_ONLY || NO_CERTS */
|
||||
|
||||
#if (defined(WOLFSSL_ALT_CERT_CHAINS) || \
|
||||
defined(WOLFSSL_NO_TRUSTED_CERTS_VERIFY)) && !defined(NO_SKID)
|
||||
#if defined(WOLFSSL_NO_TRUSTED_CERTS_VERIFY) && !defined(NO_SKID)
|
||||
static Signer* GetCABySubjectAndPubKey(DecodedCert* cert, void* cm)
|
||||
{
|
||||
Signer* ca = NULL;
|
||||
@ -7955,7 +7959,6 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
|
||||
int badDate = 0;
|
||||
int criticalExt = 0;
|
||||
word32 confirmOID;
|
||||
int selfSigned = 0;
|
||||
|
||||
if (cert == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
@ -8033,34 +8036,29 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
|
||||
}
|
||||
}
|
||||
#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
|
||||
cert->ca = GetCA(cm, cert->issuerHash);
|
||||
if (XMEMCMP(cert->issuerHash, cert->subjectHash, KEYID_SIZE) == 0)
|
||||
selfSigned = 1;
|
||||
#endif /* !NO_SKID */
|
||||
|
||||
WOLFSSL_MSG("About to verify certificate signature");
|
||||
|
||||
if (cert->ca) {
|
||||
/* Check if cert is CA type and has path length set */
|
||||
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) {
|
||||
WOLFSSL_MSG("Root CA with path length > 0");
|
||||
return ASN_PATHLEN_INV_E;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Check path lengths are valid between two CA's */
|
||||
if (cert->ca->pathLength == 0) {
|
||||
WOLFSSL_MSG("CA with path length 0 signing a CA");
|
||||
return ASN_PATHLEN_INV_E;
|
||||
}
|
||||
else if (cert->pathLength >= cert->ca->pathLength) {
|
||||
|
||||
WOLFSSL_MSG("CA signing CA with longer path length");
|
||||
return ASN_PATHLEN_INV_E;
|
||||
}
|
||||
|
@ -855,6 +855,7 @@ struct DecodedCert {
|
||||
byte extBasicConstSet : 1;
|
||||
byte extSubjAltNameSet : 1;
|
||||
byte inhibitAnyOidSet : 1;
|
||||
byte selfSigned : 1; /* Indicates subject and issuer are same */
|
||||
#ifdef WOLFSSL_SEP
|
||||
byte extCertPolicySet : 1;
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user