From 4b3a362705b44a35bb9fac0d47f5c29b626c8696 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 18 May 2012 10:18:56 -0700 Subject: [PATCH] adding OcspRequest data, check OCSP nonce extension, made ConfirmSignature generic, bug fixes --- ctaocrypt/src/asn.c | 277 ++++++++++++++++++++++++++++++++--------- cyassl/ctaocrypt/asn.h | 28 ++++- 2 files changed, 246 insertions(+), 59 deletions(-) diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index a392b0d6e..c4806de84 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef HAVE_NTRU #include "crypto_ntru.h" @@ -1887,8 +1888,10 @@ word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID) /* return true (1) for Confirmation */ -static int ConfirmSignature(DecodedCert* cert, const byte* key, word32 keySz, - word32 keyOID) +static int ConfirmSignature(const byte* buf, word32 bufSz, + const byte* key, word32 keySz, word32 keyOID, + const byte* sig, word32 sigSz, word32 sigOID, + void* heap) { #ifdef CYASSL_SHA512 byte digest[SHA512_DIGEST_SIZE]; /* max size */ @@ -1899,57 +1902,52 @@ static int ConfirmSignature(DecodedCert* cert, const byte* key, word32 keySz, #endif int typeH, digestSz, ret; - if (cert->signatureOID == CTC_MD5wRSA) { + if (sigOID == CTC_MD5wRSA) { Md5 md5; InitMd5(&md5); - Md5Update(&md5, cert->source + cert->certBegin, - cert->sigIndex - cert->certBegin); + Md5Update(&md5, buf, bufSz); Md5Final(&md5, digest); typeH = MD5h; digestSz = MD5_DIGEST_SIZE; } - else if (cert->signatureOID == CTC_SHAwRSA || - cert->signatureOID == CTC_SHAwDSA || - cert->signatureOID == CTC_SHAwECDSA) { + else if (sigOID == CTC_SHAwRSA || + sigOID == CTC_SHAwDSA || + sigOID == CTC_SHAwECDSA) { Sha sha; InitSha(&sha); - ShaUpdate(&sha, cert->source + cert->certBegin, - cert->sigIndex - cert->certBegin); + ShaUpdate(&sha, buf, bufSz); ShaFinal(&sha, digest); typeH = SHAh; digestSz = SHA_DIGEST_SIZE; } #ifndef NO_SHA256 - else if (cert->signatureOID == CTC_SHA256wRSA || - cert->signatureOID == CTC_SHA256wECDSA) { + else if (sigOID == CTC_SHA256wRSA || + sigOID == CTC_SHA256wECDSA) { Sha256 sha256; InitSha256(&sha256); - Sha256Update(&sha256, cert->source + cert->certBegin, - cert->sigIndex - cert->certBegin); + Sha256Update(&sha256, buf, bufSz); Sha256Final(&sha256, digest); typeH = SHA256h; digestSz = SHA256_DIGEST_SIZE; } #endif #ifdef CYASSL_SHA512 - else if (cert->signatureOID == CTC_SHA512wRSA || - cert->signatureOID == CTC_SHA512wECDSA) { + else if (sigOID == CTC_SHA512wRSA || + sigOID == CTC_SHA512wECDSA) { Sha512 sha512; InitSha512(&sha512); - Sha512Update(&sha512, cert->source + cert->certBegin, - cert->sigIndex - cert->certBegin); + Sha512Update(&sha512, buf, bufSz); Sha512Final(&sha512, digest); typeH = SHA512h; digestSz = SHA512_DIGEST_SIZE; } #endif #ifdef CYASSL_SHA384 - else if (cert->signatureOID == CTC_SHA384wRSA || - cert->signatureOID == CTC_SHA384wECDSA) { + else if (sigOID == CTC_SHA384wRSA || + sigOID == CTC_SHA384wECDSA) { Sha384 sha384; InitSha384(&sha384); - Sha384Update(&sha384, cert->source + cert->certBegin, - cert->sigIndex - cert->certBegin); + Sha384Update(&sha384, buf, bufSz); Sha384Final(&sha384, digest); typeH = SHA384h; digestSz = SHA384_DIGEST_SIZE; @@ -1965,30 +1963,32 @@ static int ConfirmSignature(DecodedCert* cert, const byte* key, word32 keySz, byte encodedSig[MAX_ENCODED_SIG_SZ]; byte plain[MAX_ENCODED_SIG_SZ]; word32 idx = 0; - int sigSz, verifySz; + int encodedSigSz, verifySz; byte* out; - if (cert->sigLength > MAX_ENCODED_SIG_SZ) { + if (sigSz > MAX_ENCODED_SIG_SZ) { CYASSL_MSG("Verify Signautre is too big"); return 0; } - InitRsaKey(&pubKey, cert->heap); + InitRsaKey(&pubKey, heap); if (RsaPublicKeyDecode(key, &idx, &pubKey, keySz) < 0) { CYASSL_MSG("ASN Key decode error RSA"); ret = 0; } else { - XMEMCPY(plain, cert->signature, cert->sigLength); - if ( (verifySz = RsaSSL_VerifyInline(plain, cert->sigLength, &out, + XMEMCPY(plain, sig, sigSz); + if ( (verifySz = RsaSSL_VerifyInline(plain, sigSz, &out, &pubKey)) < 0) { CYASSL_MSG("Rsa SSL verify error"); ret = 0; } else { /* make sure we're right justified */ - sigSz = EncodeSignature(encodedSig, digest, digestSz, typeH); - if (sigSz != verifySz || XMEMCMP(out, encodedSig, sigSz) != 0){ + encodedSigSz = + EncodeSignature(encodedSig, digest, digestSz, typeH); + if (encodedSigSz != verifySz || + XMEMCMP(out, encodedSig, encodedSigSz) != 0) { CYASSL_MSG("Rsa SSL verify match encode error"); ret = 0; } @@ -2029,8 +2029,7 @@ static int ConfirmSignature(DecodedCert* cert, const byte* key, word32 keySz, return 0; } - ret = ecc_verify_hash(cert->signature, cert->sigLength, digest, - digestSz, &verify, &pubKey); + ret = ecc_verify_hash(sig, sigSz, digest, digestSz, &verify, &pubKey); ecc_free(&pubKey); if (ret == 0 && verify == 1) return 1; /* match */ @@ -2213,7 +2212,7 @@ static void DecodeCertExtensions(DecodedCert* cert) if (input == NULL || sz == 0) return; - if (input[index++] != ASN_EXTENSIONS)return; + if (input[index++] != ASN_EXTENSIONS) return; if (GetLength(input, &index, &length, sz) < 0) return; @@ -2366,8 +2365,11 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) } #endif /* HAVE_OCSP */ /* try to confirm/verify signature */ - if (!ConfirmSignature(cert, ca->publicKey, - ca->pubKeySize, ca->keyOID)) { + if (!ConfirmSignature(cert->source + cert->certBegin, + cert->sigIndex - cert->certBegin, + ca->publicKey, ca->pubKeySize, ca->keyOID, + cert->signature, cert->sigLength, cert->signatureOID, + cert->heap)) { CYASSL_MSG("Confirm signature failed"); return ASN_SIG_CONFIRM_E; } @@ -3994,10 +3996,8 @@ static int GetEnumerated(const byte* input, word32* inOutIdx, int *value) static int DecodeSingleResponse(byte* source, word32* ioIndex, OcspResponse* resp, word32 size) { - word32 index = *ioIndex, prevIndex, oid, mpi_len; + word32 index = *ioIndex, prevIndex, oid; 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) @@ -4031,19 +4031,24 @@ static int DecodeSingleResponse(byte* source, return ASN_PARSE_E; index += length; - /* Read the serial number */ - if (GetInt(&mpi, source, &index, size) < 0) + /* 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; - 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; + 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; } - mp_clear(&mpi); + index += length; /* CertStatus */ switch (source[index++]) @@ -4057,7 +4062,7 @@ static int DecodeSingleResponse(byte* source, GetLength(source, &index, &length, size); index += length; break; - case (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | CERT_UNKNOWN): + case (ASN_CONTEXT_SPECIFIC | CERT_UNKNOWN): resp->certStatus[qty] = CERT_UNKNOWN; index++; break; @@ -4070,6 +4075,7 @@ static int DecodeSingleResponse(byte* source, if (GetLength(source, &index, &length, size) < 0) return ASN_PARSE_E; + resp->thisUpdate = source + index; index += length; remainder = remainder + prevIndex - index; @@ -4082,6 +4088,67 @@ static int DecodeSingleResponse(byte* source, return 0; } +static int DecodeOcspRespExtensions(byte* source, + word32* ioIndex, OcspResponse* resp, word32 sz) +{ + word32 index = *ioIndex; + int length; + int ext_bound; /* boundary index for the sequence of extensions */ + word32 oid; + + CYASSL_ENTER("DecodeOcspRespExtensions"); + + if (source[index++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) + return ASN_PARSE_E; + + if (GetLength(source, &index, &length, sz) < 0) return ASN_PARSE_E; + + if (GetSequence(source, &index, &length, sz) < 0) return ASN_PARSE_E; + + ext_bound = index + length; + + while (index < ext_bound) { + if (GetSequence(source, &index, &length, sz) < 0) { + CYASSL_MSG("\tfail: should be a SEQUENCE"); + return ASN_PARSE_E; + } + + oid = 0; + if (GetObjectId(source, &index, &oid, sz) < 0) { + CYASSL_MSG("\tfail: OBJECT ID"); + return ASN_PARSE_E; + } + + /* check for critical flag */ + if (source[index] == ASN_BOOLEAN) { + CYASSL_MSG("\tfound optional critical flag, moving past"); + index += (ASN_BOOL_SIZE + 1); + } + + /* process the extension based on the OID */ + if (source[index++] != ASN_OCTET_STRING) { + CYASSL_MSG("\tfail: should be an OCTET STRING"); + return ASN_PARSE_E; + } + + if (GetLength(source, &index, &length, sz) < 0) { + CYASSL_MSG("\tfail: extension data length"); + return ASN_PARSE_E; + } + + if (oid == OCSP_NONCE_OID) { + resp->nonce = source + index; + resp->nonceSz = length; + } + + index += length; + } + + *ioIndex = index; + return 0; +} + + static int DecodeResponseData(byte* source, word32* ioIndex, OcspResponse* resp, word32 size) { @@ -4118,28 +4185,25 @@ static int DecodeResponseData(byte* source, else return ASN_PARSE_E; - /* Skip GeneralizedTime */ + /* save pointer to the producedAt time */ if (source[index++] != ASN_GENERALIZED_TIME) return ASN_PARSE_E; if (GetLength(source, &index, &length, size) < 0) return ASN_PARSE_E; + resp->producedAt = source + index; 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; - } + if (DecodeOcspRespExtensions(source, &index, resp, size) < 0) + return ASN_PARSE_E; *ioIndex = index; return 0; } + static int DecodeCerts(byte* source, word32* ioIndex, OcspResponse* resp, word32 size) { @@ -4276,6 +4340,57 @@ static int SetSerialNumber(const byte* sn, word32 snSz, byte* output) } +static word32 SetOcspReqExtensions(word32 extSz, byte* output, + const byte* nonce, word32 nonceSz) +{ + static const byte NonceObjId[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x02 }; + byte seqArray[5][MAX_SEQ_SZ]; + word32 seqSz[5], totalSz; + + if (nonce == NULL || nonceSz == 0) return 0; + + seqArray[0][0] = ASN_OCTET_STRING; + seqSz[0] = 1 + SetLength(nonceSz, &seqArray[0][1]); + + seqArray[1][0] = ASN_OBJECT_ID; + seqSz[1] = 1 + SetLength(sizeof(NonceObjId), &seqArray[1][1]); + + totalSz = seqSz[0] + seqSz[1] + nonceSz + sizeof(NonceObjId); + + seqSz[2] = SetSequence(totalSz, seqArray[2]); + totalSz += seqSz[2]; + + seqSz[3] = SetSequence(totalSz, seqArray[3]); + totalSz += seqSz[3]; + + seqArray[4][0] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2); + seqSz[4] = 1 + SetLength(totalSz, &seqArray[4][1]); + totalSz += seqSz[4]; + + if (totalSz < extSz) + { + totalSz = 0; + XMEMCPY(output + totalSz, seqArray[4], seqSz[4]); + totalSz += seqSz[4]; + XMEMCPY(output + totalSz, seqArray[3], seqSz[3]); + totalSz += seqSz[3]; + XMEMCPY(output + totalSz, seqArray[2], seqSz[2]); + totalSz += seqSz[2]; + XMEMCPY(output + totalSz, seqArray[1], seqSz[1]); + totalSz += seqSz[1]; + XMEMCPY(output + totalSz, NonceObjId, sizeof(NonceObjId)); + totalSz += sizeof(NonceObjId); + XMEMCPY(output + totalSz, seqArray[0], seqSz[0]); + totalSz += seqSz[0]; + XMEMCPY(output + totalSz, nonce, nonceSz); + totalSz += nonceSz; + } + + return totalSz; +} + + int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz) { byte seqArray[5][MAX_SEQ_SZ]; @@ -4284,20 +4399,36 @@ int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz) byte issuerArray[MAX_ENCODED_DIG_SZ]; byte issuerKeyArray[MAX_ENCODED_DIG_SZ]; byte snArray[MAX_SN_SZ]; - - word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, totalSz; + byte extArray[MAX_OCSP_EXT_SZ]; + byte nonceArray[MAX_OCSP_NONCE_SZ]; + RNG rng; + word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, nonceSz, + extSz, totalSz; int i; + 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); + 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); + extSz = SetOcspReqExtensions(MAX_OCSP_EXT_SZ, extArray, + nonceArray, nonceSz); + } + totalSz = algoSz + issuerSz + issuerKeySz + snSz; for (i = 4; i >= 0; i--) { seqSz[i] = SetSequence(totalSz, seqArray[i]); totalSz += seqSz[i]; + if (i == 2) totalSz += extSz; } totalSz = 0; for (i = 0; i < 5; i++) { @@ -4312,8 +4443,38 @@ int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz) totalSz += issuerKeySz; XMEMCPY(output + totalSz, snArray, snSz); totalSz += snSz; + if (extSz != 0) { + XMEMCPY(output + totalSz, extArray, extSz); + totalSz += extSz; + } return totalSz; } + +void InitOcspRequest(OcspRequest* req, byte* dest, word32 destSz, void* heap) +{ + XMEMSET(req, 0, sizeof(*req)); + req->dest = dest; + req->destSz = destSz; + req->heap = heap; +} + + +int CompareOcspReqResp(OcspRequest* req, OcspResponse* resp) +{ + int cmp; + + if (req == NULL) return -1; + if (resp == NULL) return 1; + + cmp = req->nonceSz - resp->nonceSz; + if (cmp != 0) return cmp; + + cmp = XMEMCMP(req->nonce, resp->nonce, req->nonceSz); + if (cmp != 0) return cmp; + + return 0; +} + #endif diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index 5dbdc03d2..eb1a6752e 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -136,6 +136,8 @@ enum Misc_ASN { #endif /* Max total extensions, id + len + others */ #endif + MAX_OCSP_EXT_SZ = 58, /* Max OCSP Extension length */ + MAX_OCSP_NONCE_SZ = 18, /* OCSP Nonce size */ MAX_PUBLIC_KEY_SZ = MAX_NTRU_ENC_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2 /* use bigger NTRU size */ }; @@ -335,13 +337,15 @@ enum Ocsp_Cert_Status { enum Ocsp_Sums { - OCSP_BASIC_OID = 117 + OCSP_BASIC_OID = 117, + OCSP_NONCE_OID = 118 }; #define STATUS_LIST_SIZE 5 +typedef struct OcspRequest OcspRequest; typedef struct OcspResponse OcspResponse; @@ -353,6 +357,10 @@ 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 */ + 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 */ @@ -366,17 +374,35 @@ struct OcspResponse { word32 certStatus[STATUS_LIST_SIZE]; /* Certificate status array */ + byte* nonce; + int nonceSz; + 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; + int nonceSz; + + byte* dest; + word32 destSz; + void* heap; +}; + + CYASSL_LOCAL void InitOcspResponse(OcspResponse*, byte*, word32, void*); CYASSL_LOCAL void FreeOcspResponse(OcspResponse*); 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 int CompareOcspReqResp(OcspRequest*, OcspResponse*); + #endif /* HAVE_OCSP */