mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2025-08-01 03:34:39 +02:00
changed DN hashing to cover the whole DER encoding per OCSP-RFC, OCSP changes towards dynamic storage of responses
This commit is contained in:
@@ -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)
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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 */
|
||||
|
@@ -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*);
|
||||
|
||||
|
11
src/ocsp.c
11
src/ocsp.c
@@ -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;
|
||||
|
Reference in New Issue
Block a user