Merge pull request #1170 from dgarske/alt_cert_chains

Alternate certificate chain support `WOLFSSL_ALT_CERT_CHAINS`
This commit is contained in:
toddouska
2017-10-12 10:02:29 -07:00
committed by GitHub
6 changed files with 181 additions and 67 deletions

View File

@@ -7477,8 +7477,23 @@ int CheckHostName(DecodedCert* dCert, char *domainName, size_t domainNameLen)
}
#endif
#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
#ifdef SESSION_CERTS
static void AddSessionCertToChain(WOLFSSL_X509_CHAIN* chain,
byte* certBuf, word32 certSz)
{
if (chain->count < MAX_CHAIN_DEPTH &&
certSz < MAX_X509_SIZE) {
chain->certs[chain->count].length = certSz;
XMEMCPY(chain->certs[chain->count].buffer, certBuf, certSz);
chain->count++;
}
else {
WOLFSSL_MSG("Couldn't store chain cert for session");
}
}
#endif
#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
/* Copy parts X509 needs from Decoded cert, 0 on success */
int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert)
{
@@ -7723,6 +7738,9 @@ typedef struct ProcPeerCertArgs {
int certIdx;
int fatal;
int lastErr;
#ifdef WOLFSSL_ALT_CERT_CHAINS
int lastCaErr;
#endif
#ifdef WOLFSSL_TLS13
byte ctxSz;
#endif
@@ -7776,6 +7794,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ProcPeerCertArgs args[1];
#endif
buffer* cert;
#ifdef WOLFSSL_TRUST_PEER_CERT
byte haveTrustPeer = 0; /* was cert verified by loaded trusted peer cert */
#endif
@@ -7927,18 +7946,8 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
args->certs[args->totalCerts].buffer = input + args->idx;
#ifdef SESSION_CERTS
if (ssl->session.chain.count < MAX_CHAIN_DEPTH &&
certSz < MAX_X509_SIZE) {
ssl->session.chain.certs[
ssl->session.chain.count].length = certSz;
XMEMCPY(ssl->session.chain.certs[
ssl->session.chain.count].buffer,
input + args->idx, certSz);
ssl->session.chain.count++;
}
else {
WOLFSSL_MSG("Couldn't store chain cert for session");
}
AddSessionCertToChain(&ssl->session.chain,
input + args->idx, certSz);
#endif /* SESSION_CERTS */
args->idx += certSz;
@@ -7991,10 +8000,11 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
and CA test */
TrustedPeerCert* tp;
cert = &args->certs[args->certIdx];
if (!args->dCertInit) {
InitDecodedCert(args->dCert,
args->certs[args->certIdx].buffer,
args->certs[args->certIdx].length, ssl->heap);
cert->buffer, cert->length, ssl->heap);
args->dCert->sigCtx.devId = ssl->devId; /* setup async dev */
#ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl;
@@ -8058,11 +8068,11 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#endif
if (args->certIdx == 0) {
byte* subjectHash;
cert = &args->certs[args->certIdx];
if (!args->dCertInit) {
InitDecodedCert(args->dCert,
args->certs[args->certIdx].buffer,
args->certs[args->certIdx].length, ssl->heap);
cert->buffer, cert->length, ssl->heap);
args->dCert->sigCtx.devId = ssl->devId;
#ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl;
@@ -8102,14 +8112,14 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
&& !haveTrustPeer
#endif /* WOLFSSL_TRUST_PEER_CERT */
) {
byte* subjectHash;
byte *subjectHash;
args->certIdx = args->count - 1;
cert = &args->certs[args->certIdx];
if (!args->dCertInit) {
InitDecodedCert(args->dCert,
args->certs[args->certIdx].buffer,
args->certs[args->certIdx].length, ssl->heap);
cert->buffer, cert->length, ssl->heap);
args->dCert->sigCtx.devId = ssl->devId; /* setup async dev */
#ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl;
@@ -8186,16 +8196,13 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
}
else if (ret == 0 && !AlreadySigner(ssl->ctx->cm, subjectHash)) {
DerBuffer* add = NULL;
ret = AllocDer(&add, args->certs[args->certIdx].length,
CA_TYPE, ssl->heap);
ret = AllocDer(&add, cert->length, CA_TYPE, ssl->heap);
if (ret < 0)
goto exit_ppc;
WOLFSSL_MSG("Adding CA from chain");
XMEMCPY(add->buffer, args->certs[args->certIdx].buffer,
args->certs[args->certIdx].length);
XMEMCPY(add->buffer, cert->buffer, cert->length);
#ifdef WOLFSSL_NGINX
if (args->certIdx > args->untrustedDepth)
@@ -8207,9 +8214,35 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (ret == 1) {
ret = 0; /* SSL_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 */
args->lastCaErr = 0;
#ifdef SESSION_CERTS
AddSessionCertToChain(&ssl->session.altChain,
cert->buffer, cert->length);
#endif /* SESSION_CERTS */
}
#endif
}
else if (ret != 0) {
WOLFSSL_MSG("Failed to verify CA from chain");
#ifdef WOLFSSL_ALT_CERT_CHAINS
if (args->lastCaErr == 0) {
/* store CA error and proceed to next cert */
args->lastCaErr = ret;
ret = 0;
}
else {
args->lastErr = args->lastCaErr;
}
#endif
#ifdef OPENSSL_EXTRA
ssl->peerVerifyRet = X509_V_ERR_INVALID_CA;
#endif
@@ -8297,11 +8330,11 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
WOLFSSL_MSG("Verifying Peer's cert");
args->certIdx = 0;
cert = &args->certs[args->certIdx];
if (!args->dCertInit) {
InitDecodedCert(args->dCert,
args->certs[args->certIdx].buffer,
args->certs[args->certIdx].length, ssl->heap);
cert->buffer, cert->length, ssl->heap);
args->dCert->sigCtx.devId = ssl->devId; /* setup async dev */
#ifdef WOLFSSL_ASYNC_CRYPT
args->dCert->sigCtx.asyncCtx = ssl;
@@ -8330,6 +8363,12 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#ifdef OPENSSL_EXTRA
ssl->peerVerifyRet = X509_V_OK;
#endif
#if defined(SESSION_CERTS) && defined(WOLFSSL_ALT_CERT_CHAINS)
if (ssl->options.usingAltCertChain) {
AddSessionCertToChain(&ssl->session.altChain,
cert->buffer, cert->length);
}
#endif /* SESSION_CERTS && WOLFSSL_ALT_CERT_CHAINS */
args->fatal = 0;
}
else if (ret == ASN_PARSE_E || ret == BUFFER_E) {
@@ -8802,6 +8841,9 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (store->discardSessionCerts) {
WOLFSSL_MSG("Verify callback requested discard sess certs");
ssl->session.chain.count = 0;
#ifdef WOLFSSL_ALT_CERT_CHAINS
ssl->session.altChain.count = 0;
#endif
}
#endif /* SESSION_CERTS */
}
@@ -8847,6 +8889,9 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (store->discardSessionCerts) {
WOLFSSL_MSG("Verify callback requested discard sess certs");
ssl->session.chain.count = 0;
#ifdef WOLFSSL_ALT_CERT_CHAINS
ssl->session.altChain.count = 0;
#endif
}
#endif /* SESSION_CERTS */
}

View File

@@ -22832,8 +22832,31 @@ int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key,
#endif /* OPENSSL_EXTRA */
#ifdef WOLFSSL_ALT_CERT_CHAINS
int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl)
{
int isUsing = 0;
if (ssl)
isUsing = ssl->options.usingAltCertChain;
return isUsing;
}
#endif /* WOLFSSL_ALT_CERT_CHAINS */
#ifdef SESSION_CERTS
#ifdef WOLFSSL_ALT_CERT_CHAINS
/* Get peer's alternate certificate chain */
WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl)
{
WOLFSSL_ENTER("wolfSSL_get_peer_alt_chain");
if (ssl)
return &ssl->session.altChain;
return 0;
}
#endif /* WOLFSSL_ALT_CERT_CHAINS */
/* Get peer's certificate chain */
WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl)

