diff --git a/cyassl/internal.h b/cyassl/internal.h index fb773239e..e5cd2b8db 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -617,7 +617,8 @@ struct CYASSL_CTX { byte groupMessages; /* group handshake messages before sending */ CallbackIORecv CBIORecv; CallbackIOSend CBIOSend; - VerifyCallback verifyCallback; /* cert verification callback */ + CallbackCACache caCacheCallback; /* CA cache addition callback */ + VerifyCallback verifyCallback; /* cert verification callback */ #ifndef NO_PSK byte havePSK; /* psk key set by user */ psk_client_callback client_psk_cb; /* client callback */ diff --git a/cyassl/ssl.h b/cyassl/ssl.h index a5ae1f003..f1b81ef4a 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -744,6 +744,16 @@ CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX*, CallbackIOSend); CYASSL_API void CyaSSL_SetIOReadCtx(CYASSL* ssl, void *ctx); CYASSL_API void CyaSSL_SetIOWriteCtx(CYASSL* ssl, void *ctx); +/* CA cache callbacks */ +enum { + CYASSL_USER_CA = 1, /* user added as trusted */ + CYASSL_CHAIN_CA = 2 /* added to cache from trusted chain */ +}; + +typedef void (*CallbackCACache)(unsigned char* der, int sz, int type); + +CYASSL_API void CyaSSL_CTX_SetCACb(CYASSL_CTX*, CallbackCACache); + #ifdef CYASSL_CALLBACKS diff --git a/src/internal.c b/src/internal.c index d370a40a8..fa6a213c8 100644 --- a/src/internal.c +++ b/src/internal.c @@ -358,6 +358,7 @@ int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_METHOD* method) #endif ctx->partialWrite = 0; ctx->verifyCallback = 0; + ctx->caCacheCallback = 0; ctx->caList = 0; #ifdef HAVE_NTRU @@ -1561,7 +1562,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) return MEMORY_E; XMEMCPY(add.buffer, myCert.buffer, myCert.length); - ret = AddCA(ssl->ctx, add, 0); /* never force chain add */ + ret = AddCA(ssl->ctx, add, CYASSL_CHAIN_CA); if (ret == 1) ret = 0; /* SSL_SUCCESS for external */ } else if (ret != 0) { diff --git a/src/ssl.c b/src/ssl.c index 3150afb14..5e7aa66b7 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -455,9 +455,9 @@ Signer* GetCA(Signer* signers, byte* hash) /* owns der, internal now uses too */ -/* force flag means override CA check, ok for root certs that user requested - if they're from a chain we don't want to force, ever */ -int AddCA(CYASSL_CTX* ctx, buffer der, int force) +/* type flag ids from user or from chain received during verify + don't allow chain ones to be added w/o isCA extension */ +int AddCA(CYASSL_CTX* ctx, buffer der, int type) { int ret; DecodedCert cert; @@ -468,7 +468,7 @@ int AddCA(CYASSL_CTX* ctx, buffer der, int force) ret = ParseCert(&cert, CA_TYPE, ctx->verifyPeer, 0); CYASSL_MSG(" Parsed new CA"); - if (ret == 0 && cert.isCA == 0 && !force) { + if (ret == 0 && cert.isCA == 0 && type != CYASSL_USER_CA) { CYASSL_MSG(" Can't add as CA if not actually one"); ret = NOT_CA_ERROR; } @@ -496,6 +496,8 @@ int AddCA(CYASSL_CTX* ctx, buffer der, int force) signer->next = ctx->caList; ctx->caList = signer; /* takes ownership */ UnLockMutex(&ca_mutex); + if (ctx->caCacheCallback) + ctx->caCacheCallback(der.buffer, (int)der.length, type); } else { CYASSL_MSG(" CA Mutex Lock failed"); @@ -912,7 +914,7 @@ int AddCA(CYASSL_CTX* ctx, buffer der, int force) #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ if (type == CA_TYPE) - return AddCA(ctx, der, 1); /* takes der over, force user request */ + return AddCA(ctx, der, CYASSL_USER_CA); /* takes der over */ else if (type == CERT_TYPE) { if (ssl) { if (ssl->buffers.weOwnCert && ssl->buffers.certificate.buffer) @@ -1445,6 +1447,14 @@ void CyaSSL_set_verify(CYASSL* ssl, int mode, VerifyCallback vc) } +/* store context CA Cache addition callback */ +void CyaSSL_CTX_SetCACb(CYASSL_CTX* ctx, CallbackCACache cb) +{ + if (ctx && cb) + ctx->caCacheCallback = cb; +} + + #ifndef NO_SESSION_CACHE CYASSL_SESSION* CyaSSL_get_session(CYASSL* ssl)