Certificate extension parsing addition

pull/1/head
John Safranek 2012-05-14 15:38:59 -07:00
parent 7b2d62f4f7
commit 43592def99
2 changed files with 264 additions and 109 deletions

View File

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

View File

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