forked from wolfSSL/wolfssl
dynamic allocation of OCSP responses, response signature check
This commit is contained in:
@@ -1916,7 +1916,7 @@ word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID)
|
||||
return encDigSz + algoSz + seqSz;
|
||||
}
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
/* return true (1) for Confirmation */
|
||||
static int ConfirmSignature(const byte* buf, word32 bufSz,
|
||||
const byte* key, word32 keySz, word32 keyOID,
|
||||
@@ -2029,7 +2029,7 @@ static int ConfirmSignature(const byte* buf, word32 bufSz,
|
||||
{
|
||||
int x;
|
||||
printf("cyassl encodedSig:\n");
|
||||
for (x = 0; x < sigSz; x++) {
|
||||
for (x = 0; x < encodedSigSz; x++) {
|
||||
printf("%02x ", encodedSig[x]);
|
||||
if ( (x % 16) == 15)
|
||||
printf("\n");
|
||||
@@ -4122,6 +4122,8 @@ static int GetEnumerated(const byte* input, word32* inOutIdx, int *value)
|
||||
word32 idx = *inOutIdx;
|
||||
word32 len;
|
||||
|
||||
CYASSL_ENTER("GetEnumerated");
|
||||
|
||||
*value = 0;
|
||||
|
||||
if (input[idx++] != ASN_ENUMERATED)
|
||||
@@ -4145,22 +4147,19 @@ static int DecodeSingleResponse(byte* source,
|
||||
word32* ioIndex, OcspResponse* resp, word32 size)
|
||||
{
|
||||
word32 index = *ioIndex, prevIndex, oid;
|
||||
int length;
|
||||
CertStatus* cs = NULL;
|
||||
int length, wrapperSz;
|
||||
CertStatus* cs = resp->status;
|
||||
|
||||
CYASSL_ENTER("DecodeSingleResponse");
|
||||
|
||||
/* Outer wrapper of the SEQUENCE OF Single Responses. */
|
||||
if (GetSequence(source, &index, &length, size) < 0)
|
||||
if (GetSequence(source, &index, &wrapperSz, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
|
||||
prevIndex = index;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
CYASSL_MSG("\tAlloc Cert Status failed");
|
||||
return MEMORY_E;
|
||||
}
|
||||
cs->next = NULL; */
|
||||
|
||||
/* Wrapper around the Single Response */
|
||||
if (GetSequence(source, &index, &length, size) < 0)
|
||||
@@ -4172,17 +4171,19 @@ static int DecodeSingleResponse(byte* source,
|
||||
/* Skip the hash algorithm */
|
||||
if (GetAlgoId(source, &index, &oid, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
/* Skip the hash of CN */
|
||||
/* Save reference to 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;
|
||||
resp->issuerHash = source + index;
|
||||
index += length;
|
||||
/* Skip the hash of the issuer public key */
|
||||
/* Save reference to 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;
|
||||
resp->issuerKeyHash = source + index;
|
||||
index += length;
|
||||
|
||||
/* Read the serial number, it is handled as a string, not as a
|
||||
@@ -4231,8 +4232,12 @@ static int DecodeSingleResponse(byte* source,
|
||||
if (GetBasicDate(source, &index, cs->thisDate,
|
||||
&cs->thisDateFormat, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
|
||||
if (source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
|
||||
|
||||
/* The following items are optional. Only check for them if there is more
|
||||
* unprocessed data in the singleResponse wrapper. */
|
||||
|
||||
if ((index - prevIndex < wrapperSz) &&
|
||||
(source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)))
|
||||
{
|
||||
index++;
|
||||
if (GetLength(source, &index, &length, size) < 0)
|
||||
@@ -4241,7 +4246,8 @@ static int DecodeSingleResponse(byte* source,
|
||||
&cs->nextDateFormat, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
if (source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
|
||||
if ((index - prevIndex < wrapperSz) &&
|
||||
(source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)))
|
||||
{
|
||||
index++;
|
||||
if (GetLength(source, &index, &length, size) < 0)
|
||||
@@ -4318,15 +4324,18 @@ static int DecodeOcspRespExtensions(byte* source,
|
||||
static int DecodeResponseData(byte* source,
|
||||
word32* ioIndex, OcspResponse* resp, word32 size)
|
||||
{
|
||||
word32 idx = *ioIndex;
|
||||
word32 idx = *ioIndex, prev_idx;
|
||||
int length;
|
||||
int version;
|
||||
word32 responderId = 0;
|
||||
|
||||
CYASSL_ENTER("DecodeResponseData");
|
||||
|
||||
resp->response = source + idx;
|
||||
prev_idx = idx;
|
||||
if (GetSequence(source, &idx, &length, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
resp->respBegin = idx;
|
||||
resp->respLength = length;
|
||||
resp->responseSz = length + idx - prev_idx;
|
||||
|
||||
/* 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
|
||||
@@ -4375,7 +4384,7 @@ static int DecodeCerts(byte* source,
|
||||
{
|
||||
word32 idx = *ioIndex;
|
||||
|
||||
(void)resp;
|
||||
CYASSL_ENTER("DecodeCerts");
|
||||
|
||||
if (source[idx++] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC))
|
||||
{
|
||||
@@ -4383,6 +4392,13 @@ static int DecodeCerts(byte* source,
|
||||
|
||||
if (GetLength(source, &idx, &length, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
|
||||
if (GetSequence(source, &idx, &length, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
|
||||
resp->cert = source + idx;
|
||||
resp->certSz = length;
|
||||
|
||||
idx += length;
|
||||
}
|
||||
*ioIndex = idx;
|
||||
@@ -4396,6 +4412,8 @@ static int DecodeBasicOcspResponse(byte* source,
|
||||
word32 idx = *ioIndex;
|
||||
word32 end_index;
|
||||
|
||||
CYASSL_ENTER("DecodeBasicOcspResponse");
|
||||
|
||||
if (GetSequence(source, &idx, &length, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
|
||||
@@ -4416,8 +4434,8 @@ static int DecodeBasicOcspResponse(byte* source,
|
||||
int sigLength = 0;
|
||||
if (GetLength(source, &idx, &sigLength, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
resp->sigLength = sigLength;
|
||||
resp->sigIndex = idx;
|
||||
resp->sigSz = sigLength;
|
||||
resp->sig = source + idx;
|
||||
idx += sigLength;
|
||||
}
|
||||
|
||||
@@ -4426,25 +4444,55 @@ static int DecodeBasicOcspResponse(byte* source,
|
||||
* see if there are certificates, they are optional.
|
||||
*/
|
||||
if (idx < end_index)
|
||||
return DecodeCerts(source, &idx, resp, size);
|
||||
{
|
||||
DecodedCert cert;
|
||||
int ret;
|
||||
|
||||
if (DecodeCerts(source, &idx, resp, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
|
||||
InitDecodedCert(&cert, resp->cert, resp->certSz, 0);
|
||||
ret = ParseCertRelative(&cert, CA_TYPE, NO_VERIFY, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ConfirmSignature(resp->response, resp->responseSz,
|
||||
cert.publicKey, cert.pubKeySize, cert.keyOID,
|
||||
resp->sig, resp->sigSz, resp->sigOID, NULL);
|
||||
FreeDecodedCert(&cert);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
CYASSL_MSG("\tConfirm signature failed");
|
||||
return ASN_SIG_CONFIRM_E;
|
||||
}
|
||||
}
|
||||
|
||||
*ioIndex = idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void InitOcspResponse(OcspResponse* resp, byte* source, word32 inSz, void* heap)
|
||||
void InitOcspResponse(OcspResponse* resp, CertStatus* status,
|
||||
byte* source, word32 inSz)
|
||||
{
|
||||
XMEMSET(resp, 0, sizeof(*resp));
|
||||
CYASSL_ENTER("InitOcspResponse");
|
||||
|
||||
resp->responseStatus = -1;
|
||||
resp->response = NULL;
|
||||
resp->responseSz = 0;
|
||||
resp->producedAt = NULL;
|
||||
resp->producedAtFormat = 0;
|
||||
resp->issuerHash = NULL;
|
||||
resp->issuerKeyHash = NULL;
|
||||
resp->sig = NULL;
|
||||
resp->sigSz = 0;
|
||||
resp->sigOID = 0;
|
||||
resp->status = status;
|
||||
resp->nonce = NULL;
|
||||
resp->nonceSz = 0;
|
||||
resp->source = source;
|
||||
resp->maxIdx = inSz;
|
||||
resp->heap = heap;
|
||||
}
|
||||
|
||||
|
||||
void FreeOcspResponse(OcspResponse* resp)
|
||||
{
|
||||
(void)resp;
|
||||
}
|
||||
|
||||
|
||||
@@ -4456,6 +4504,8 @@ int OcspResponseDecode(OcspResponse* resp)
|
||||
word32 size = resp->maxIdx;
|
||||
word32 oid;
|
||||
|
||||
CYASSL_ENTER("OcspResponseDecode");
|
||||
|
||||
/* peel the outer SEQUENCE wrapper */
|
||||
if (GetSequence(source, &idx, &length, size) < 0)
|
||||
return ASN_PARSE_E;
|
||||
@@ -4501,6 +4551,8 @@ static int SetSerialNumber(const byte* sn, word32 snSz, byte* output)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
CYASSL_ENTER("SetSerialNumber");
|
||||
|
||||
if (snSz <= EXTERNAL_SERIAL_SIZE) {
|
||||
output[0] = ASN_INTEGER;
|
||||
output[1] = snSz + 1;
|
||||
@@ -4520,6 +4572,8 @@ static word32 SetOcspReqExtensions(word32 extSz, byte* output,
|
||||
byte seqArray[5][MAX_SEQ_SZ];
|
||||
word32 seqSz[5], totalSz;
|
||||
|
||||
CYASSL_ENTER("SetOcspReqExtensions");
|
||||
|
||||
if (nonce == NULL || nonceSz == 0) return 0;
|
||||
|
||||
seqArray[0][0] = ASN_OCTET_STRING;
|
||||
@@ -4563,7 +4617,7 @@ static word32 SetOcspReqExtensions(word32 extSz, byte* output,
|
||||
}
|
||||
|
||||
|
||||
int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz)
|
||||
int EncodeOcspRequest(OcspRequest* req)
|
||||
{
|
||||
byte seqArray[5][MAX_SEQ_SZ];
|
||||
/* The ASN.1 of the OCSP Request is an onion of sequences */
|
||||
@@ -4572,29 +4626,34 @@ int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz)
|
||||
byte issuerKeyArray[MAX_ENCODED_DIG_SZ];
|
||||
byte snArray[MAX_SN_SZ];
|
||||
byte extArray[MAX_OCSP_EXT_SZ];
|
||||
byte nonceArray[MAX_OCSP_NONCE_SZ];
|
||||
byte* output = req->dest;
|
||||
word32 outputSz = req->destSz;
|
||||
RNG rng;
|
||||
word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, nonceSz,
|
||||
extSz, totalSz;
|
||||
word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, extSz, totalSz;
|
||||
int i;
|
||||
|
||||
(void)outputSz;
|
||||
|
||||
CYASSL_ENTER("EncodeOcspRequest");
|
||||
|
||||
algoSz = SetAlgoID(SHAh, algoArray, hashType);
|
||||
issuerSz = SetDigest(cert->issuerHash, SHA_SIZE, issuerArray);
|
||||
issuerKeySz = SetDigest(cert->issuerKeyHash, SHA_SIZE, issuerKeyArray);
|
||||
snSz = SetSerialNumber(cert->serial, cert->serialSz, snArray);
|
||||
|
||||
req->issuerHash = req->cert->issuerHash;
|
||||
issuerSz = SetDigest(req->cert->issuerHash, SHA_SIZE, issuerArray);
|
||||
|
||||
req->issuerKeyHash = req->cert->issuerKeyHash;
|
||||
issuerKeySz = SetDigest(req->cert->issuerKeyHash, SHA_SIZE, issuerKeyArray);
|
||||
|
||||
req->serial = req->cert->serial;
|
||||
req->serialSz = req->cert->serialSz;
|
||||
snSz = SetSerialNumber(req->cert->serial, req->cert->serialSz, snArray);
|
||||
|
||||
if (InitRng(&rng) != 0) {
|
||||
CYASSL_MSG("\tCannot initialize RNG. Skipping the OSCP Nonce.");
|
||||
nonceSz = 0;
|
||||
extSz = 0;
|
||||
} else {
|
||||
nonceSz = MAX_OCSP_NONCE_SZ;
|
||||
RNG_GenerateBlock(&rng, nonceArray, nonceSz);
|
||||
req->nonceSz = MAX_OCSP_NONCE_SZ;
|
||||
RNG_GenerateBlock(&rng, req->nonce, req->nonceSz);
|
||||
extSz = SetOcspReqExtensions(MAX_OCSP_EXT_SZ, extArray,
|
||||
nonceArray, nonceSz);
|
||||
req->nonce, req->nonceSz);
|
||||
}
|
||||
|
||||
totalSz = algoSz + issuerSz + issuerKeySz + snSz;
|
||||
@@ -4626,12 +4685,18 @@ int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz)
|
||||
}
|
||||
|
||||
|
||||
void InitOcspRequest(OcspRequest* req, byte* dest, word32 destSz, void* heap)
|
||||
void InitOcspRequest(OcspRequest* req, DecodedCert* cert,
|
||||
byte* dest, word32 destSz)
|
||||
{
|
||||
XMEMSET(req, 0, sizeof(*req));
|
||||
CYASSL_ENTER("InitOcspRequest");
|
||||
|
||||
req->cert = cert;
|
||||
req->nonceSz = 0;
|
||||
req->issuerHash = NULL;
|
||||
req->issuerKeyHash = NULL;
|
||||
req->serial = NULL;
|
||||
req->dest = dest;
|
||||
req->destSz = destSz;
|
||||
req->heap = heap;
|
||||
}
|
||||
|
||||
|
||||
@@ -4639,14 +4704,61 @@ int CompareOcspReqResp(OcspRequest* req, OcspResponse* resp)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
if (req == NULL) return -1;
|
||||
if (resp == NULL) return 1;
|
||||
CYASSL_ENTER("CompareOcspReqResp");
|
||||
|
||||
if (req == NULL)
|
||||
{
|
||||
CYASSL_MSG("\tReq missing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (resp == NULL)
|
||||
{
|
||||
CYASSL_MSG("\tResp missing");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cmp = req->nonceSz - resp->nonceSz;
|
||||
if (cmp != 0) return cmp;
|
||||
if (cmp != 0)
|
||||
{
|
||||
CYASSL_MSG("\tnonceSz mismatch");
|
||||
return cmp;
|
||||
}
|
||||
|
||||
cmp = XMEMCMP(req->nonce, resp->nonce, req->nonceSz);
|
||||
if (cmp != 0) return cmp;
|
||||
if (cmp != 0)
|
||||
{
|
||||
CYASSL_MSG("\tnonce mismatch");
|
||||
return cmp;
|
||||
}
|
||||
|
||||
cmp = XMEMCMP(req->issuerHash, resp->issuerHash, SHA_DIGEST_SIZE);
|
||||
if (cmp != 0)
|
||||
{
|
||||
CYASSL_MSG("\tissuerHash mismatch");
|
||||
return cmp;
|
||||
}
|
||||
|
||||
cmp = XMEMCMP(req->issuerKeyHash, resp->issuerKeyHash, SHA_DIGEST_SIZE);
|
||||
if (cmp != 0)
|
||||
{
|
||||
CYASSL_MSG("\tissuerKeyHash mismatch");
|
||||
return cmp;
|
||||
}
|
||||
|
||||
cmp = req->serialSz - resp->status->serialSz;
|
||||
if (cmp != 0)
|
||||
{
|
||||
CYASSL_MSG("\tserialSz mismatch");
|
||||
return cmp;
|
||||
}
|
||||
|
||||
cmp = XMEMCMP(req->serial, resp->status->serial, req->serialSz);
|
||||
if (cmp != 0)
|
||||
{
|
||||
CYASSL_MSG("\tserial mismatch");
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -358,68 +358,69 @@ typedef struct OcspResponse OcspResponse;
|
||||
|
||||
|
||||
struct CertStatus {
|
||||
CertStatus* next;
|
||||
CertStatus* next;
|
||||
|
||||
byte serial[EXTERNAL_SERIAL_SIZE];
|
||||
int serialSz;
|
||||
byte serial[EXTERNAL_SERIAL_SIZE];
|
||||
int serialSz;
|
||||
|
||||
int status;
|
||||
|
||||
byte thisDate[MAX_DATE_SIZE];
|
||||
byte nextDate[MAX_DATE_SIZE];
|
||||
byte thisDateFormat;
|
||||
byte nextDateFormat;
|
||||
byte thisDate[MAX_DATE_SIZE];
|
||||
byte nextDate[MAX_DATE_SIZE];
|
||||
byte thisDateFormat;
|
||||
byte nextDateFormat;
|
||||
};
|
||||
|
||||
|
||||
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 */
|
||||
byte* response; /* Pointer to beginning of OCSP Response */
|
||||
word32 responseSz; /* length of the OCSP Response */
|
||||
|
||||
byte* producedAt; /* Time at which this response was signed */
|
||||
byte producedAtFormat;/* format of the producedAt date */
|
||||
byte producedAtFormat;/* format of the producedAt date */
|
||||
byte* issuerHash;
|
||||
byte* issuerKeyHash;
|
||||
|
||||
word32 sigIndex; /* Index into source for start of sig */
|
||||
word32 sigLength; /* Length in octets for the sig */
|
||||
byte* cert;
|
||||
word32 certSz;
|
||||
|
||||
byte* sig; /* Pointer to sig in source */
|
||||
word32 sigSz; /* Length in octets for the sig */
|
||||
word32 sigOID; /* OID for hash used for sig */
|
||||
|
||||
CertStatus status[1]; /* list of certificate status */
|
||||
CertStatus* status; /* certificate status to fill out */
|
||||
|
||||
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 */
|
||||
void* heap; /* for user memory overrides */
|
||||
};
|
||||
|
||||
|
||||
struct OcspRequest {
|
||||
byte* nonce;
|
||||
DecodedCert* cert;
|
||||
|
||||
byte nonce[MAX_OCSP_NONCE_SZ];
|
||||
int nonceSz;
|
||||
|
||||
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* 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;
|
||||
};
|
||||
|
||||
|
||||
CYASSL_LOCAL void InitOcspResponse(OcspResponse*, byte*, word32, void*);
|
||||
CYASSL_LOCAL void FreeOcspResponse(OcspResponse*);
|
||||
CYASSL_LOCAL void InitOcspResponse(OcspResponse*, CertStatus*, byte*, word32);
|
||||
CYASSL_LOCAL int OcspResponseDecode(OcspResponse*);
|
||||
|
||||
CYASSL_LOCAL void InitOcspRequest(OcspRequest*, byte*, word32, void*);
|
||||
CYASSL_LOCAL void FreeOcspRequest(OcspRequest*);
|
||||
CYASSL_LOCAL int EncodeOcspRequest(DecodedCert*, byte*, word32);
|
||||
CYASSL_LOCAL void InitOcspRequest(OcspRequest*, DecodedCert*, byte*, word32);
|
||||
CYASSL_LOCAL int EncodeOcspRequest(OcspRequest*);
|
||||
|
||||
CYASSL_LOCAL int CompareOcspReqResp(OcspRequest*, OcspResponse*);
|
||||
|
||||
|
@@ -630,7 +630,7 @@ 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 */
|
||||
CertStatus* status; /* OCSP response list */
|
||||
int totalStatus; /* number on list */
|
||||
};
|
||||
|
||||
@@ -642,7 +642,7 @@ struct CYASSL_OCSP {
|
||||
char overrideName[80];
|
||||
char overridePath[80];
|
||||
int overridePort;
|
||||
OCSP_Entry ocspList[1];
|
||||
OCSP_Entry* ocspList;
|
||||
};
|
||||
|
||||
|
||||
|
420
src/ocsp.c
420
src/ocsp.c
@@ -51,29 +51,6 @@ typedef struct sockaddr_in SOCKADDR_IN_T;
|
||||
#define SOCKET_T unsigned int
|
||||
|
||||
|
||||
int ocsp_test(unsigned char* buf, int sz)
|
||||
{
|
||||
CYASSL_OCSP ocsp;
|
||||
OcspResponse resp;
|
||||
int result;
|
||||
|
||||
CyaSSL_OCSP_Init(&ocsp);
|
||||
InitOcspResponse(&resp, buf, sz, NULL);
|
||||
|
||||
ocsp.enabled = 1;
|
||||
ocsp.useOverrideUrl = 1;
|
||||
CyaSSL_OCSP_set_override_url(&ocsp, "http://ocsp.example.com:8080/bob");
|
||||
CyaSSL_OCSP_Lookup_Cert(&ocsp, NULL);
|
||||
|
||||
result = OcspResponseDecode(&resp);
|
||||
|
||||
FreeOcspResponse(&resp);
|
||||
CyaSSL_OCSP_Cleanup(&ocsp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int CyaSSL_OCSP_Init(CYASSL_OCSP* ocsp)
|
||||
{
|
||||
if (ocsp != NULL) {
|
||||
@@ -85,83 +62,105 @@ int CyaSSL_OCSP_Init(CYASSL_OCSP* ocsp)
|
||||
}
|
||||
|
||||
|
||||
static void FreeOCSP_Entry(OCSP_Entry* ocspe)
|
||||
{
|
||||
CertStatus* tmp = ocspe->status;
|
||||
|
||||
CYASSL_ENTER("FreeOCSP_Entry");
|
||||
|
||||
while (tmp) {
|
||||
CertStatus* next = tmp->next;
|
||||
XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS);
|
||||
tmp = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CyaSSL_OCSP_Cleanup(CYASSL_OCSP* ocsp)
|
||||
{
|
||||
OCSP_Entry* tmp = ocsp->ocspList;
|
||||
|
||||
ocsp->enabled = 0;
|
||||
while (tmp) {
|
||||
OCSP_Entry* next = tmp->next;
|
||||
FreeOCSP_Entry(tmp);
|
||||
XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
|
||||
tmp = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int decode_url(const char* url, int urlSz,
|
||||
char* outName, char* outPath, int* outPort)
|
||||
char* outName, char* outPath, int* outPort)
|
||||
{
|
||||
if (outName != NULL && outPath != NULL && outPort != NULL)
|
||||
{
|
||||
if (url == NULL || urlSz == 0)
|
||||
{
|
||||
*outName = 0;
|
||||
*outPath = 0;
|
||||
*outPort = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, cur;
|
||||
|
||||
/* need to break the url down into scheme, address, and port */
|
||||
/* "http://example.com:8080/" */
|
||||
if (XSTRNCMP(url, "http://", 7) == 0) {
|
||||
cur = 7;
|
||||
} else cur = 0;
|
||||
|
||||
i = 0;
|
||||
while (url[cur] != 0 && url[cur] != ':' && url[cur] != '/') {
|
||||
outName[i++] = url[cur++];
|
||||
}
|
||||
outName[i] = 0;
|
||||
/* Need to pick out the path after the domain name */
|
||||
|
||||
if (cur < urlSz && url[cur] == ':') {
|
||||
char port[6];
|
||||
int j;
|
||||
i = 0;
|
||||
cur++;
|
||||
while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
|
||||
i < 6) {
|
||||
port[i++] = url[cur++];
|
||||
}
|
||||
|
||||
*outPort = 0;
|
||||
for (j = 0; j < i; j++) {
|
||||
if (port[j] < '0' || port[j] > '9') return -1;
|
||||
*outPort = (*outPort * 10) + (port[j] - '0');
|
||||
}
|
||||
}
|
||||
else
|
||||
*outPort = 80;
|
||||
|
||||
if (cur < urlSz && url[cur] == '/') {
|
||||
i = 0;
|
||||
while (cur < urlSz && url[cur] != 0 && i < 80) {
|
||||
outPath[i++] = url[cur++];
|
||||
}
|
||||
outPath[i] = 0;
|
||||
}
|
||||
else {
|
||||
outPath[0] = '/';
|
||||
outPath[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outName != NULL && outPath != NULL && outPort != NULL)
|
||||
{
|
||||
if (url == NULL || urlSz == 0)
|
||||
{
|
||||
*outName = 0;
|
||||
*outPath = 0;
|
||||
*outPort = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, cur;
|
||||
|
||||
/* need to break the url down into scheme, address, and port */
|
||||
/* "http://example.com:8080/" */
|
||||
if (XSTRNCMP(url, "http://", 7) == 0) {
|
||||
cur = 7;
|
||||
} else cur = 0;
|
||||
|
||||
i = 0;
|
||||
while (url[cur] != 0 && url[cur] != ':' && url[cur] != '/') {
|
||||
outName[i++] = url[cur++];
|
||||
}
|
||||
outName[i] = 0;
|
||||
/* Need to pick out the path after the domain name */
|
||||
|
||||
if (cur < urlSz && url[cur] == ':') {
|
||||
char port[6];
|
||||
int j;
|
||||
i = 0;
|
||||
cur++;
|
||||
while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
|
||||
i < 6) {
|
||||
port[i++] = url[cur++];
|
||||
}
|
||||
|
||||
*outPort = 0;
|
||||
for (j = 0; j < i; j++) {
|
||||
if (port[j] < '0' || port[j] > '9') return -1;
|
||||
*outPort = (*outPort * 10) + (port[j] - '0');
|
||||
}
|
||||
}
|
||||
else
|
||||
*outPort = 80;
|
||||
|
||||
if (cur < urlSz && url[cur] == '/') {
|
||||
i = 0;
|
||||
while (cur < urlSz && url[cur] != 0 && i < 80) {
|
||||
outPath[i++] = url[cur++];
|
||||
}
|
||||
outPath[i] = 0;
|
||||
}
|
||||
else {
|
||||
outPath[0] = '/';
|
||||
outPath[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CyaSSL_OCSP_set_override_url(CYASSL_OCSP* ocsp, const char* url)
|
||||
{
|
||||
if (ocsp != NULL) {
|
||||
int urlSz = strlen(url);
|
||||
decode_url(url, urlSz,
|
||||
ocsp->overrideName, ocsp->overridePath, &ocsp->overridePort);
|
||||
int urlSz = strlen(url);
|
||||
decode_url(url, urlSz,
|
||||
ocsp->overrideName, ocsp->overridePath, &ocsp->overridePort);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -214,7 +213,7 @@ static INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
|
||||
|
||||
|
||||
static int build_http_request(const char* domainName, const char* path,
|
||||
int ocspReqSz, byte* buf, int bufSize)
|
||||
int ocspReqSz, byte* buf, int bufSize)
|
||||
{
|
||||
return snprintf((char*)buf, bufSize,
|
||||
"POST %s HTTP/1.1\r\n"
|
||||
@@ -226,22 +225,23 @@ static int build_http_request(const char* domainName, const char* path,
|
||||
}
|
||||
|
||||
|
||||
static byte* decode_http_response(byte* httpBuf, int httpBufSz, int* ocspRespSz)
|
||||
static int decode_http_response(byte* httpBuf, int httpBufSz, byte** dst)
|
||||
{
|
||||
int idx = 0;
|
||||
int stop = 0;
|
||||
int len = 0;
|
||||
byte* contentType = NULL;
|
||||
byte* contentLength = NULL;
|
||||
char* buf = (char*)httpBuf; /* kludge so I'm not constantly casting */
|
||||
|
||||
if (strncasecmp(buf, "HTTP/1", 6) != 0)
|
||||
return NULL;
|
||||
return 0;
|
||||
|
||||
idx = 9; /* sets to the first byte after "HTTP/1.X ", which should be the
|
||||
* HTTP result code */
|
||||
|
||||
if (strncasecmp(&buf[idx], "200 OK", 6) != 0)
|
||||
return NULL;
|
||||
return 0;
|
||||
|
||||
idx += 8;
|
||||
|
||||
@@ -256,18 +256,16 @@ static byte* decode_http_response(byte* httpBuf, int httpBufSz, int* ocspRespSz)
|
||||
idx += 13;
|
||||
if (buf[idx] == ' ') idx++;
|
||||
if (strncasecmp(&buf[idx], "application/ocsp-response", 25) != 0)
|
||||
return NULL;
|
||||
return 0;
|
||||
idx += 27;
|
||||
} else if (contentLength == NULL &&
|
||||
strncasecmp(&buf[idx], "Content-Length:", 15) == 0) {
|
||||
int len = 0;
|
||||
idx += 15;
|
||||
if (buf[idx] == ' ') idx++;
|
||||
while (buf[idx] >= '0' && buf[idx] <= '9' && idx < httpBufSz) {
|
||||
len = (len * 10) + (buf[idx] - '0');
|
||||
idx++;
|
||||
}
|
||||
*ocspRespSz = len;
|
||||
idx += 2; /* skip the crlf */
|
||||
} else {
|
||||
/* Advance idx past the next \r\n */
|
||||
@@ -277,52 +275,128 @@ static byte* decode_http_response(byte* httpBuf, int httpBufSz, int* ocspRespSz)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &httpBuf[idx];
|
||||
|
||||
if (len > 0) {
|
||||
*dst = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_IN_BUFFER);
|
||||
XMEMCPY(*dst, httpBuf + idx, len);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
|
||||
{
|
||||
CYASSL_ENTER("InitOCSP_Entry");
|
||||
|
||||
ocspe->next = NULL;
|
||||
XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
|
||||
XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
|
||||
ocspe->status = NULL;
|
||||
ocspe->totalStatus = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static OCSP_Entry* find_ocsp_entry(CYASSL_OCSP* ocsp, DecodedCert* cert)
|
||||
{
|
||||
OCSP_Entry* entry = ocsp->ocspList;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (XMEMCMP(entry->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0
|
||||
&& XMEMCMP(entry->issuerKeyHash, cert->issuerKeyHash,
|
||||
SHA_DIGEST_SIZE) == 0)
|
||||
{
|
||||
CYASSL_MSG("Found OCSP responder");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry == NULL)
|
||||
{
|
||||
CYASSL_MSG("Add a new OCSP entry");
|
||||
entry = (OCSP_Entry*)XMALLOC(sizeof(OCSP_Entry),
|
||||
NULL, DYNAMIC_TYPE_OCSP_ENTRY);
|
||||
if (entry != NULL)
|
||||
{
|
||||
InitOCSP_Entry(entry, cert);
|
||||
entry->next = ocsp->ocspList;
|
||||
ocsp->ocspList = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static CertStatus* find_cert_status(OCSP_Entry* ocspe, DecodedCert* cert)
|
||||
{
|
||||
CertStatus* stat = ocspe->status;
|
||||
|
||||
while (stat)
|
||||
{
|
||||
if(stat->serialSz == cert->serialSz &&
|
||||
(XMEMCMP(stat->serial, cert->serial, cert->serialSz) == 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
stat = stat->next;
|
||||
}
|
||||
}
|
||||
if (stat == NULL)
|
||||
{
|
||||
stat = (CertStatus*)XMALLOC(sizeof(CertStatus),
|
||||
NULL, DYNAMIC_TYPE_OCSP_STATUS);
|
||||
if (stat != NULL)
|
||||
{
|
||||
XMEMCPY(stat->serial, cert->serial, cert->serialSz);
|
||||
stat->serialSz = cert->serialSz;
|
||||
stat->status = -1;
|
||||
ocspe->totalStatus++;
|
||||
|
||||
stat->next = ocspe->status;
|
||||
ocspe->status = stat;
|
||||
}
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
#define SCRATCH_BUFFER_SIZE 2048
|
||||
|
||||
int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
|
||||
static int http_ocsp_transaction(CYASSL_OCSP* ocsp, DecodedCert* cert,
|
||||
byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
|
||||
{
|
||||
SOCKET_T sfd = -1;
|
||||
byte buf[SCRATCH_BUFFER_SIZE];
|
||||
byte* httpBuf = &buf[0];
|
||||
int httpBufSz = SCRATCH_BUFFER_SIZE/4;
|
||||
byte* ocspReqBuf = &buf[httpBufSz];
|
||||
int ocspReqSz = SCRATCH_BUFFER_SIZE - httpBufSz;
|
||||
OcspResponse ocspResponse;
|
||||
int result = 0;
|
||||
char domainName[80], path[80];
|
||||
int port;
|
||||
|
||||
/* If OCSP lookups are disabled, return success. */
|
||||
if (!ocsp->enabled) {
|
||||
CYASSL_MSG("OCSP lookup disabled, assuming CERT_GOOD");
|
||||
return 0;
|
||||
}
|
||||
byte httpBuf[SCRATCH_BUFFER_SIZE];
|
||||
int httpBufSz = SCRATCH_BUFFER_SIZE;
|
||||
char domainName[80], path[80];
|
||||
int port, ocspRespSz;
|
||||
|
||||
if (ocsp->useOverrideUrl || cert->extAuthInfo == NULL) {
|
||||
if (ocsp->overrideName != NULL) {
|
||||
XMEMCPY(domainName, ocsp->overrideName, 80);
|
||||
XMEMCPY(path, ocsp->overridePath, 80);
|
||||
port = ocsp->overridePort;
|
||||
} else
|
||||
return OCSP_NEED_URL;
|
||||
} else {
|
||||
if (!decode_url((const char*)cert->extAuthInfo, cert->extAuthInfoSz,
|
||||
domainName, path, &port))
|
||||
return OCSP_NEED_URL;
|
||||
}
|
||||
if (ocsp->overrideName != NULL) {
|
||||
XMEMCPY(domainName, ocsp->overrideName, 80);
|
||||
XMEMCPY(path, ocsp->overridePath, 80);
|
||||
port = ocsp->overridePort;
|
||||
} else
|
||||
return OCSP_NEED_URL;
|
||||
} else {
|
||||
if (!decode_url((const char*)cert->extAuthInfo, cert->extAuthInfoSz,
|
||||
domainName, path, &port))
|
||||
return OCSP_NEED_URL;
|
||||
}
|
||||
|
||||
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,
|
||||
httpBuf, httpBufSz);
|
||||
httpBuf, httpBufSz);
|
||||
|
||||
tcp_connect(&sfd, domainName, port);
|
||||
if (sfd > 0) {
|
||||
@@ -331,15 +405,15 @@ int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
|
||||
if (written == httpBufSz) {
|
||||
written = write(sfd, ocspReqBuf, ocspReqSz);
|
||||
if (written == ocspReqSz) {
|
||||
httpBufSz = read(sfd, buf, SCRATCH_BUFFER_SIZE);
|
||||
httpBufSz = read(sfd, httpBuf, SCRATCH_BUFFER_SIZE);
|
||||
if (httpBufSz > 0) {
|
||||
ocspReqBuf = decode_http_response(buf, httpBufSz,
|
||||
&ocspReqSz);
|
||||
ocspRespSz = decode_http_response(httpBuf, httpBufSz,
|
||||
ocspRespBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
close(sfd);
|
||||
if (ocspReqBuf == NULL) {
|
||||
if (ocspRespSz == 0) {
|
||||
CYASSL_MSG("HTTP response was not OK, no OCSP response");
|
||||
return OCSP_LOOKUP_FAIL;
|
||||
}
|
||||
@@ -348,26 +422,82 @@ int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
|
||||
return OCSP_LOOKUP_FAIL;
|
||||
}
|
||||
|
||||
InitOcspResponse(&ocspResponse, ocspReqBuf, ocspReqSz, NULL);
|
||||
return ocspRespSz;
|
||||
}
|
||||
|
||||
|
||||
int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
|
||||
{
|
||||
byte ocspReqBuf[SCRATCH_BUFFER_SIZE];
|
||||
int ocspReqSz = SCRATCH_BUFFER_SIZE;
|
||||
byte* ocspRespBuf = NULL;
|
||||
int ocspRespSz;
|
||||
OcspRequest ocspRequest;
|
||||
OcspResponse ocspResponse;
|
||||
int result = 0;
|
||||
OCSP_Entry* ocspe;
|
||||
CertStatus* certStatus;
|
||||
|
||||
/* If OCSP lookups are disabled, return success. */
|
||||
if (!ocsp->enabled) {
|
||||
CYASSL_MSG("OCSP lookup disabled, assuming CERT_GOOD");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ocspe = find_ocsp_entry(ocsp, cert);
|
||||
if (ocspe == NULL) {
|
||||
CYASSL_MSG("alloc OCSP entry failed");
|
||||
return MEMORY_ERROR;
|
||||
}
|
||||
|
||||
certStatus = find_cert_status(ocspe, cert);
|
||||
if (certStatus == NULL)
|
||||
{
|
||||
CYASSL_MSG("alloc OCSP cert status failed");
|
||||
return MEMORY_ERROR;
|
||||
}
|
||||
|
||||
if (certStatus->status != -1)
|
||||
{
|
||||
}
|
||||
|
||||
InitOcspRequest(&ocspRequest, cert, ocspReqBuf, ocspReqSz);
|
||||
ocspReqSz = EncodeOcspRequest(&ocspRequest);
|
||||
result = http_ocsp_transaction(ocsp, cert,
|
||||
ocspReqBuf, ocspReqSz, &ocspRespBuf);
|
||||
if (result < 0) return result;
|
||||
/* If the transaction failed, return that result. */
|
||||
|
||||
InitOcspResponse(&ocspResponse, certStatus, ocspRespBuf, ocspRespSz);
|
||||
OcspResponseDecode(&ocspResponse);
|
||||
|
||||
if (ocspResponse.responseStatus != OCSP_SUCCESSFUL) {
|
||||
CYASSL_MSG("OCSP Responder failure");
|
||||
result = OCSP_LOOKUP_FAIL;
|
||||
result = OCSP_LOOKUP_FAIL;
|
||||
} else {
|
||||
switch (ocspResponse.status[0].status) {
|
||||
case CERT_GOOD:
|
||||
result = 0;
|
||||
break;
|
||||
case CERT_REVOKED:
|
||||
result = OCSP_CERT_REVOKED;
|
||||
break;
|
||||
default:
|
||||
result = OCSP_CERT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (CompareOcspReqResp(&ocspRequest, &ocspResponse) == 0)
|
||||
{
|
||||
switch (ocspResponse.status[0].status) {
|
||||
case CERT_GOOD:
|
||||
result = 0;
|
||||
break;
|
||||
case CERT_REVOKED:
|
||||
result = OCSP_CERT_REVOKED;
|
||||
break;
|
||||
default:
|
||||
result = OCSP_CERT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CYASSL_MSG("OCSP Response incorrect for Request");
|
||||
result = OCSP_LOOKUP_FAIL;
|
||||
}
|
||||
}
|
||||
if (ocspReqBuf != NULL) {
|
||||
XFREE(ocspRespBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
|
||||
}
|
||||
FreeOcspResponse(&ocspResponse);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user