added OCSP Response simple parsing

This commit is contained in:
John Safranek 2012-04-26 13:52:48 -07:00
parent 8fe36b417f
commit cbde04a06b
2 changed files with 393 additions and 0 deletions

View File

@ -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

View File

@ -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