diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 479c10f5b..48cb97923 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -1017,6 +1017,7 @@ void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) cert->extensions = 0; cert->extensionsSz = 0; cert->extensionsIdx = 0; + cert->isCA = 0; #ifdef CYASSL_CERT_GEN cert->subjectSN = 0; cert->subjectSNLen = 0; @@ -1970,6 +1971,78 @@ int ParseCert(DecodedCert* cert, int type, int verify, } +/* If extension CA basic constraint is turned on, flag it, not error if not */ +static void IsCa(DecodedCert* cert) +{ + if (cert->extensions) { + byte b; + int length; + word32 maxExtensionsIdx; + + cert->srcIdx = cert->extensionsIdx; + b = cert->source[cert->srcIdx++]; + if (b != ASN_EXTENSIONS) + return; + + if (GetLength(cert->source, &cert->srcIdx, &length, + cert->maxIdx) < 0) + return; + + if (GetSequence(cert->source, &cert->srcIdx, &length, + cert->maxIdx) < 0) + return; + + maxExtensionsIdx = cert->srcIdx + length; + + while (cert->srcIdx < maxExtensionsIdx) { + word32 oid; + word32 startIdx = cert->srcIdx; + word32 tmpIdx; + + if (GetSequence(cert->source, &cert->srcIdx, &length, + cert->maxIdx) < 0) + return; + + tmpIdx = cert->srcIdx; + cert->srcIdx = startIdx; + + if (GetAlgoId(cert->source, &cert->srcIdx, &oid, + cert->maxIdx) < 0) + return; + + if (oid == BASIC_CA_OID) { + b = cert->source[cert->srcIdx++]; + if (b != ASN_OCTET_STRING) + return; + + if (GetLength(cert->source, &cert->srcIdx, &length, + cert->maxIdx) < 0) + return; + + if (GetSequence(cert->source, &cert->srcIdx, &length, + cert->maxIdx) < 0) + return; + + b = cert->source[cert->srcIdx++]; + if (b != ASN_BOOLEAN) + return; + + if (GetLength(cert->source, &cert->srcIdx, &length, + cert->maxIdx) < 0) + return; + + b = cert->source[cert->srcIdx++]; + if (b) + cert->isCA = 1; + + return; /* we're done checking */ + } + cert->srcIdx = tmpIdx + length; + } + } +} + + /* from SSL proper, for locking can't do find here anymore */ CYASSL_LOCAL Signer* GetCA(Signer* signers, byte* hash); @@ -1995,6 +2068,7 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, cert->extensionsSz = cert->sigIndex - cert->srcIdx; cert->extensionsIdx = cert->srcIdx; /* for potential later use */ } + IsCa(cert); /* turn on ca flag if there */ /* advance past extensions */ cert->srcIdx = cert->sigIndex; } diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index 433d0219a..71d00859b 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -50,6 +50,7 @@ enum { /* ASN Tags */ enum ASN_Tags { + ASN_BOOLEAN = 0x01, ASN_INTEGER = 0x02, ASN_BIT_STRING = 0x03, ASN_OCTET_STRING = 0x04, @@ -167,6 +168,7 @@ enum KDF_Sum { enum Extensions_Sum { + BASIC_CA_OID = 133, ALT_NAMES_OID = 131 }; @@ -207,6 +209,7 @@ struct DecodedCert { byte* extensions; /* not owned, points into raw cert */ int extensionsSz; /* length of cert extensions */ word32 extensionsIdx; /* if want to go back and parse later */ + byte isCA; /* CA basic constraint true */ #ifdef CYASSL_CERT_GEN /* easy access to subject info for other sign */ char* subjectSN; diff --git a/cyassl/internal.h b/cyassl/internal.h index 7b08e62e7..1c9c76a48 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -617,7 +617,7 @@ int ProcessOldClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, CYASSL_LOCAL int AddCA(CYASSL_CTX* ctx, buffer der); CYASSL_LOCAL -int IsCA(CYASSL_CTX* ctx, byte* hash); +int AlreadySigner(CYASSL_CTX* ctx, byte* hash); /* All cipher suite related info */ typedef struct CipherSpecs { diff --git a/src/internal.c b/src/internal.c index fca44e892..df7f1c5be 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1511,7 +1511,11 @@ 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); - if (ret == 0 && !IsCA(ssl->ctx, dCert.subjectHash)) { + if (ret == 0 && dCert.isCA == 0) { + CYASSL_MSG("Chain cert is not a CA, not adding as one"); + (void)ret; + } + else if (ret == 0 && !AlreadySigner(ssl->ctx, dCert.subjectHash)) { buffer add; add.length = myCert.length; add.buffer = (byte*)XMALLOC(myCert.length, ssl->heap, diff --git a/src/ssl.c b/src/ssl.c index 912fcde3e..efdeaf104 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -367,8 +367,8 @@ int CyaSSL_pending(CYASSL* ssl) static CyaSSL_Mutex ca_mutex; /* CA signers mutex */ -/* does CA already exist on list */ -int IsCA(CYASSL_CTX* ctx, byte* hash) +/* does CA already exist on signer list */ +int AlreadySigner(CYASSL_CTX* ctx, byte* hash) { Signer* signers; int ret = 0; @@ -421,7 +421,11 @@ int AddCA(CYASSL_CTX* ctx, buffer der) ret = ParseCert(&cert, CA_TYPE, ctx->verifyPeer, 0); CYASSL_MSG(" Parsed new CA"); - if (ret == 0 && IsCA(ctx, cert.subjectHash)) { + if (ret == 0 && cert.isCA == 0) { + CYASSL_MSG(" Can't add as CA if not actually one"); + ret = -1; + } + else if (ret == 0 && AlreadySigner(ctx, cert.subjectHash)) { CYASSL_MSG(" Already have this CA, not adding again"); (void)ret; }