diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 9643f1030..ccbb9e511 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -1060,6 +1060,7 @@ void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) cert->subjectCN = 0; cert->subjectCNLen = 0; cert->subjectCNStored = 0; + cert->altNames = NULL; cert->issuer[0] = '\0'; cert->subject[0] = '\0'; cert->source = source; /* don't own */ @@ -1099,12 +1100,26 @@ void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) } +void FreeAltNames(DNS_entry* altNames, void* heap) +{ + while (altNames) { + DNS_entry* tmp = altNames->next; + + XFREE(altNames->name, heap, DYNAMIC_TYPE_ALTNAME); + XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME); + altNames = tmp; + } +} + + void FreeDecodedCert(DecodedCert* cert) { if (cert->subjectCNStored == 1) XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN); if (cert->pubKeyStored == 1) XFREE(cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (cert->altNames) + FreeAltNames(cert->altNames, cert->heap); } @@ -2093,6 +2108,62 @@ static int ConfirmSignature(const byte* buf, word32 bufSz, } +static void DecodeAltNames(byte* input, int sz, DecodedCert* cert) +{ + word32 idx = 0; + int length = 0; + + CYASSL_ENTER("DecodeAltNames"); + + if (GetSequence(input, &idx, &length, sz) < 0) { + CYASSL_MSG("\tBad Sequence"); + return; + } + + while (length > 0) { + DNS_entry* entry; + int strLen; + byte b = input[idx++]; + + length--; + + if (b != (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) { + CYASSL_MSG("\tNot DNS type"); + return; + } + + if (GetLength(input, &idx, &strLen, sz) < 0) { + CYASSL_MSG("\tfail: str length"); + return; + } + + entry = (DNS_entry*)XMALLOC(sizeof(DNS_entry), cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (entry == NULL) { + CYASSL_MSG("\tOut of Memory"); + return; + } + + entry->name = (char*)XMALLOC(strLen + 1, cert->heap, + DYNAMIC_TYPE_ALTNAME); + if (entry->name == NULL) { + CYASSL_MSG("\tOut of Memory"); + XFREE(entry, cert->heap, DYNAMIC_TYPE_ALTNAME); + return; + } + + XMEMCPY(entry->name, &input[idx], strLen); + entry->name[strLen] = '\0'; + + entry->next = cert->altNames; + cert->altNames = entry; + + length -= strLen; + idx += strLen; + } +} + + static void DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert) { word32 idx = 0; @@ -2311,6 +2382,9 @@ static void DecodeCertExtensions(DecodedCert* cert) DecodeAuthInfo(&input[idx], length, cert); break; + case ALT_NAMES_OID: + DecodeAltNames(&input[idx], length, cert); + default: CYASSL_MSG("\tExtension type not handled, skipping"); break; diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index 7dbd59f8d..cf2ac1cb7 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -61,6 +61,7 @@ enum ASN_Tags { ASN_SEQUENCE = 0x10, ASN_SET = 0x11, ASN_UTC_TIME = 0x17, + ASN_DNS_TYPE = 0x02, ASN_GENERALIZED_TIME = 0x18, CRL_EXTENSIONS = 0xa0, ASN_EXTENSIONS = 0xa3, @@ -200,6 +201,13 @@ enum VerifyType { }; +typedef struct DNS_entry DNS_entry; + +struct DNS_entry { + DNS_entry* next; /* next on DNS list */ + char* name; /* actual DNS name */ +}; + typedef struct DecodedCert DecodedCert; typedef struct Signer Signer; @@ -213,6 +221,7 @@ struct DecodedCert { word32 sigLength; /* length of signature */ word32 signatureOID; /* sum of algorithm object id */ word32 keyOID; /* sum of key algo object id */ + DNS_entry* altNames; /* alt names list of dns entries */ byte subjectHash[SHA_SIZE]; /* hash of all Names */ byte issuerHash[SHA_SIZE]; /* hash of all Names */ #ifdef HAVE_OCSP @@ -281,6 +290,7 @@ struct Signer { #define CYASSL_TEST_API CYASSL_LOCAL #endif +CYASSL_TEST_API void FreeAltNames(DNS_entry*, void*); 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, void* cm); diff --git a/cyassl/ctaocrypt/types.h b/cyassl/ctaocrypt/types.h index e8f207213..723115a23 100644 --- a/cyassl/ctaocrypt/types.h +++ b/cyassl/ctaocrypt/types.h @@ -209,9 +209,10 @@ enum { DYNAMIC_TYPE_REVOKED = 23, DYNAMIC_TYPE_CRL_ENTRY = 24, DYNAMIC_TYPE_CERT_MANAGER = 25, - DYNAMIC_TYPE_CRL_MONITOR = 26, - DYNAMIC_TYPE_OCSP_STATUS = 27, - DYNAMIC_TYPE_OCSP_ENTRY = 28 + DYNAMIC_TYPE_CRL_MONITOR = 26, + DYNAMIC_TYPE_OCSP_STATUS = 27, + DYNAMIC_TYPE_OCSP_ENTRY = 28, + DYNAMIC_TYPE_ALTNAME = 29 }; /* stack protection */ diff --git a/cyassl/internal.h b/cyassl/internal.h index c843a081c..f9735a23d 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1147,6 +1147,8 @@ struct CYASSL_X509 { byte serial[EXTERNAL_SERIAL_SIZE]; char subjectCN[ASN_NAME_MAX]; /* common name short cut */ buffer derCert; /* may need */ + DNS_entry* altNames; /* alt names list */ + DNS_entry* altNamesNext; /* hint for retrieval */ }; diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 95d222bf2..b86181380 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -692,6 +692,8 @@ CYASSL_API const unsigned char* CyaSSL_X509_get_der(CYASSL_X509*, int*); CYASSL_API int CyaSSL_cmp_peer_cert_to_file(CYASSL*, const char*); +CYASSL_API char* CyaSSL_X509_get_next_altname(CYASSL_X509*); + /* connect enough to get peer cert */ CYASSL_API int CyaSSL_connect_cert(CYASSL* ssl); diff --git a/cyassl/test.h b/cyassl/test.h index c13ec8caa..6b3045955 100644 --- a/cyassl/test.h +++ b/cyassl/test.h @@ -169,6 +169,7 @@ static INLINE void showPeer(CYASSL* ssl) CYASSL_CIPHER* cipher; CYASSL_X509* peer = CyaSSL_get_peer_certificate(ssl); if (peer) { + char* altName; char* issuer = CyaSSL_X509_NAME_oneline( CyaSSL_X509_get_issuer_name(peer), 0, 0); char* subject = CyaSSL_X509_NAME_oneline( @@ -179,6 +180,10 @@ static INLINE void showPeer(CYASSL* ssl) 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 == 0) { int i; diff --git a/src/internal.c b/src/internal.c index 59637670a..783e8ba6e 100644 --- a/src/internal.c +++ b/src/internal.c @@ -839,7 +839,9 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->buffers.plainSz = 0; #ifdef OPENSSL_EXTRA - ssl->peerCert.derCert.buffer = 0; + ssl->peerCert.derCert.buffer = NULL; + ssl->peerCert.altNames = NULL; + ssl->peerCert.altNamesNext = NULL; #endif #ifdef HAVE_ECC @@ -1038,6 +1040,8 @@ void SSL_ResourceFree(CYASSL* ssl) ShrinkOutputBuffer(ssl); #if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS) XFREE(ssl->peerCert.derCert.buffer, ssl->heap, DYNAMIC_TYPE_CERT); + if (ssl->peerCert.altNames) + FreeAltNames(ssl->peerCert.altNames, ssl->heap); CyaSSL_BIO_free(ssl->biord); if (ssl->biord != ssl->biowr) /* in case same as write */ CyaSSL_BIO_free(ssl->biowr); @@ -1845,10 +1849,18 @@ static int DoCertificate(CYASSL* ssl, byte* input, word32* inOutIdx) /* store cert for potential retrieval */ ssl->peerCert.derCert.buffer = (byte*)XMALLOC(myCert.length, ssl->heap, DYNAMIC_TYPE_CERT); - if (ssl->peerCert.derCert.buffer == NULL) - return MEMORY_E; - XMEMCPY(ssl->peerCert.derCert.buffer, myCert.buffer, myCert.length); - ssl->peerCert.derCert.length = myCert.length; + if (ssl->peerCert.derCert.buffer == NULL) { + ret = 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 225c76254..b6c75a64c 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3483,6 +3483,27 @@ 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");