From cbde04a06b55789c9e7638042de3a3b6be259d01 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 26 Apr 2012 13:52:48 -0700 Subject: [PATCH] added OCSP Response simple parsing --- ctaocrypt/src/asn.c | 328 +++++++++++++++++++++++++++++++++++++++++ cyassl/ctaocrypt/asn.h | 65 ++++++++ 2 files changed, 393 insertions(+) diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 6a2362ef6..076323c53 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -3728,3 +3728,331 @@ int EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key, } #endif /* HAVE_ECC */ + + +#ifdef HAVE_OCSP + +static int GetEnumerated(const byte* input, word32* inOutIdx, int *value) +{ + word32 idx = *inOutIdx; + word32 len; + + *value = 0; + + if (input[idx++] != ASN_ENUMERATED) + return ASN_PARSE_E; + + len = input[idx++]; + if (len > 4) + return ASN_PARSE_E; + + while (len--) { + *value = *value << 8 | input[idx++]; + } + + *inOutIdx = idx; + + return *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) +{ + word32 index = *ioIndex, prevIndex, oid, mpi_len; + int length, remainder, qty = 0; + mp_int mpi; + byte serialTmp[EXTERNAL_SERIAL_SIZE]; + + /* Outer wrapper of the SEQUENCE OF Single Responses. */ + if (GetSequence(source, &index, &length, size) < 0) + return ASN_PARSE_E; + remainder = length; + + /* First Single Response */ + while (remainder != 0 && qty < STATUS_LIST_SIZE) + { + prevIndex = index; + /* Wrapper around the Single Response */ + if (GetSequence(source, &index, &length, size) < 0) + return ASN_PARSE_E; + + /* Wrapper around the CertID */ + if (GetSequence(source, &index, &length, size) < 0) + return ASN_PARSE_E; + /* Skip the hash algorithm */ + if (GetAlgoId(source, &index, &oid, size) < 0) + return ASN_PARSE_E; + /* Skip the hash of CN */ + if (source[index++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + index += length; + /* Skip the hash of the issuer public key */ + if (source[index++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + index += length; + + /* Read the serial number */ + if (GetInt(&mpi, source, &index, size) < 0) + return ASN_PARSE_E; + mpi_len = mp_unsigned_bin_size(&mpi); + if (mpi_len < (int)sizeof(serialTmp)) { + if (mp_to_unsigned_bin(&mpi, serialTmp) == MP_OKAY) { + if (mpi_len > EXTERNAL_SERIAL_SIZE) + mpi_len = EXTERNAL_SERIAL_SIZE; + XMEMCPY(resp->certSN[qty], serialTmp, mpi_len); + resp->certSNsz[qty] = mpi_len; + } + } + mp_clear(&mpi); + + /* CertStatus */ + switch (source[index++]) + { + case (ASN_CONTEXT_SPECIFIC | CERT_GOOD): + resp->certStatus[qty] = CERT_GOOD; + index++; + break; + case (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CERT_REVOKED): + resp->certStatus[qty] = CERT_REVOKED; + GetLength(source, &index, &length, size); + index += length; + break; + case (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CERT_UNKNOWN): + resp->certStatus[qty] = CERT_UNKNOWN; + index++; + break; + default: + return ASN_PARSE_E; + } + + if (source[index++] != ASN_GENERALIZED_TIME) + return ASN_PARSE_E; + + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + index += length; + + remainder = remainder + prevIndex - index; + qty++; + } + resp->certStatusCount = qty; + + *ioIndex = index; + + return 0; +} + +static int DecodeResponseData(byte* source, + word32* ioIndex, OcspResponse* resp, word32 size) +{ + word32 index = *ioIndex; + int length, result; + int version; + word32 responderId = 0; + + if (GetSequence(source, &index, &length, size) < 0) + return ASN_PARSE_E; + resp->respBegin = index; + resp->respLength = length; + + /* Get version. It is an EXPLICIT[0] DEFAULT(0) value. If this + * item isn't an EXPLICIT[0], then set version to zero and move + * onto the next item. + */ + if (source[index] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) + { + index += 2; /* Eat the value and length */ + if (GetMyVersion(source, &index, &version) < 0) + return ASN_PARSE_E; + } else + version = 0; + + responderId = source[index++]; + if ((responderId == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) || + (responderId == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 2))) + { + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + index += length; + } + else + return ASN_PARSE_E; + + /* Skip GeneralizedTime */ + if (source[index++] != ASN_GENERALIZED_TIME) + return ASN_PARSE_E; + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + index += length; + + if (DecodeSingleResponse(source, &index, resp, size) < 0) + return ASN_PARSE_E; + + /* Skip the extensions */ + if (source[index++] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) + { + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + index += length; + } + + *ioIndex = index; + return 0; +} + +static int DecodeCerts(byte* source, + word32* ioIndex, OcspResponse* resp, word32 size) +{ + word32 index = *ioIndex; + if (source[index++] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) + { + int length; + + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + index += length; + } + *ioIndex = index; + return 0; +} + +static int DecodeBasicOcspResponse(byte* source, + word32* ioIndex, OcspResponse* resp, word32 size) +{ + int length; + word32 index = *ioIndex; + word32 end_index; + + if (GetSequence(source, &index, &length, size) < 0) + return ASN_PARSE_E; + + if (index + length > size) + return ASN_INPUT_E; + end_index = index + length; + + if (DecodeResponseData(source, &index, resp, size) < 0) + return ASN_PARSE_E; + + /* Get the signature algorithm */ + if (GetAlgoId(source, &index, &resp->sigOID, size) < 0) + return ASN_PARSE_E; + + /* Obtain pointer to the start of the signature, and save the size */ + if (source[index++] == ASN_BIT_STRING) + { + int sigLength = 0; + if (GetLength(source, &index, &sigLength, size) < 0) + return ASN_PARSE_E; + resp->sigLength = sigLength; + resp->sigIndex = index; + index += sigLength; + } + + /* + * Check the length of the BasicOcspResponse against the current index to + * see if there are certificates, they are optional. + */ + if (index < end_index) + return DecodeCerts(source, &index, resp, size); + + *ioIndex = index; + return 0; +} + + +void InitOcspResponse(OcspResponse* resp, byte* source, word32 inSz, void* heap) +{ + XMEMSET(resp, 0, sizeof(*resp)); + resp->source = source; + resp->maxIdx = inSz; + resp->heap = heap; +} + + +void FreeOcspResponse(OcspResponse* resp) {} + + +int OcspResponseDecode(OcspResponse* resp) +{ + int length = 0; + word32 index = 0; + byte* source = resp->source; + word32 size = resp->maxIdx; + word32 oid; + + /* peel the outer SEQUENCE wrapper */ + if (GetSequence(source, &index, &length, size) < 0) + return ASN_PARSE_E; + + /* First get the responseStatus, an ENUMERATED */ + if (GetEnumerated(source, &index, &resp->responseStatus) < 0) + return ASN_PARSE_E; + + if (resp->responseStatus != OCSP_SUCCESSFUL) + return 0; + + /* Next is an EXPLICIT record called ResponseBytes, OPTIONAL */ + if (index >= size) + return ASN_INPUT_E; + if (source[index++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) + return ASN_PARSE_E; + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + + /* Get the responseBytes SEQUENCE */ + if (GetSequence(source, &index, &length, size) < 0) + return ASN_PARSE_E; + + /* Check ObjectID for the resposeBytes */ + if (GetObjectId(source, &index, &oid, size) < 0) + return ASN_PARSE_E; + if (oid != OCSP_BASIC_OID) + return ASN_PARSE_E; + if (source[index++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(source, &index, &length, size) < 0) + return ASN_PARSE_E; + + if (DecodeBasicOcspResponse(source, &index, resp, size) < 0) + return ASN_PARSE_E; + + return 0; +} + +int EncodeOcspRequest(void) +{ + return 0; +} + +#endif diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index 21020d5cd..f2ac9667f 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -56,6 +56,7 @@ enum ASN_Tags { ASN_OCTET_STRING = 0x04, ASN_TAG_NULL = 0x05, ASN_OBJECT_ID = 0x06, + ASN_ENUMERATED = 0x0a, ASN_SEQUENCE = 0x10, ASN_SET = 0x11, ASN_UTC_TIME = 0x17, @@ -302,6 +303,70 @@ enum cert_enums { #endif /* CYASSL_CERT_GEN */ +#ifdef HAVE_OCSP + +enum Ocsp_Response_Status { + OCSP_SUCCESSFUL = 0, /* Response has valid confirmations */ + OCSP_MALFORMED_REQUEST = 1, /* Illegal confirmation request */ + OCSP_INTERNAL_ERROR = 2, /* Internal error in issuer */ + OCSP_TRY_LATER = 3, /* Try again later */ + OCSP_SIG_REQUIRED = 5, /* Must sign the request (4 is skipped) */ + OCSP_UNAUTHROIZED = 6 /* Request unauthorized */ +}; + + +enum Ocsp_Cert_Status { + CERT_GOOD = 0, + CERT_REVOKED = 1, + CERT_UNKNOWN = 2 +}; + + +enum Ocsp_Sums { + OCSP_BASIC_OID = 117 +}; + + +#define STATUS_LIST_SIZE 5 + + +typedef struct OcspResponse OcspResponse; + +struct OcspResponse { + int responseStatus; /* return code from Responder */ + + word32 respBegin; /* index to beginning of OCSP Response */ + word32 respLength; /* length of the OCSP Response */ + + int version; /* Response version number */ + + word32 sigIndex; /* Index into source for start of sig */ + word32 sigLength; /* Length in octets for the sig */ + word32 sigOID; /* OID for hash used for sig */ + + int certStatusCount; /* Count of certificate statuses, Note + * 1:1 correspondence between certStatus + * and certSerialNumber */ + byte certSN[STATUS_LIST_SIZE][EXTERNAL_SERIAL_SIZE]; + int certSNsz[STATUS_LIST_SIZE]; + /* Certificate serial number array. */ + word32 certStatus[STATUS_LIST_SIZE]; + /* Certificate status array */ + + byte* source; /* pointer to source buffer, not owned */ + word32 maxIdx; /* max offset based on init size */ + void* heap; /* for user memory overrides */ +}; + + +CYASSL_API void InitOcspResponse(OcspResponse*, byte*, word32, void*); +CYASSL_API void FreeOcspResponse(OcspResponse*); +CYASSL_API int OcspResponseDecode(OcspResponse*); + + +#endif /* HAVE_OCSP */ + + #ifdef __cplusplus } /* extern "C" */ #endif