View File

@@ -42,6 +42,8 @@ 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)
*/
#ifndef NO_ASN
@@ -6069,6 +6071,25 @@ 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)
static Signer* GetCABySubjectAndPubKey(DecodedCert* cert, void* cm)
{
Signer* ca = NULL;
if (cert->extSubjKeyIdSet)
ca = GetCA(cm, cert->extSubjKeyId);
if (ca == NULL)
ca = GetCAByName(cm, cert->subjectHash);
if (ca) {
if ((ca->pubKeySize == cert->pubKeySize) &&
(XMEMCMP(ca->publicKey, cert->publicKey, ca->pubKeySize) == 0)) {
return ca;
}
}
return NULL;
}
#endif
int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
{
int ret = 0;
@@ -6147,25 +6168,22 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
if (cert->ca == NULL)
cert->ca = GetCAByName(cm, cert->issuerHash);
/* alternate lookup method using subject and match on public key */
/* OCSP Only: alt lookup using subject and pub key w/o sig check */
#ifdef WOLFSSL_NO_TRUSTED_CERTS_VERIFY
if (cert->ca == NULL && verify == VERIFY_OCSP) {
if (cert->extSubjKeyIdSet) {
cert->ca = GetCA(cm, cert->extSubjKeyId);
}
if (cert->ca == NULL) {
cert->ca = GetCAByName(cm, cert->subjectHash);
}
cert->ca = GetCABySubjectAndPubKey(cert, cm);
if (cert->ca) {
if ((cert->ca->pubKeySize == cert->pubKeySize) &&
(XMEMCMP(cert->ca->publicKey, cert->publicKey,
cert->ca->pubKeySize) == 0)) {
ret = 0; /* success */
goto exit_pcr;
}
ret = 0; /* success */
goto exit_pcr;
}
}
#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);
#endif /* !NO_SKID */
@@ -6191,10 +6209,10 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
/* Need the CA's public key hash for OCSP */
#ifdef NO_SHA
ret = wc_Sha256Hash(cert->ca->publicKey, cert->ca->pubKeySize,
cert->issuerKeyHash);
cert->issuerKeyHash);
#else
ret = wc_ShaHash(cert->ca->publicKey, cert->ca->pubKeySize,
cert->issuerKeyHash);
cert->issuerKeyHash);
#endif /* NO_SHA */
if (ret != 0)
return ret;
@@ -6235,7 +6253,7 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm)
}
}
#ifdef WOLFSSL_NO_TRUSTED_CERTS_VERIFY
#if defined(WOLFSSL_NO_TRUSTED_CERTS_VERIFY) && !defined(NO_SKID)
exit_pcr:
#endif

