diff --git a/cyassl/ctaocrypt/types.h b/cyassl/ctaocrypt/types.h index adf69fdf1..a0a78812d 100644 --- a/cyassl/ctaocrypt/types.h +++ b/cyassl/ctaocrypt/types.h @@ -242,7 +242,8 @@ enum { DYNAMIC_TYPE_TMP_BUFFER = 38, DYNAMIC_TYPE_DTLS_MSG = 39, DYNAMIC_TYPE_CAVIUM_TMP = 40, - DYNAMIC_TYPE_CAVIUM_RSA = 41 + DYNAMIC_TYPE_CAVIUM_RSA = 41, + DYNAMIC_TYPE_X509 = 42 }; /* stack protection */ diff --git a/cyassl/internal.h b/cyassl/internal.h index 1a1a53dc8..aae92855b 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1536,6 +1536,7 @@ struct CYASSL_X509 { buffer derCert; /* may need */ DNS_entry* altNames; /* alt names list */ DNS_entry* altNamesNext; /* hint for retrieval */ + byte dynamicMemory; /* dynamic memory flag */ }; @@ -1885,6 +1886,9 @@ CYASSL_LOCAL int GrowInputBuffer(CYASSL* ssl, int size, int usedLength); CYASSL_LOCAL word32 LowResTimer(void); +CYASSL_LOCAL void InitX509(CYASSL_X509*, int); +CYASSL_LOCAL void FreeX509(CYASSL_X509*); +CYASSL_LOCAL int CopyDecodedToX509(CYASSL_X509*, DecodedCert*); #ifdef __cplusplus diff --git a/cyassl/ssl.h b/cyassl/ssl.h index cfb8d2f91..b50b31c09 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -714,6 +714,10 @@ CYASSL_API int CyaSSL_get_chain_count(CYASSL_X509_CHAIN* chain); CYASSL_API int CyaSSL_get_chain_length(CYASSL_X509_CHAIN*, int idx); /* index cert */ CYASSL_API unsigned char* CyaSSL_get_chain_cert(CYASSL_X509_CHAIN*, int idx); +/* index cert in X509 */ +CYASSL_API CYASSL_X509* CyaSSL_get_chain_X509(CYASSL_X509_CHAIN*, int idx); +/* free X509 */ +CYASSL_API void CyaSSL_FreeX509(CYASSL_X509*); /* get index cert in PEM */ CYASSL_API int CyaSSL_get_chain_cert_pem(CYASSL_X509_CHAIN*, int idx, unsigned char* buffer, int inLen, int* outLen); diff --git a/cyassl/test.h b/cyassl/test.h index b7c3a0f62..910a2b530 100644 --- a/cyassl/test.h +++ b/cyassl/test.h @@ -263,49 +263,53 @@ static INLINE int PasswordCallBack(char* passwd, int sz, int rw, void* userdata) #endif +#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) + +static INLINE void ShowX509(CYASSL_X509* x509, const char* hdr) +{ + char* altName; + char* issuer = CyaSSL_X509_NAME_oneline( + CyaSSL_X509_get_issuer_name(x509), 0, 0); + char* subject = CyaSSL_X509_NAME_oneline( + CyaSSL_X509_get_subject_name(x509), 0, 0); + byte serial[32]; + int ret; + int sz = sizeof(serial); + + printf("%s\n issuer : %s\n subject: %s\n", hdr, issuer, subject); + + while ( (altName = CyaSSL_X509_get_next_altname(x509)) ) + printf(" altname = %s\n", altName); + + ret = CyaSSL_X509_get_serial_number(x509, serial, &sz); + if (ret == SSL_SUCCESS) { + int i; + int strLen; + char serialMsg[80]; + + /* testsuite has multiple threads writing to stdout, get output + message ready to write once */ + strLen = sprintf(serialMsg, " serial number"); + for (i = 0; i < sz; i++) + sprintf(serialMsg + strLen + (i*3), ":%02x ", serial[i]); + printf("%s\n", serialMsg); + } + + XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL); + XFREE(issuer, 0, DYNAMIC_TYPE_OPENSSL); +} + +#endif /* KEEP_PEER_CERT || SESSION_CERTS */ + + static INLINE void showPeer(CYASSL* ssl) { CYASSL_CIPHER* cipher; #ifdef KEEP_PEER_CERT - CYASSL_X509* peer = CyaSSL_get_peer_certificate(ssl); - if (peer) { -#ifdef OPENSSL_EXTRA - char* altName; - char* issuer = CyaSSL_X509_NAME_oneline( - CyaSSL_X509_get_issuer_name(peer), 0, 0); - char* subject = CyaSSL_X509_NAME_oneline( - CyaSSL_X509_get_subject_name(peer), 0, 0); - byte serial[32]; - int ret; - int sz = sizeof(serial); - - printf("peer's cert info:\n issuer : %s\n subject: %s\n", issuer, - subject); - - while ( (altName = CyaSSL_X509_get_next_altname(peer)) ) - printf(" altname = %s\n", altName); - - ret = CyaSSL_X509_get_serial_number(peer, serial, &sz); - if (ret == SSL_SUCCESS) { - int i; - int strLen; - char serialMsg[80]; - - /* testsuite has multiple threads writing to stdout, get output - message ready to write once */ - strLen = sprintf(serialMsg, " serial number"); - for (i = 0; i < sz; i++) - sprintf(serialMsg + strLen + (i*3), ":%02x ", serial[i]); - printf("%s\n", serialMsg); - } - - XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL); - XFREE(issuer, 0, DYNAMIC_TYPE_OPENSSL); -#else - printf("peer has a cert!\n"); -#endif - } + CYASSL_X509* peer = CyaSSL_get_peer_certificate(ssl); + if (peer) + ShowX509(peer, "peer's cert info:"); else printf("peer has no cert!\n"); #endif @@ -323,10 +327,18 @@ static INLINE void showPeer(CYASSL* ssl) for (i = 0; i < count; i++) { int length; unsigned char buffer[3072]; + CYASSL_X509* chainX509; CyaSSL_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 = CyaSSL_get_chain_X509(chain, i); + if (chainX509) + ShowX509(chainX509, "session cert info:"); + else + printf("get_chain_X509 failed\n"); + CyaSSL_FreeX509(chainX509); } } #endif diff --git a/src/internal.c b/src/internal.c index a3511181c..ff5182d3a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1182,6 +1182,30 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveRSA, byte havePSK, } +/* Initialize CyaSSL X509 type */ +void InitX509(CYASSL_X509* x509, int dynamicFlag) +{ + x509->derCert.buffer = NULL; + x509->altNames = NULL; + x509->altNamesNext = NULL; + x509->dynamicMemory = dynamicFlag; +} + + +/* Free CyaSSL X509 type */ +void FreeX509(CYASSL_X509* x509) +{ + if (x509 == NULL) + return; + + XFREE(x509->derCert.buffer, NULL, DYNAMIC_TYPE_CERT); + if (x509->altNames) + FreeAltNames(x509->altNames, NULL); + if (x509->dynamicMemory) + XFREE(x509, NULL, DYNAMIC_TYPE_X509); +} + + /* init everything to 0, NULL, default values before calling anything that may fail so that desctructor has a "good" state to cleanup */ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) @@ -1231,9 +1255,7 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->buffers.plainSz = 0; #ifdef KEEP_PEER_CERT - ssl->peerCert.derCert.buffer = NULL; - ssl->peerCert.altNames = NULL; - ssl->peerCert.altNamesNext = NULL; + InitX509(&ssl->peerCert, 0); #endif #ifdef HAVE_ECC @@ -1590,9 +1612,7 @@ void SSL_ResourceFree(CYASSL* ssl) ssl->buffers.dtlsCtx.peer.sa = NULL; #endif #if defined(KEEP_PEER_CERT) || defined(GOAHEAD_WS) - XFREE(ssl->peerCert.derCert.buffer, ssl->heap, DYNAMIC_TYPE_CERT); - if (ssl->peerCert.altNames) - FreeAltNames(ssl->peerCert.altNames, ssl->heap); + FreeX509(&ssl->peerCert); #endif #if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS) CyaSSL_BIO_free(ssl->biord); @@ -2798,6 +2818,54 @@ static int CheckAltNames(DecodedCert* dCert, char* domain) } +#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) + +/* Copy parts X509 needs from Decoded cert, 0 on success */ +int CopyDecodedToX509(CYASSL_X509* x509, DecodedCert* dCert) +{ + int ret = 0; + + if (x509 == NULL || dCert == NULL) + return BAD_FUNC_ARG; + + XSTRNCPY(x509->issuer.name, dCert->issuer, ASN_NAME_MAX); + x509->issuer.name[ASN_NAME_MAX - 1] = '\0'; + x509->issuer.sz = (int)XSTRLEN(x509->issuer.name) + 1; + + XSTRNCPY(x509->subject.name, dCert->subject, ASN_NAME_MAX); + x509->subject.name[ASN_NAME_MAX - 1] = '\0'; + x509->subject.sz = (int)XSTRLEN(x509->subject.name) + 1; + + XMEMCPY(x509->serial, dCert->serial, EXTERNAL_SERIAL_SIZE); + x509->serialSz = dCert->serialSz; + if (dCert->subjectCNLen < ASN_NAME_MAX) { + XMEMCPY(x509->subjectCN, dCert->subjectCN, dCert->subjectCNLen); + x509->subjectCN[dCert->subjectCNLen] = '\0'; + } + else + x509->subjectCN[0] = '\0'; + + /* store cert for potential retrieval */ + x509->derCert.buffer = (byte*)XMALLOC(dCert->maxIdx, NULL, + DYNAMIC_TYPE_CERT); + if (x509->derCert.buffer == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(x509->derCert.buffer, dCert->source, dCert->maxIdx); + x509->derCert.length = dCert->maxIdx; + } + + x509->altNames = dCert->altNames; + dCert->altNames = NULL; /* takes ownership */ + x509->altNamesNext = x509->altNames; /* index hint */ + + return ret; +} + +#endif /* KEEP_PEER_CERT || SESSION_CERTS */ + + static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) { word32 listSz, i = *inOutIdx; @@ -2974,39 +3042,12 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) #endif /* HAVE_CRL */ #ifdef KEEP_PEER_CERT + { /* set X509 format for peer cert even if fatal */ - XSTRNCPY(ssl->peerCert.issuer.name, dCert.issuer, ASN_NAME_MAX); - ssl->peerCert.issuer.name[ASN_NAME_MAX - 1] = '\0'; - ssl->peerCert.issuer.sz = (int)XSTRLEN(ssl->peerCert.issuer.name) + 1; - - XSTRNCPY(ssl->peerCert.subject.name, dCert.subject, ASN_NAME_MAX); - ssl->peerCert.subject.name[ASN_NAME_MAX - 1] = '\0'; - ssl->peerCert.subject.sz = (int)XSTRLEN(ssl->peerCert.subject.name) + 1; - - XMEMCPY(ssl->peerCert.serial, dCert.serial, EXTERNAL_SERIAL_SIZE); - ssl->peerCert.serialSz = dCert.serialSz; - if (dCert.subjectCNLen < ASN_NAME_MAX) { - XMEMCPY(ssl->peerCert.subjectCN,dCert.subjectCN,dCert.subjectCNLen); - ssl->peerCert.subjectCN[dCert.subjectCNLen] = '\0'; - } - else - ssl->peerCert.subjectCN[0] = '\0'; - - /* store cert for potential retrieval */ - ssl->peerCert.derCert.buffer = (byte*)XMALLOC(myCert.length, ssl->heap, - DYNAMIC_TYPE_CERT); - if (ssl->peerCert.derCert.buffer == NULL) { - ret = MEMORY_E; + int copyRet = CopyDecodedToX509(&ssl->peerCert, &dCert); + if (copyRet == MEMORY_E) fatal = 1; } - else { - XMEMCPY(ssl->peerCert.derCert.buffer, myCert.buffer, myCert.length); - ssl->peerCert.derCert.length = myCert.length; - } - - ssl->peerCert.altNames = dCert.altNames; - dCert.altNames = NULL; /* takes ownership */ - ssl->peerCert.altNamesNext = ssl->peerCert.altNames; /* index hint */ #endif if (fatal) { diff --git a/src/ssl.c b/src/ssl.c index 3ed0f3200..69f7e8541 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -4117,65 +4117,6 @@ int CyaSSL_set_compression(CYASSL* ssl) } - /* return the next, if any, altname from the peer cert */ - char* CyaSSL_X509_get_next_altname(CYASSL_X509* cert) - { - char* ret = NULL; - CYASSL_ENTER("CyaSSL_X509_get_next_altname"); - - /* don't have any to work with */ - if (cert == NULL || cert->altNames == NULL) - return NULL; - - /* already went through them */ - if (cert->altNamesNext == NULL) - return NULL; - - ret = cert->altNamesNext->name; - cert->altNamesNext = cert->altNamesNext->next; - - return ret; - } - - - CYASSL_X509_NAME* CyaSSL_X509_get_issuer_name(CYASSL_X509* cert) - { - CYASSL_ENTER("X509_get_issuer_name"); - return &cert->issuer; - } - - - CYASSL_X509_NAME* CyaSSL_X509_get_subject_name(CYASSL_X509* cert) - { - CYASSL_ENTER("X509_get_subject_name"); - return &cert->subject; - } - - - /* copy name into in buffer, at most sz bytes, if buffer is null will - malloc buffer, call responsible for freeing */ - char* CyaSSL_X509_NAME_oneline(CYASSL_X509_NAME* name, char* in, int sz) - { - int copySz = min(sz, name->sz); - - CYASSL_ENTER("CyaSSL_X509_NAME_oneline"); - if (!name->sz) return in; - - if (!in) { - in = (char*)XMALLOC(name->sz, 0, DYNAMIC_TYPE_OPENSSL); - if (!in ) return in; - copySz = name->sz; - } - - if (copySz == 0) - return in; - - XMEMCPY(in, name->name, copySz - 1); - in[copySz - 1] = 0; - - return in; - } - CYASSL_X509* CyaSSL_X509_STORE_CTX_get_current_cert( CYASSL_X509_STORE_CTX* ctx) @@ -5540,8 +5481,12 @@ int CyaSSL_set_compression(CYASSL* ssl) (void)flags; return 0; } -#endif -#ifdef KEEP_PEER_CERT + +#endif /* OPENSSL_EXTRA */ + + +#if defined(KEEP_PEER_CERT) + CYASSL_X509* CyaSSL_get_peer_certificate(CYASSL* ssl) { CYASSL_ENTER("SSL_get_peer_certificate"); @@ -5550,7 +5495,108 @@ int CyaSSL_set_compression(CYASSL* ssl) else return 0; } -#endif + +#endif /* KEEP_PEER_CERT */ + + +#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) + + void CyaSSL_FreeX509(CYASSL_X509* x509) + { + CYASSL_ENTER("CyaSSL_FreeX509"); + FreeX509(x509); + } + + + /* return the next, if any, altname from the peer cert */ + char* CyaSSL_X509_get_next_altname(CYASSL_X509* cert) + { + char* ret = NULL; + CYASSL_ENTER("CyaSSL_X509_get_next_altname"); + + /* don't have any to work with */ + if (cert == NULL || cert->altNames == NULL) + return NULL; + + /* already went through them */ + if (cert->altNamesNext == NULL) + return NULL; + + ret = cert->altNamesNext->name; + cert->altNamesNext = cert->altNamesNext->next; + + return ret; + } + + + CYASSL_X509_NAME* CyaSSL_X509_get_issuer_name(CYASSL_X509* cert) + { + CYASSL_ENTER("X509_get_issuer_name"); + return &cert->issuer; + } + + + CYASSL_X509_NAME* CyaSSL_X509_get_subject_name(CYASSL_X509* cert) + { + CYASSL_ENTER("X509_get_subject_name"); + return &cert->subject; + } + + + /* copy name into in buffer, at most sz bytes, if buffer is null will + malloc buffer, call responsible for freeing */ + char* CyaSSL_X509_NAME_oneline(CYASSL_X509_NAME* name, char* in, int sz) + { + int copySz = min(sz, name->sz); + + CYASSL_ENTER("CyaSSL_X509_NAME_oneline"); + if (!name->sz) return in; + + if (!in) { + in = (char*)XMALLOC(name->sz, 0, DYNAMIC_TYPE_OPENSSL); + if (!in ) return in; + copySz = name->sz; + } + + if (copySz == 0) + return in; + + XMEMCPY(in, name->name, copySz - 1); + in[copySz - 1] = 0; + + return in; + } + + + /* write X509 serial number in unsigned binary to buffer + buffer needs to be at least EXTERNAL_SERIAL_SIZE (32) for all cases + return SSL_SUCCESS on success */ + int CyaSSL_X509_get_serial_number(CYASSL_X509* x509, byte* in, int* inOutSz) + { + CYASSL_ENTER("CyaSSL_X509_get_serial_number"); + if (x509 == NULL || in == NULL || *inOutSz < x509->serialSz) + return BAD_FUNC_ARG; + + XMEMCPY(in, x509->serial, x509->serialSz); + *inOutSz = x509->serialSz; + + return SSL_SUCCESS; + } + + + const byte* CyaSSL_X509_get_der(CYASSL_X509* x509, int* outSz) + { + CYASSL_ENTER("CyaSSL_X509_get_der"); + + if (x509 == NULL || outSz == NULL) + return NULL; + + *outSz = (int)x509->derCert.length; + return x509->derCert.buffer; + } + +#endif /* KEEP_PEER_CERT || SESSION_CERTS */ + #ifdef OPENSSL_EXTRA int CyaSSL_set_ex_data(CYASSL* ssl, int idx, void* data) @@ -6696,32 +6742,6 @@ int CyaSSL_set_compression(CYASSL* ssl) return 0; } - /* write X509 serial number in unsigned binary to buffer - buffer needs to be at least EXTERNAL_SERIAL_SIZE (32) for all cases - return SSL_SUCCESS on success */ - int CyaSSL_X509_get_serial_number(CYASSL_X509* x509, byte* in, int* inOutSz) - { - CYASSL_ENTER("CyaSSL_X509_get_serial_number"); - if (x509 == NULL || in == NULL || *inOutSz < x509->serialSz) - return BAD_FUNC_ARG; - - XMEMCPY(in, x509->serial, x509->serialSz); - *inOutSz = x509->serialSz; - - return SSL_SUCCESS; - } - - - const byte* CyaSSL_X509_get_der(CYASSL_X509* x509, int* outSz) - { - CYASSL_ENTER("CyaSSL_X509_get_der"); - - if (x509 == NULL || outSz == NULL) - return NULL; - - *outSz = (int)x509->derCert.length; - return x509->derCert.buffer; - } #endif /* OPENSSL_EXTRA */ @@ -8583,6 +8603,44 @@ byte* CyaSSL_get_chain_cert(CYASSL_X509_CHAIN* chain, int idx) } +/* Get peer's CyaSSL X509 ceritifcate at index (idx) */ +CYASSL_X509* CyaSSL_get_chain_X509(CYASSL_X509_CHAIN* chain, int idx) +{ + int ret; + CYASSL_X509* x509; + DecodedCert dCert; + + CYASSL_ENTER("CyaSSL_get_chain_X509"); + if (chain == NULL) + return NULL; + + InitDecodedCert(&dCert, chain->certs[idx].buffer, chain->certs[idx].length, + NULL); + ret = ParseCertRelative(&dCert, CERT_TYPE, 0, NULL); + if (ret != 0) { + CYASSL_MSG("Failed to parse cert"); + FreeDecodedCert(&dCert); + } + + x509 = (CYASSL_X509*)XMALLOC(sizeof(CYASSL_X509), NULL, DYNAMIC_TYPE_X509); + if (x509 == NULL) { + CYASSL_MSG("Failed alloc X509"); + FreeDecodedCert(&dCert); + } + InitX509(x509, 1); + + ret = CopyDecodedToX509(x509, &dCert); + if (ret != 0) { + CYASSL_MSG("Failed to copy decoded"); + XFREE(x509, NULL, DYNAMIC_TYPE_X509); + x509 = NULL; + } + FreeDecodedCert(&dCert); + + return x509; +} + + /* Get peer's PEM ceritifcate at index (idx), output to buffer if inLen big enough else return error (-1), output length is in *outLen */ int CyaSSL_get_chain_cert_pem(CYASSL_X509_CHAIN* chain, int idx,