changed DN hashing to cover the whole DER encoding per OCSP-RFC, OCSP changes towards dynamic storage of responses

This commit is contained in:
John Safranek
2012-05-29 09:11:37 -07:00
parent 0a31dc3a37
commit 9818fe4f55
5 changed files with 198 additions and 152 deletions

View File

@@ -1287,7 +1287,7 @@ static int GetName(DecodedCert* cert, int nameType)
int length; /* length of all distinguished names */
int dummy;
char* full = (nameType == ISSUER) ? cert->issuer : cert->subject;
word32 idx = 0;
word32 idx;
if (cert->source[cert->srcIdx] == ASN_OBJECT_ID) {
CYASSL_MSG("Trying optional prefix...");
@@ -1299,17 +1299,22 @@ static int GetName(DecodedCert* cert, int nameType)
CYASSL_MSG("Got optional prefix");
}
/* For OCSP, RFC2560 section 4.1.1 states the issuer hash should be
* calculated over the entire DER encoding of the Name field, including
* the tag and length. */
idx = cert->srcIdx;
if (GetSequence(cert->source, &cert->srcIdx, &length, cert->maxIdx) < 0)
return ASN_PARSE_E;
InitSha(&sha);
ShaUpdate(&sha, &cert->source[cert->srcIdx], length);
ShaUpdate(&sha, &cert->source[idx], length + cert->srcIdx - idx);
if (nameType == ISSUER)
ShaFinal(&sha, cert->issuerHash);
else
ShaFinal(&sha, cert->subjectHash);
length += cert->srcIdx;
idx = 0;
while (cert->srcIdx < (word32)length) {
byte b;
@@ -4076,6 +4081,36 @@ int EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key,
#endif /* HAVE_ECC */
#if defined(HAVE_OCSP) || defined(HAVE_CRL)
/* Get raw Date only, no processing, 0 on success */
static int GetBasicDate(const byte* source, word32* idx, byte* date,
byte* format, int maxIdx)
{
int length;
CYASSL_ENTER("GetBasicDate");
*format = source[*idx];
*idx += 1;
if (*format != ASN_UTC_TIME && *format != ASN_GENERALIZED_TIME)
return ASN_TIME_E;
if (GetLength(source, idx, &length, maxIdx) < 0)
return ASN_PARSE_E;
if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
return ASN_DATE_SZ_E;
XMEMCPY(date, &source[*idx], length);
*idx += length;
return 0;
}
#endif
#ifdef HAVE_OCSP
static int GetEnumerated(const byte* input, word32* inOutIdx, int *value)
@@ -4106,91 +4141,109 @@ static int DecodeSingleResponse(byte* source,
word32* ioIndex, OcspResponse* resp, word32 size)
{
word32 index = *ioIndex, prevIndex, oid;
int length, remainder, qty = 0;
int length;
CertStatus* cs = NULL;
/* 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)
/* When making a request, we only request one status on one certificate
* at a time. There should only be one SingleResponse */
cs = resp->status;/*XMALLOC(sizeof(CertStatus), NULL, DYNAMIC_TYPE_CERT_STATUS);
if (cs == NULL)
{
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, it is handled as a string, not as a
* proper number. Just XMEMCPY the data over, rather than load it
* as an mp_int. */
if (source[index++] != ASN_INTEGER)
return ASN_PARSE_E;
if (GetLength(source, &index, &length, size) < 0)
return ASN_PARSE_E;
if (length <= EXTERNAL_SERIAL_SIZE) {
if (source[index] == 0) {
index++;
length--;
}
XMEMCPY(resp->certSN[qty], source + index, length);
resp->certSNsz[qty] = length;
} else {
return ASN_GETINT_E;
}
index += length;
/* 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 | 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;
resp->thisUpdate = source + index;
index += length;
remainder = remainder + prevIndex - index;
qty++;
CYASSL_MSG("\tAlloc Cert Status failed");
return MEMORY_E;
}
cs->next = NULL; */
/* 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, it is handled as a string, not as a
* proper number. Just XMEMCPY the data over, rather than load it
* as an mp_int. */
if (source[index++] != ASN_INTEGER)
return ASN_PARSE_E;
if (GetLength(source, &index, &length, size) < 0)
return ASN_PARSE_E;
if (length <= EXTERNAL_SERIAL_SIZE)
{
if (source[index] == 0)
{
index++;
length--;
}
XMEMCPY(cs->serial, source + index, length);
cs->serialSz = length;
}
else
{
return ASN_GETINT_E;
}
index += length;
/* CertStatus */
switch (source[index++])
{
case (ASN_CONTEXT_SPECIFIC | CERT_GOOD):
cs->status = CERT_GOOD;
index++;
break;
case (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CERT_REVOKED):
cs->status = CERT_REVOKED;
GetLength(source, &index, &length, size);
index += length;
break;
case (ASN_CONTEXT_SPECIFIC | CERT_UNKNOWN):
cs->status = CERT_UNKNOWN;
index++;
break;
default:
return ASN_PARSE_E;
}
if (GetBasicDate(source, &index, cs->thisDate,
&cs->thisDateFormat, size) < 0)
return ASN_PARSE_E;
if (source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
{
index++;
if (GetLength(source, &index, &length, size) < 0)
return ASN_PARSE_E;
if (GetBasicDate(source, &index, cs->nextDate,
&cs->nextDateFormat, size) < 0)
return ASN_PARSE_E;
}
if (source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
{
index++;
if (GetLength(source, &index, &length, size) < 0)
return ASN_PARSE_E;
index += length;
}
resp->certStatusCount = qty;
*ioIndex = index;
@@ -4625,6 +4678,7 @@ static int GetNameHash(const byte* source, word32* idx, byte* hash, int maxIdx)
{
Sha sha;
int length; /* length of all distinguished names */
word32 dummy;
CYASSL_ENTER("GetNameHash");
@@ -4638,11 +4692,15 @@ static int GetNameHash(const byte* source, word32* idx, byte* hash, int maxIdx)
CYASSL_MSG("Got optional prefix");
}
/* For OCSP, RFC2560 section 4.1.1 states the issuer hash should be
* calculated over the entire DER encoding of the Name field, including
* the tag and length. */
dummy = *idx;
if (GetSequence(source, idx, &length, maxIdx) < 0)
return ASN_PARSE_E;
InitSha(&sha);
ShaUpdate(&sha, &source[*idx], length);
ShaUpdate(&sha, source + dummy, length + *idx - dummy);
ShaFinal(&sha, hash);
*idx += length;
@@ -4651,32 +4709,6 @@ static int GetNameHash(const byte* source, word32* idx, byte* hash, int maxIdx)
}
/* Get raw Date only, no processing, 0 on success */
static int GetBasicDate(const byte* source, word32* idx, byte* date,
byte* format, int maxIdx)
{
int length;
CYASSL_ENTER("GetBasicDate");
*format = source[*idx];
*idx += 1;
if (*format != ASN_UTC_TIME && *format != ASN_GENERALIZED_TIME)
return ASN_TIME_E;
if (GetLength(source, idx, &length, maxIdx) < 0)
return ASN_PARSE_E;
if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE)
return ASN_DATE_SZ_E;
XMEMCPY(date, &source[*idx], length);
*idx += length;
return 0;
}
/* Get Revoked Cert list, 0 on success */
static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl,
int maxIdx)

View File

@@ -324,6 +324,10 @@ enum cert_enums {
#endif /* CYASSL_CERT_GEN */
/* for pointer use */
typedef struct CertStatus CertStatus;
#ifdef HAVE_OCSP
enum Ocsp_Response_Status {
@@ -349,13 +353,25 @@ enum Ocsp_Sums {
};
#define STATUS_LIST_SIZE 5
typedef struct OcspRequest OcspRequest;
typedef struct OcspResponse OcspResponse;
struct CertStatus {
CertStatus* next;
byte serial[EXTERNAL_SERIAL_SIZE];
int serialSz;
int status;
byte thisDate[MAX_DATE_SIZE];
byte nextDate[MAX_DATE_SIZE];
byte thisDateFormat;
byte nextDateFormat;
};
struct OcspResponse {
int responseStatus; /* return code from Responder */
@@ -364,25 +380,17 @@ struct OcspResponse {
int version; /* Response version number */
byte* thisUpdate; /* Time at which this status was set */
byte* nextUpdate; /* Time for next update */
byte* producedAt; /* Time at which this response was signed */
byte producedAtFormat;/* format of the producedAt date */
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 */
CertStatus status[1]; /* list of certificate status */
byte* nonce;
int nonceSz;
byte* nonce; /* pointer to nonce inside ASN.1 response */
int nonceSz; /* length of the nonce string */
byte* source; /* pointer to source buffer, not owned */
word32 maxIdx; /* max offset based on init size */
@@ -394,8 +402,13 @@ struct OcspRequest {
byte* nonce;
int nonceSz;
byte* dest;
word32 destSz;
byte* issuerHash; /* pointer to issuerHash in source cert */
byte* issuerKeyHash; /* pointer to issuerKeyHash in source cert */
byte* serial; /* pointer to serial number in source cert */
int serialSz; /* length of the serial number */
byte* dest; /* pointer to the destination ASN.1 buffer */
word32 destSz; /* length of the destination buffer */
void* heap;
};

View File

@@ -624,6 +624,28 @@ CYASSL_LOCAL int UnLockMutex(CyaSSL_Mutex*);
typedef struct OCSP_Entry OCSP_Entry;
struct OCSP_Entry {
OCSP_Entry* next; /* next entry */
byte issuerHash[SHA_DIGEST_SIZE]; /* issuer hash */
byte issuerKeyHash[SHA_DIGEST_SIZE]; /* issuer public key hash */
CertStatus status[1]; /* OCSP response list */
int totalStatus; /* number on list */
};
/* CyaSSL OCSP controller */
struct CYASSL_OCSP {
byte enabled;
byte useOverrideUrl;
char overrideName[80];
char overridePath[80];
int overridePort;
OCSP_Entry ocspList[1];
};
typedef struct CRL_Entry CRL_Entry;
/* Complete CRL */

View File

@@ -26,38 +26,18 @@
#define CYASSL_OCSP_H
#include <cyassl/ssl.h>
#include <cyassl/ctaocrypt/asn.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct CYASSL_OCSP CYASSL_OCSP;
typedef struct CertStatus CertStatus;
struct CertStatus {
byte issuerHash[SHA_SIZE];
byte issuerKeyHash[SHA_SIZE];
byte serial[EXTERNAL_SERIAL_SIZE];
int serialSz;
int status;
};
struct CYASSL_OCSP {
byte enabled;
byte useOverrideUrl;
char overrideName[80];
char overridePath[80];
int overridePort;
int statusLen;
CertStatus status[1];
};
CYASSL_LOCAL int CyaSSL_OCSP_Init(CYASSL_OCSP*);
CYASSL_LOCAL void CyaSSL_OCSP_Cleanup(CYASSL_OCSP*);
CYASSL_LOCAL int CyaSSL_OCSP_set_override_url(CYASSL_OCSP*, const char*);
CYASSL_LOCAL int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP*, DecodedCert*);

View File

@@ -314,11 +314,10 @@ int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
return OCSP_NEED_URL;
}
XMEMCPY(ocsp->status[0].issuerHash, cert->issuerHash, SHA_SIZE);
XMEMCPY(ocsp->status[0].issuerKeyHash, cert->issuerKeyHash, SHA_SIZE);
XMEMCPY(ocsp->status[0].serial, cert->serial, cert->serialSz);
ocsp->status[0].serialSz = cert->serialSz;
ocsp->statusLen = 1;
XMEMCPY(ocsp->ocspList->issuerHash, cert->issuerHash, SHA_SIZE);
XMEMCPY(ocsp->ocspList->issuerKeyHash, cert->issuerKeyHash, SHA_SIZE);
XMEMCPY(ocsp->ocspList->status->serial, cert->serial, cert->serialSz);
ocsp->ocspList->status->serialSz = cert->serialSz;
ocspReqSz = EncodeOcspRequest(cert, ocspReqBuf, ocspReqSz);
httpBufSz = build_http_request(domainName, path, ocspReqSz,
@@ -355,7 +354,7 @@ int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
CYASSL_MSG("OCSP Responder failure");
result = OCSP_LOOKUP_FAIL;
} else {
switch (ocspResponse.certStatus[0]) {
switch (ocspResponse.status[0].status) {
case CERT_GOOD:
result = 0;
break;