View File

@@ -2640,6 +2640,9 @@ struct WOLFSSL_SESSION {
word16 haveEMS; /* ext master secret flag */
#ifdef SESSION_CERTS
WOLFSSL_X509_CHAIN chain; /* peer cert chain, static */
#ifdef WOLFSSL_ALT_CERT_CHAINS
WOLFSSL_X509_CHAIN altChain; /* peer alt cert chain, static */
#endif
#endif
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
defined(HAVE_SESSION_TICKET))
@@ -2809,14 +2812,14 @@ typedef struct Options {
wc_psk_client_callback client_psk_cb;
wc_psk_server_callback server_psk_cb;
#endif /* NO_PSK */
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
word16 havePSK:1; /* psk key set by user */
#endif /* HAVE_SESSION_TICKET || !NO_PSK */
#ifdef OPENSSL_EXTRA
unsigned long mask; /* store SSL_OP_ flags */
#endif
/* on/off or small bit flags, optimize layout */
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
word16 havePSK:1; /* psk key set by user */
#endif /* HAVE_SESSION_TICKET || !NO_PSK */
word16 sendVerify:2; /* false = 0, true = 1, sendBlank = 2 */
word16 sessionCacheOff:1;
word16 sessionCacheFlushOff:1;
@@ -2895,6 +2898,9 @@ typedef struct Options {
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
word16 sendCookie:1; /* Server creates a Cookie in HRR */
#endif
#ifdef WOLFSSL_ALT_CERT_CHAINS
word16 usingAltCertChain:1;/* Alternate cert chain was used */
#endif
/* need full byte values for this section */
byte processReply; /* nonblocking resume */

View File

@@ -1193,6 +1193,11 @@ WOLFSSL_API int wolfSSL_CTX_set_timeout(WOLFSSL_CTX*, unsigned int);
/* get wolfSSL peer X509_CHAIN */
WOLFSSL_API WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl);
#ifdef WOLFSSL_ALT_CERT_CHAINS
WOLFSSL_API int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl);
/* get wolfSSL alternate peer X509_CHAIN */
WOLFSSL_API WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl);
#endif
/* peer chain count */
WOLFSSL_API int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain);
/* index cert length */
@@ -1410,7 +1415,7 @@ WOLFSSL_API WC_RNG* wolfSSL_GetRNG(WOLFSSL*);
WOLFSSL_API int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version);
WOLFSSL_API int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version);
WOLFSSL_API int wolfSSL_GetObjectSize(void); /* object size based on build */
WOLFSSL_API int wolfSSL_CTX_GetObjectSize(void);
WOLFSSL_API int wolfSSL_CTX_GetObjectSize(void);
WOLFSSL_API int wolfSSL_METHOD_GetObjectSize(void);
WOLFSSL_API int wolfSSL_GetOutputSize(WOLFSSL*, int);
WOLFSSL_API int wolfSSL_GetMaxOutputSize(WOLFSSL*);

