added OCSP Response simple parsing
This commit is contained in:
parent
8fe36b417f
commit
cbde04a06b
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user