From 4fe81df45c98985cbf2367cefd836a3fcc3a4829 Mon Sep 17 00:00:00 2001 From: toddouska Date: Thu, 3 May 2012 18:07:31 -0700 Subject: [PATCH] basic extneral cert manager added --- ctaocrypt/src/asn.c | 10 +- cyassl/ctaocrypt/asn.h | 6 +- cyassl/ctaocrypt/types.h | 3 +- cyassl/error.h | 5 +- cyassl/internal.h | 18 +++- cyassl/ssl.h | 9 ++ src/internal.c | 24 +++-- src/ssl.c | 207 +++++++++++++++++++++++++++++++++------ 8 files changed, 225 insertions(+), 57 deletions(-) diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 4d99584d1..dc74b909f 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -2017,13 +2017,12 @@ static int ConfirmSignature(DecodedCert* cert, const byte* key, word32 keySz, } -int ParseCert(DecodedCert* cert, int type, int verify, - Signer* signers) +int ParseCert(DecodedCert* cert, int type, int verify, void* cm) { int ret; char* ptr; - ret = ParseCertRelative(cert, type, verify, signers); + ret = ParseCertRelative(cert, type, verify, cm); if (ret < 0) return ret; @@ -2144,8 +2143,7 @@ static void IsCa(DecodedCert* cert) #endif -int ParseCertRelative(DecodedCert* cert, int type, int verify, - Signer* signers) +int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) { word32 confirmOID; int ret; @@ -2181,7 +2179,7 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, return ASN_SIG_OID_E; if (verify && type != CA_TYPE) { - Signer* ca = GetCA(signers, cert->issuerHash); + Signer* ca = GetCA(cm, cert->issuerHash); CYASSL_MSG("About to verify certificate signature"); if (ca) { diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index 148e71ce3..b17bed755 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -262,11 +262,9 @@ struct Signer { CYASSL_TEST_API void InitDecodedCert(DecodedCert*, byte*, word32, void*); CYASSL_TEST_API void FreeDecodedCert(DecodedCert*); -CYASSL_TEST_API int ParseCert(DecodedCert*, int type, int verify, - Signer* signer); +CYASSL_TEST_API int ParseCert(DecodedCert*, int type, int verify, void* cm); -CYASSL_LOCAL int ParseCertRelative(DecodedCert*, int type, int verify, - Signer* signer); +CYASSL_LOCAL int ParseCertRelative(DecodedCert*, int type, int verify,void* cm); CYASSL_LOCAL int DecodeToKey(DecodedCert*, int verify); CYASSL_LOCAL word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, diff --git a/cyassl/ctaocrypt/types.h b/cyassl/ctaocrypt/types.h index 9e1c829bf..441be4105 100644 --- a/cyassl/ctaocrypt/types.h +++ b/cyassl/ctaocrypt/types.h @@ -200,7 +200,8 @@ enum { DYNAMIC_TYPE_SSL = 17, DYNAMIC_TYPE_CTX = 18, DYNAMIC_TYPE_WRITEV = 19, - DYNAMIC_TYPE_OPENSSL = 20 + DYNAMIC_TYPE_OPENSSL = 20, + DYNAMIC_TYPE_CERT_MANAGER = 21 }; /* stack protection */ diff --git a/cyassl/error.h b/cyassl/error.h index f22c56865..70eefcd40 100644 --- a/cyassl/error.h +++ b/cyassl/error.h @@ -91,11 +91,12 @@ enum CyaSSL_ErrorCodes { BAD_MUTEX_ERROR = -256, /* Bad mutex */ NOT_CA_ERROR = -257, /* Not a CA cert error */ BAD_PATH_ERROR = -258, /* Bad path for opendir */ + BAD_CERT_MANAGER_ERROR = -259, /* Bad Cert Manager */ /* add strings to SetErrorString !!!!! */ /* begin negotiation parameter errors */ - UNSUPPORTED_SUITE = -260, /* unsupported cipher suite */ - MATCH_SUITE_ERROR = -261 /* can't match cipher suite */ + UNSUPPORTED_SUITE = -270, /* unsupported cipher suite */ + MATCH_SUITE_ERROR = -271 /* can't match cipher suite */ /* end negotiation parameter errors only 10 for now */ /* add strings to SetErrorString !!!!! */ }; diff --git a/cyassl/internal.h b/cyassl/internal.h index f1a8b0670..79913cb06 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -619,6 +619,15 @@ CYASSL_LOCAL int LockMutex(CyaSSL_Mutex*); CYASSL_LOCAL int UnLockMutex(CyaSSL_Mutex*); +/* CyaSSL Certificate Manager */ +struct CYASSL_CERT_MANAGER { + Signer* caList; /* the CA signer list */ + CyaSSL_Mutex caLock; /* CA list lock */ + CallbackCACache caCacheCallback; /* CA cache addition callback */ + void* heap; /* heap helper */ +}; + + /* CyaSSL context type */ struct CYASSL_CTX { CYASSL_METHOD* method; @@ -630,7 +639,7 @@ struct CYASSL_CTX { buffer privateKey; buffer serverDH_P; buffer serverDH_G; - Signer* caList; /* CYASSL_CTX owns this, SSL will reference */ + CYASSL_CERT_MANAGER* cm; /* our cert manager, ctx owns SSL will use */ Suites suites; void* heap; /* for user memory overrides */ byte verifyPeer; @@ -648,7 +657,6 @@ struct CYASSL_CTX { byte groupMessages; /* group handshake messages before sending */ CallbackIORecv CBIORecv; CallbackIOSend CBIOSend; - CallbackCACache caCacheCallback; /* CA cache addition callback */ VerifyCallback verifyCallback; /* cert verification callback */ word32 timeout; /* session timeout */ #ifdef HAVE_ECC @@ -680,9 +688,9 @@ CYASSL_LOCAL int ProcessOldClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, word32 inSz, word16 sz); CYASSL_LOCAL -int AddCA(CYASSL_CTX* ctx, buffer der, int force); +int AddCA(CYASSL_CERT_MANAGER* ctx, buffer der, int type, int verify); CYASSL_LOCAL -int AlreadySigner(CYASSL_CTX* ctx, byte* hash); +int AlreadySigner(CYASSL_CERT_MANAGER* cm, byte* hash); /* All cipher suite related info */ typedef struct CipherSpecs { @@ -1257,7 +1265,7 @@ CYASSL_LOCAL int IsAtLeastTLSv1_2(const CYASSL* ssl); CYASSL_LOCAL void ShrinkInputBuffer(CYASSL* ssl, int forcedFree); CYASSL_LOCAL void ShrinkOutputBuffer(CYASSL* ssl); CYASSL_LOCAL int SendHelloVerifyRequest(CYASSL* ssl); -CYASSL_LOCAL Signer* GetCA(Signer* signers, byte* hash); +CYASSL_LOCAL Signer* GetCA(void* cm, byte* hash); CYASSL_LOCAL void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender); #ifndef NO_TLS diff --git a/cyassl/ssl.h b/cyassl/ssl.h index c850aa09b..3b9c8e42f 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -65,6 +65,7 @@ typedef struct CYASSL_X509 CYASSL_X509; typedef struct CYASSL_X509_NAME CYASSL_X509_NAME; typedef struct CYASSL_X509_CHAIN CYASSL_X509_CHAIN; +typedef struct CYASSL_CERT_MANAGER CYASSL_CERT_MANAGER; /* redeclare guard */ #define CYASSL_TYPES_DEFINED @@ -776,6 +777,14 @@ typedef void (*CallbackCACache)(unsigned char* der, int sz, int type); CYASSL_API void CyaSSL_CTX_SetCACb(CYASSL_CTX*, CallbackCACache); +CYASSL_API CYASSL_CERT_MANAGER* CyaSSL_CertManagerNew(void); +CYASSL_API void CyaSSL_CertManagerFree(CYASSL_CERT_MANAGER*); + +CYASSL_API int CyaSSL_CertManagerLoadCA(CYASSL_CERT_MANAGER*, const char* f, + const char* d); +CYASSL_API int CyaSSL_CertManagerVerify(CYASSL_CERT_MANAGER*, const char* f, + int format); + #ifdef CYASSL_CALLBACKS /* used internally by CyaSSL while OpenSSL types aren't */ diff --git a/src/internal.c b/src/internal.c index 1d9633096..adf5bd1ad 100644 --- a/src/internal.c +++ b/src/internal.c @@ -364,9 +364,8 @@ int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_METHOD* method) #endif ctx->partialWrite = 0; ctx->verifyCallback = 0; - ctx->caCacheCallback = 0; - ctx->caList = 0; + ctx->cm = CyaSSL_CertManagerNew(); #ifdef HAVE_NTRU if (method->side == CLIENT_END) ctx->haveNTRU = 1; /* always on cliet side */ @@ -395,6 +394,10 @@ int InitSSL_Ctx(CYASSL_CTX* ctx, CYASSL_METHOD* method) CYASSL_MSG("Mutex error on CTX init"); return BAD_MUTEX_ERROR; } + if (ctx->cm == NULL) { + CYASSL_MSG("Bad Cert Manager New"); + return BAD_CERT_MANAGER_ERROR; + } return 0; } @@ -409,7 +412,7 @@ void SSL_CtxResourceFree(CYASSL_CTX* ctx) XFREE(ctx->certChain.buffer, ctx->heap, DYNAMIC_TYPE_CERT); XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD); - FreeSigners(ctx->caList, ctx->heap); + CyaSSL_CertManagerFree(ctx->cm); } @@ -858,7 +861,7 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->options.certOnly = 0; ssl->options.groupMessages = ctx->groupMessages; - /* ctx still owns certificate, certChain, key, dh, and caList buffers */ + /* ctx still owns certificate, certChain, key, dh, and cm */ ssl->buffers.certificate = ctx->certificate; ssl->buffers.certChain = ctx->certChain; ssl->buffers.key = ctx->privateKey; @@ -1613,7 +1616,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, - ssl->ctx->caList); + ssl->ctx->cm); if (ret == 0 && dCert.isCA == 0) { CYASSL_MSG("Chain cert is not a CA, not adding as one"); (void)ret; @@ -1622,7 +1625,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) CYASSL_MSG("Chain cert not verified by option, not adding as CA"); (void)ret; } - else if (ret == 0 && !AlreadySigner(ssl->ctx, dCert.subjectHash)) { + else if (ret == 0 && !AlreadySigner(ssl->ctx->cm, dCert.subjectHash)) { buffer add; add.length = myCert.length; add.buffer = (byte*)XMALLOC(myCert.length, ssl->heap, @@ -1633,7 +1636,8 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) return MEMORY_E; XMEMCPY(add.buffer, myCert.buffer, myCert.length); - ret = AddCA(ssl->ctx, add, CYASSL_CHAIN_CA); + ret = AddCA(ssl->ctx->cm, add, CYASSL_CHAIN_CA, + ssl->ctx->verifyPeer); if (ret == 1) ret = 0; /* SSL_SUCCESS for external */ } else if (ret != 0) { @@ -1662,7 +1666,7 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) InitDecodedCert(&dCert, myCert.buffer, myCert.length, ssl->heap); ret = ParseCertRelative(&dCert, CERT_TYPE, !ssl->options.verifyNone, - ssl->ctx->caList); + ssl->ctx->cm); if (ret == 0) { CYASSL_MSG("Verified Peer's cert"); fatal = 0; @@ -3482,6 +3486,10 @@ void SetErrorString(int error, char* str) XSTRNCPY(str, "Bad path for opendir error", max); break; + case BAD_CERT_MANAGER_ERROR: + XSTRNCPY(str, "Bad Cert Manager error", max); + break; + default : XSTRNCPY(str, "unknown error number", max); } diff --git a/src/ssl.c b/src/ssl.c index 705cd2f60..182a08548 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -362,6 +362,45 @@ void CyaSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len) } +CYASSL_CERT_MANAGER* CyaSSL_CertManagerNew(void) +{ + CYASSL_CERT_MANAGER* cm = NULL; + + CYASSL_ENTER("CyaSSL_CertManagerNew"); + + cm = (CYASSL_CERT_MANAGER*) XMALLOC(sizeof(CYASSL_CERT_MANAGER), 0, + DYNAMIC_TYPE_CERT_MANAGER); + if (cm) { + cm->caList = NULL; + cm->heap = NULL; + cm->caCacheCallback = NULL; + + if (InitMutex(&cm->caLock) != 0) { + CYASSL_MSG("Bad mutex init"); + CyaSSL_CertManagerFree(cm); + return NULL; + } + } + + return cm; +} + + +void CyaSSL_CertManagerFree(CYASSL_CERT_MANAGER* cm) +{ + CYASSL_ENTER("CyaSSL_CertManagerFree"); + + if (cm) { + FreeSigners(cm->caList, NULL); + FreeMutex(&cm->caLock); + XFREE(cm, NULL, DYNAMIC_TYPE_CERT_MANAGER); + } + +} + + + + #ifndef NO_FILESYSTEM void CyaSSL_ERR_print_errors_fp(FILE* fp, int err) @@ -423,17 +462,15 @@ int CyaSSL_set_group_messages(CYASSL* ssl) } -static CyaSSL_Mutex ca_mutex; /* CA signers mutex */ - /* does CA already exist on signer list */ -int AlreadySigner(CYASSL_CTX* ctx, byte* hash) +int AlreadySigner(CYASSL_CERT_MANAGER* cm, byte* hash) { Signer* signers; int ret = 0; - if (LockMutex(&ca_mutex) != 0) + if (LockMutex(&cm->caLock) != 0) return ret; - signers = ctx->caList; + signers = cm->caList; while (signers) { if (XMEMCMP(hash, signers->hash, SHA_DIGEST_SIZE) == 0) { ret = 1; @@ -441,18 +478,25 @@ int AlreadySigner(CYASSL_CTX* ctx, byte* hash) } signers = signers->next; } - UnLockMutex(&ca_mutex); + UnLockMutex(&cm->caLock); return ret; } /* return CA if found, otherwise NULL */ -Signer* GetCA(Signer* signers, byte* hash) +Signer* GetCA(void* vp, byte* hash) { - Signer* ret = 0; + CYASSL_CERT_MANAGER* cm = (CYASSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; - if (LockMutex(&ca_mutex) != 0) + if (cm == NULL) + return NULL; + + signers = cm->caList; + + if (LockMutex(&cm->caLock) != 0) return ret; while (signers) { if (XMEMCMP(hash, signers->hash, SHA_DIGEST_SIZE) == 0) { @@ -461,7 +505,7 @@ Signer* GetCA(Signer* signers, byte* hash) } signers = signers->next; } - UnLockMutex(&ca_mutex); + UnLockMutex(&cm->caLock); return ret; } @@ -470,28 +514,28 @@ Signer* GetCA(Signer* signers, byte* hash) /* owns der, internal now uses too */ /* 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 AddCA(CYASSL_CERT_MANAGER* cm, buffer der, int type, int verify) { int ret; DecodedCert cert; Signer* signer = 0; CYASSL_MSG("Adding a CA"); - InitDecodedCert(&cert, der.buffer, der.length, ctx->heap); - ret = ParseCert(&cert, CA_TYPE, ctx->verifyPeer, 0); + InitDecodedCert(&cert, der.buffer, der.length, cm->heap); + ret = ParseCert(&cert, CA_TYPE, verify, cm); CYASSL_MSG(" Parsed new CA"); 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; } - else if (ret == 0 && AlreadySigner(ctx, cert.subjectHash)) { + else if (ret == 0 && AlreadySigner(cm, cert.subjectHash)) { CYASSL_MSG(" Already have this CA, not adding again"); (void)ret; } else if (ret == 0) { /* take over signer parts */ - signer = MakeSigner(ctx->heap); + signer = MakeSigner(cm->heap); if (!signer) ret = MEMORY_ERROR; else { @@ -505,17 +549,17 @@ int AddCA(CYASSL_CTX* ctx, buffer der, int type) cert.publicKey = 0; /* don't free here */ cert.subjectCN = 0; - if (LockMutex(&ca_mutex) == 0) { - signer->next = ctx->caList; - ctx->caList = signer; /* takes ownership */ - UnLockMutex(&ca_mutex); - if (ctx->caCacheCallback) - ctx->caCacheCallback(der.buffer, (int)der.length, type); + if (LockMutex(&cm->caLock) == 0) { + signer->next = cm->caList; + cm->caList = signer; /* takes ownership */ + UnLockMutex(&cm->caLock); + if (cm->caCacheCallback) + cm->caCacheCallback(der.buffer, (int)der.length, type); } else { CYASSL_MSG(" CA Mutex Lock failed"); ret = BAD_MUTEX_ERROR; - FreeSigners(signer, ctx->heap); + FreeSigners(signer, cm->heap); } } } @@ -932,7 +976,8 @@ int AddCA(CYASSL_CTX* ctx, buffer der, int type) #endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ if (type == CA_TYPE) - return AddCA(ctx, der, CYASSL_USER_CA); /* takes der over */ + return AddCA(ctx->cm, der, CYASSL_USER_CA, ctx->verifyPeer); + /* takes der over */ else if (type == CERT_TYPE) { if (ssl) { if (ssl->buffers.weOwnCert && ssl->buffers.certificate.buffer) @@ -1201,6 +1246,105 @@ int CyaSSL_CTX_load_verify_locations(CYASSL_CTX* ctx, const char* file, } +/* Verify the ceritficate, 1 for success, < 0 for error */ +int CyaSSL_CertManagerVerify(CYASSL_CERT_MANAGER* cm, const char* fname, + int format) +{ + int ret = SSL_FATAL_ERROR; + int eccKey = 0; /* not used */ + DecodedCert cert; + + byte staticBuffer[FILE_BUFFER_SIZE]; + byte* myBuffer = staticBuffer; + int dynamic = 0; + long sz = 0; + buffer der; + XFILE* file = XFOPEN(fname, "rb"); + + if (!file) return SSL_BAD_FILE; + XFSEEK(file, 0, XSEEK_END); + sz = XFTELL(file); + XREWIND(file); + + der.buffer = NULL; + + if (sz > (long)sizeof(staticBuffer)) { + CYASSL_MSG("Getting dynamic buffer"); + myBuffer = (byte*) XMALLOC(sz, cm->heap, DYNAMIC_TYPE_FILE); + if (myBuffer == NULL) { + XFCLOSE(file); + return SSL_BAD_FILE; + } + dynamic = 1; + } + + if ( (ret = XFREAD(myBuffer, sz, 1, file)) < 0) + ret = SSL_BAD_FILE; + else { + ret = 0; /* ok */ + if (format == SSL_FILETYPE_PEM) { + EncryptedInfo info; + + info.set = 0; + info.ctx = NULL; + info.consumed = 0; + ret = PemToDer(myBuffer, sz, CERT_TYPE, &der, cm->heap, &info, + &eccKey); + InitDecodedCert(&cert, der.buffer, der.length, cm->heap); + + } + else + InitDecodedCert(&cert, myBuffer, sz, cm->heap); + + if (ret == 0) + ret = ParseCertRelative(&cert, CERT_TYPE, 1, cm); + } + + FreeDecodedCert(&cert); + XFREE(der.buffer, cm->heap, DYNAMIC_TYPE_CERT); + XFCLOSE(file); + if (dynamic) XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE); + + if (ret == 0) + return SSL_SUCCESS; + return ret; +} + + +/* like load verify locations, 1 for success, < 0 for error */ +int CyaSSL_CertManagerLoadCA(CYASSL_CERT_MANAGER* cm, const char* file, + const char* path) +{ + int ret = SSL_FATAL_ERROR; + CYASSL_CTX* tmp; + + CYASSL_ENTER("CyaSSL_CertManagerLoadCA"); + + if (cm == NULL) { + CYASSL_MSG("No CertManager error"); + return ret; + } + tmp = CyaSSL_CTX_new(CyaSSLv3_client_method()); + + if (tmp == NULL) { + CYASSL_MSG("CTX new failed"); + return ret; + } + + /* for tmp use */ + CyaSSL_CertManagerFree(tmp->cm); + tmp->cm = cm; + + ret = CyaSSL_CTX_load_verify_locations(tmp, file, path); + + /* don't loose our good one */ + tmp->cm = NULL; + CyaSSL_CTX_free(tmp); + + return ret; +} + + #ifdef CYASSL_DER_LOAD /* Add format parameter to allow DER load of CA files */ @@ -1580,8 +1724,8 @@ 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; + if (ctx && ctx->cm) + ctx->cm->caCacheCallback = cb; } @@ -2126,6 +2270,7 @@ int CyaSSL_set_cipher_list(CYASSL* ssl, const char* list) /* prevent multiple mutex initializations */ static volatile int initRefCount = 0; +static CyaSSL_Mutex count_mutex; /* init ref count mutex */ int CyaSSL_Init(void) { @@ -2138,13 +2283,13 @@ int CyaSSL_Init(void) if (InitMutex(&session_mutex) != 0) ret = BAD_MUTEX_ERROR; #endif - if (InitMutex(&ca_mutex) != 0) + if (InitMutex(&count_mutex) != 0) ret = BAD_MUTEX_ERROR; } if (ret == 0) { - LockMutex(&ca_mutex); + LockMutex(&count_mutex); initRefCount++; - UnLockMutex(&ca_mutex); + UnLockMutex(&count_mutex); } return ret; @@ -2158,13 +2303,13 @@ int CyaSSL_Cleanup(void) CYASSL_ENTER("CyaSSL_Cleanup"); - LockMutex(&ca_mutex); + LockMutex(&count_mutex); release = initRefCount-- == 1; if (initRefCount < 0) initRefCount = 0; - UnLockMutex(&ca_mutex); + UnLockMutex(&count_mutex); if (!release) return ret; @@ -2173,7 +2318,7 @@ int CyaSSL_Cleanup(void) if (FreeMutex(&session_mutex) != 0) ret = BAD_MUTEX_ERROR; #endif - if (FreeMutex(&ca_mutex) != 0) + if (FreeMutex(&count_mutex) != 0) ret = BAD_MUTEX_ERROR; return ret;