View File

@@ -517,10 +517,32 @@ static INLINE void ShowX509(WOLFSSL_X509* x509, const char* hdr)
#endif /* KEEP_PEER_CERT || SESSION_CERTS */
#if defined(SESSION_CERTS) && defined(SHOW_CERTS)
static INLINE void ShowX509Chain(WOLFSSL_X509_CHAIN* chain, int count,
const char* hdr)
{
int i;
int length;
unsigned char buffer[3072];
WOLFSSL_X509* chainX509;
for (i = 0; i < count; i++) {
wolfSSL_get_chain_cert_pem(chain, i, buffer, sizeof(buffer), &length);
buffer[length] = 0;
printf("\n%s: %d has length %d data = \n%s\n", hdr, i, length, buffer);
chainX509 = wolfSSL_get_chain_X509(chain, i);
if (chainX509)
ShowX509(chainX509, hdr);
else
printf("get_chain_X509 failed\n");
wolfSSL_FreeX509(chainX509);
}
}
#endif
static INLINE void showPeer(WOLFSSL* ssl)
{
WOLFSSL_CIPHER* cipher;
#ifdef HAVE_ECC
const char *name;
@@ -559,31 +581,26 @@ static INLINE void showPeer(WOLFSSL* ssl)
#endif
if (wolfSSL_session_reused(ssl))
printf("SSL reused session\n");
#ifdef WOLFSSL_ALT_CERT_CHAINS
if (wolfSSL_is_peer_alt_cert_chain(ssl))
printf("Alternate cert chain used\n");
#endif
#if defined(SESSION_CERTS) && defined(SHOW_CERTS)
{
WOLFSSL_X509_CHAIN* chain = wolfSSL_get_peer_chain(ssl);
int count = wolfSSL_get_chain_count(chain);
int i;
WOLFSSL_X509_CHAIN* chain;
for (i = 0; i < count; i++) {
int length;
unsigned char buffer[3072];
WOLFSSL_X509* chainX509;
chain = wolfSSL_get_peer_chain(ssl);
ShowX509Chain(chain, wolfSSL_get_chain_count(chain), "session cert");
wolfSSL_get_chain_cert_pem(chain,i,buffer, sizeof(buffer), &length);
buffer[length] = 0;
printf("cert %d has length %d data = \n%s\n", i, length, buffer);
chainX509 = wolfSSL_get_chain_X509(chain, i);
if (chainX509)
ShowX509(chainX509, "session cert info:");
else
printf("get_chain_X509 failed\n");
wolfSSL_FreeX509(chainX509);
#ifdef WOLFSSL_ALT_CERT_CHAINS
if (wolfSSL_is_peer_alt_cert_chain(ssl)) {
chain = wolfSSL_get_peer_alt_chain(ssl);
ShowX509Chain(chain, wolfSSL_get_chain_count(chain), "alt cert");
}
#endif
}
#endif
#endif /* SESSION_CERTS && SHOW_CERTS */
(void)ssl;
}
@@ -1234,7 +1251,7 @@ static INLINE int myVerify(int preverify, WOLFSSL_X509_STORE_CTX* store)
printf("\tPeer has no cert!\n");
#else
printf("\tPeer certs: %d\n", store->totalCerts);
#ifdef VERIFY_CALLBACK_SHOW_PEER_CERTS
#ifdef SHOW_CERTS
{ int i;
for (i=0; i<store->totalCerts; i++) {
WOLFSSL_BUFFER_INFO* cert = &store->certs[i];