diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 0af015174..a392b0d6e 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -439,6 +439,31 @@ static int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx, } +static int GetObjectId(const byte* input, word32* inOutIdx, word32* oid, + word32 maxIdx) +{ + int length; + word32 i = *inOutIdx; + byte b; + *oid = 0; + + b = input[i++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, &i, &length, maxIdx) < 0) + return ASN_PARSE_E; + + while(length--) + *oid += input[i++]; + /* just sum it up for now */ + + *inOutIdx = i; + + return 0; +} + + static int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, word32 maxIdx) { @@ -1028,6 +1053,10 @@ void InitDecodedCert(DecodedCert* cert, byte* source, word32 inSz, void* heap) cert->extensions = 0; cert->extensionsSz = 0; cert->extensionsIdx = 0; + cert->extAuthInfo = NULL; + cert->extAuthInfoSz = 0; + cert->extCrlInfo = NULL; + cert->extCrlInfoSz = 0; cert->isCA = 0; #ifdef CYASSL_CERT_GEN cert->subjectSN = 0; @@ -2017,6 +2046,232 @@ static int ConfirmSignature(DecodedCert* cert, const byte* key, word32 keySz, } +static void DecodeBasicCaConstraint(byte* input, int sz, DecodedCert* cert) +{ + word32 index = 0; + int length = 0; + + CYASSL_ENTER("DecodeBasicCaConstraint"); + if (GetSequence(input, &index, &length, sz) < 0) return; + + if (input[index++] != ASN_BOOLEAN) + { + CYASSL_MSG("\tfail: constraint not BOOLEAN"); + return; + } + + if (GetLength(input, &index, &length, sz) < 0) + { + CYASSL_MSG("\tfail: length"); + return; + } + + if (input[index]) + cert->isCA = 1; +} + + +#define CRLDP_FULL_NAME 0 + /* From RFC3280 SS4.2.1.14, Distribution Point Name*/ +#define GENERALNAME_URI 6 + /* From RFC3280 SS4.2.1.7, GeneralName */ + +static void DecodeCrlDist(byte* input, int sz, DecodedCert* cert) +{ + word32 index = 0; + int length = 0; + word32 oid; + + CYASSL_ENTER("DecodeCrlDist"); + + /* Unwrap the list of Distribution Points*/ + if (GetSequence(input, &index, &length, sz) < 0) return; + + /* Unwrap a single Distribution Point */ + if (GetSequence(input, &index, &length, sz) < 0) return; + + /* The Distribution Point has three explicit optional members + * First check for a DistributionPointName + */ + if (input[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) + { + index++; + if (GetLength(input, &index, &length, sz) < 0) return; + + if (input[index] == + (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CRLDP_FULL_NAME)) + { + index++; + if (GetLength(input, &index, &length, sz) < 0) return; + + if (input[index] == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI)) + { + index++; + if (GetLength(input, &index, &length, sz) < 0) return; + + cert->extCrlInfoSz = length; + cert->extCrlInfo = input + index; + index += length; + } + else + /* This isn't a URI, skip it. */ + index += length; + } + else + /* This isn't a FULLNAME, skip it. */ + index += length; + } + + /* Check for reasonFlags */ + if (index < sz && + input[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) + { + index++; + if (GetLength(input, &index, &length, sz) < 0) return; + index += length; + } + + /* Check for cRLIssuer */ + if (index < sz && + input[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2)) + { + index++; + if (GetLength(input, &index, &length, sz) < 0) return; + index += length; + } + + if (index < sz) + { + CYASSL_MSG("\tThere are more CRL Distribution Point records, " + "but we only use the first one."); + } + + return; +} + + +static void DecodeAuthInfo(byte* input, int sz, DecodedCert* cert) +/* + * Read the first of the Authority Information Access records. If there are + * any issues, return without saving the record. + */ +{ + word32 index = 0; + int length = 0; + word32 oid; + + /* Unwrap the list of AIAs */ + if (GetSequence(input, &index, &length, sz) < 0) return; + + /* Unwrap a single AIA */ + if (GetSequence(input, &index, &length, sz) < 0) return; + + oid = 0; + if (GetObjectId(input, &index, &oid, sz) < 0) return; + + /* Only supporting URIs right now. */ + if (input[index] == (ASN_CONTEXT_SPECIFIC | GENERALNAME_URI)) + { + index++; + if (GetLength(input, &index, &length, sz) < 0) return; + + cert->extAuthInfoSz = length; + cert->extAuthInfo = input + index; + index += length; + } + else + { + /* Skip anything else. */ + index++; + if (GetLength(input, &index, &length, sz) < 0) return; + index += length; + } + + if (index < sz) + { + CYASSL_MSG("\tThere are more Authority Information Access records, " + "but we only use first one."); + } + + return; +} + + +static void DecodeCertExtensions(DecodedCert* cert) +/* + * Processing the Certificate Extensions. This does not modify the current + * index. It is works starting with the recorded extensions pointer. + */ +{ + word32 index = 0; + int sz = cert->extensionsSz; + byte* input = cert->extensions; + int length; + word32 oid; + + CYASSL_ENTER("DecodeCertExtensions"); + + if (input == NULL || sz == 0) return; + + if (input[index++] != ASN_EXTENSIONS)return; + + if (GetLength(input, &index, &length, sz) < 0) return; + + if (GetSequence(input, &index, &length, sz) < 0) return; + + while (index < sz) { + if (GetSequence(input, &index, &length, sz) < 0) { + CYASSL_MSG("\tfail: should be a SEQUENCE"); + return; + } + + oid = 0; + if (GetObjectId(input, &index, &oid, sz) < 0) { + CYASSL_MSG("\tfail: OBJECT ID"); + return; + } + + /* check for critical flag */ + if (input[index] == ASN_BOOLEAN) { + CYASSL_MSG("\tfound optional critical flag, moving past"); + index += (ASN_BOOL_SIZE + 1); + } + + /* process the extension based on the OID */ + if (input[index++] != ASN_OCTET_STRING) { + CYASSL_MSG("\tfail: should be an OCTET STRING"); + return; + } + + if (GetLength(input, &index, &length, sz) < 0) { + CYASSL_MSG("\tfail: extension data length"); + return; + } + + switch (oid) { + case BASIC_CA_OID: + DecodeBasicCaConstraint(&input[index], length, cert); + break; + + case CRL_DIST_OID: + DecodeCrlDist(&input[index], length, cert); + break; + + case AUTH_INFO_OID: + DecodeAuthInfo(&input[index], length, cert); + break; + + default: + CYASSL_MSG("\tExtension type not handled, skipping"); + break; + } + index += length; + } + + return; +} + + int ParseCert(DecodedCert* cert, int type, int verify, void* cm) { int ret; @@ -2051,88 +2306,6 @@ int ParseCert(DecodedCert* cert, int type, int verify, void* cm) } -/* 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) { - CYASSL_MSG("Found Basic CA constraint"); - b = cert->source[cert->srcIdx++]; - - if (b != ASN_OCTET_STRING) { - CYASSL_MSG("Found optional critical flag, moving past"); - cert->srcIdx += ASN_BOOL_SIZE; - b = cert->source[cert->srcIdx++]; - - if (b != ASN_OCTET_STRING) { - CYASSL_MSG("Unkown Basic CA constraint format"); - 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 */ #ifdef __cplusplus extern "C" { @@ -2163,7 +2336,7 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) cert->extensionsSz = cert->sigIndex - cert->srcIdx; cert->extensionsIdx = cert->srcIdx; /* for potential later use */ } - IsCa(cert); /* turn on ca flag if there */ + DecodeCertExtensions(cert); /* advance past extensions */ cert->srcIdx = cert->sigIndex; } @@ -3818,31 +3991,6 @@ static int GetEnumerated(const byte* input, word32* inOutIdx, int *value) } -static int GetObjectId(const byte* input, word32* inOutIdx, word32* oid, - word32 maxIdx) -{ - int length; - word32 i = *inOutIdx; - byte b; - *oid = 0; - - b = input[i++]; - if (b != ASN_OBJECT_ID) - return ASN_OBJECT_ID_E; - - if (GetLength(input, &i, &length, maxIdx) < 0) - return ASN_PARSE_E; - - while(length--) - *oid += input[i++]; - /* just sum it up for now */ - - *inOutIdx = i; - - return 0; -} - - static int DecodeSingleResponse(byte* source, word32* ioIndex, OcspResponse* resp, word32 size) { diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index 3090288f4..5dbdc03d2 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -183,7 +183,10 @@ enum KDF_Sum { enum Extensions_Sum { BASIC_CA_OID = 133, - ALT_NAMES_OID = 131 + ALT_NAMES_OID = 131, + CRL_DIST_OID = 145, + AUTH_INFO_OID = 69, + CA_ISSUER_OID = 117 }; @@ -226,6 +229,10 @@ 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* extAuthInfo; /* Authority Information Access URI */ + int extAuthInfoSz; /* length of the URI */ + byte* extCrlInfo; /* CRL Distribution Points */ + int extCrlInfoSz; /* length of the URI */ byte isCA; /* CA basic constraint true */ #ifdef CYASSL_CERT_GEN /* easy access to subject info for other sign */