From 3152c286504ac1be49c7ab82bf4c1336156d333e Mon Sep 17 00:00:00 2001 From: toddouska Date: Tue, 14 Jan 2014 09:36:21 -0800 Subject: [PATCH 1/7] add escape for 64encdoe + and = too --- ctaocrypt/src/coding.c | 137 +++++++++++++++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 27 deletions(-) diff --git a/ctaocrypt/src/coding.c b/ctaocrypt/src/coding.c index 26a884a9b..ed7a54c5e 100644 --- a/ctaocrypt/src/coding.c +++ b/ctaocrypt/src/coding.c @@ -147,10 +147,87 @@ const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', }; +/* make sure *i (idx) won't exceed max, store and possibly escape to out, + * raw means use e w/o decode, 0 on success */ +static int Escape(int escaped, byte e, byte* out, word32* i, word32 max, + int raw) +{ + int doEscape = 0; + word32 needed = 1; + word32 idx = *i; + + byte basic; + byte plus = 0; + byte equals = 0; + byte newline = 0; + + if (raw) + basic = e; + else + basic = base64Encode[e]; + + /* check whether to escape */ + if (escaped) { + switch ((char)basic) { + case '+' : + plus = 1; + doEscape = 1; + needed += 2; + break; + case '=' : + equals = 1; + doEscape = 1; + needed += 2; + break; + case '\n' : + newline = 1; + doEscape = 1; + needed += 2; + break; + default: + /* do nothing */ + break; + } + } + + /* check size */ + if ( (idx+needed) > max) { + CYASSL_MSG("Escape buffer max too small"); + return BUFFER_E; + } + + /* store it */ + if (doEscape == 0) { + out[idx++] = basic; + } + else { + out[idx++] = '%'; /* start escape */ + + if (plus) { + out[idx++] = '2'; + out[idx++] = 'B'; + } + else if (equals) { + out[idx++] = '3'; + out[idx++] = 'D'; + } + else if (newline) { + out[idx++] = '0'; + out[idx++] = 'A'; + } + + } + *i = idx; + + return 0; +} + + /* internal worker, handles both escaped and normal line endings */ static int DoBase64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen, int escaped) { + int ret = 0; word32 i = 0, j = 0, n = 0; /* new line counter */ @@ -163,6 +240,8 @@ static int DoBase64_Encode(const byte* in, word32 inLen, byte* out, outSz += addSz; + /* if escaped we can't predetermine size for one pass encoding, but + * make sure we have enough if no escapes are in input */ if (outSz > *outLen) return BAD_FUNC_ARG; while (inLen > 2) { @@ -177,26 +256,25 @@ static int DoBase64_Encode(const byte* in, word32 inLen, byte* out, byte e4 = b3 & 0x3F; /* store */ - out[i++] = base64Encode[e1]; - out[i++] = base64Encode[e2]; - out[i++] = base64Encode[e3]; - out[i++] = base64Encode[e4]; + ret = Escape(escaped, e1, out, &i, *outLen, 0); + if (ret != 0) break; + ret = Escape(escaped, e2, out, &i, *outLen, 0); + if (ret != 0) break; + ret = Escape(escaped, e3, out, &i, *outLen, 0); + if (ret != 0) break; + ret = Escape(escaped, e4, out, &i, *outLen, 0); + if (ret != 0) break; inLen -= 3; if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen) { - if (escaped) { - out[i++] = '%'; - out[i++] = '0'; - out[i++] = 'A'; - } - else - out[i++] = '\n'; + ret = Escape(escaped, '\n', out, &i, *outLen, 1); + if (ret != 0) break; } } /* last integral */ - if (inLen) { + if (inLen && ret == 0) { int twoBytes = (inLen == 2); byte b1 = in[j++]; @@ -206,24 +284,29 @@ static int DoBase64_Encode(const byte* in, word32 inLen, byte* out, byte e2 = ((b1 & 0x3) << 4) | (b2 >> 4); byte e3 = (b2 & 0xF) << 2; - out[i++] = base64Encode[e1]; - out[i++] = base64Encode[e2]; - out[i++] = (twoBytes) ? base64Encode[e3] : PAD; - out[i++] = PAD; + ret = Escape(escaped, e1, out, &i, *outLen, 0); + if (ret == 0) + ret = Escape(escaped, e2, out, &i, *outLen, 0); + if (ret == 0) { + /* third */ + if (twoBytes) + ret = Escape(escaped, e3, out, &i, *outLen, 0); + else + ret = Escape(escaped, '=', out, &i, *outLen, 1); + } + /* fourth always pad */ + if (ret == 0) + ret = Escape(escaped, '=', out, &i, *outLen, 1); } - if (escaped) { - out[i++] = '%'; - out[i++] = '0'; - out[i++] = 'A'; - } - else - out[i++] = '\n'; - if (i != outSz) - return ASN_INPUT_E; - *outLen = outSz; + if (ret == 0) + ret = Escape(escaped, '\n', out, &i, *outLen, 1); - return 0; + if (i != outSz && escaped == 0 && ret == 0) + return ASN_INPUT_E; + + *outLen = i; + return ret; } From 8a1971d52b43cee2bb2cf584e6ee0934820348ac Mon Sep 17 00:00:00 2001 From: toddouska Date: Tue, 14 Jan 2014 15:13:43 -0800 Subject: [PATCH 2/7] add CyaSSL_CertPemToDer for certs, ca certs, and cert reqs --- cyassl/ssl.h | 2 ++ src/ssl.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 19db2aba1..2b5f44273 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -973,6 +973,8 @@ CYASSL_API int CyaSSL_GetObjectSize(void); /* object size based on build */ CYASSL_API int CyaSSL_SetVersion(CYASSL* ssl, int version); CYASSL_API int CyaSSL_KeyPemToDer(const unsigned char*, int sz, unsigned char*, int, const char*); +CYASSL_API int CyaSSL_CertPemToDer(const unsigned char*, int sz, unsigned char*, + int, int); typedef void (*CallbackCACache)(unsigned char* der, int sz, int type); typedef void (*CbMissingCRL)(const char* url); diff --git a/src/ssl.c b/src/ssl.c index 37c9313a6..3b5230619 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1059,6 +1059,54 @@ int CyaSSL_CertManagerUnloadCAs(CYASSL_CERT_MANAGER* cm) } +/* Return bytes written to buff or < 0 for error */ +int CyaSSL_CertPemToDer(const unsigned char* pem, int pemSz, + unsigned char* buff, int buffSz, + int type) +{ + EncryptedInfo info; + int eccKey = 0; + int ret; + buffer der; + + CYASSL_ENTER("CyaSSL_CertPemToDer"); + + if (pem == NULL || buff == NULL || buffSz <= 0) { + CYASSL_MSG("Bad pem der args"); + return BAD_FUNC_ARG; + } + + if (type != CERT_TYPE && type != CA_TYPE && type != CERTREQ_TYPE) { + CYASSL_MSG("Bad cert type"); + return BAD_FUNC_ARG; + } + + info.set = 0; + info.ctx = NULL; + info.consumed = 0; + der.buffer = NULL; + + ret = PemToDer(pem, pemSz, type, &der, NULL, &info, &eccKey); + if (ret < 0) { + CYASSL_MSG("Bad Pem To Der"); + } + else { + if (der.length <= (word32)buffSz) { + XMEMCPY(buff, der.buffer, der.length); + ret = der.length; + } + else { + CYASSL_MSG("Bad der length"); + ret = BAD_FUNC_ARG; + } + } + + XFREE(der.buffer, NULL, DYNAMIC_TYPE_KEY); + + return ret; +} + + /* our KeyPemToDer password callback, password in userData */ static INLINE int OurPasswordCb(char* passwd, int sz, int rw, void* userdata) { @@ -1582,6 +1630,12 @@ int CyaSSL_Init(void) XSTRNCPY(footer, "-----END CERTIFICATE-----", sizeof(footer)); dynamicType = (type == CA_TYPE) ? DYNAMIC_TYPE_CA : DYNAMIC_TYPE_CERT; + } else if (type == CERTREQ_TYPE) { + XSTRNCPY(header, "-----BEGIN CERTIFICATE REQUEST-----", + sizeof(header)); + XSTRNCPY(footer, "-----END CERTIFICATE REQUEST-----", + sizeof(footer)); + dynamicType = DYNAMIC_TYPE_KEY; } else if (type == DH_PARAM_TYPE) { XSTRNCPY(header, "-----BEGIN DH PARAMETERS-----", sizeof(header)); XSTRNCPY(footer, "-----END DH PARAMETERS-----", sizeof(footer)); From 80c19aaf334de0b8fbec5b6b677ef36a5064d501 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Tue, 14 Jan 2014 22:46:54 -0700 Subject: [PATCH 3/7] add PKCS7 error codes --- ctaocrypt/src/error.c | 8 ++++++++ cyassl/ctaocrypt/error.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/ctaocrypt/src/error.c b/ctaocrypt/src/error.c index 449a9b583..d7ed45194 100644 --- a/ctaocrypt/src/error.c +++ b/ctaocrypt/src/error.c @@ -335,6 +335,14 @@ void CTaoCryptErrorString(int error, char* buffer) XSTRNCPY(buffer, "Setting cert request attributes error", max); break; + case PKCS7_OID_E: + XSTRNCPY(buffer, "PKCS#7 error: mismatched OID value", max); + break; + + case PKCS7_RECIP_E: + XSTRNCPY(buffer, "PKCS#7 error: no matching recipient found", max); + break; + default: XSTRNCPY(buffer, "unknown error number", max); diff --git a/cyassl/ctaocrypt/error.h b/cyassl/ctaocrypt/error.h index d99ac3d72..af4d8e9c8 100644 --- a/cyassl/ctaocrypt/error.h +++ b/cyassl/ctaocrypt/error.h @@ -119,6 +119,9 @@ enum { REQ_ATTRIBUTE_E = -194, /* setting cert request attributes error */ + PKCS7_OID_E = -195, /* PKCS#7, mismatched OID error */ + PKCS7_RECIP_E = -196, /* PKCS#7, recipient error */ + MIN_CODE_E = -200 /* errors -101 - -199 */ }; From d63c58864f8af5b1945c6db42bd43dcf002257f3 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Tue, 14 Jan 2014 22:48:55 -0700 Subject: [PATCH 4/7] expose more ASN.1 helper functions with CYASSL_LOCAL --- ctaocrypt/src/asn.c | 78 ++++++++++++++++++++++-------------------- cyassl/ctaocrypt/asn.h | 12 +++++++ 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index 1874e36c8..9c773be00 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -439,8 +439,8 @@ CYASSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, } -static int GetSequence(const byte* input, word32* inOutIdx, int* len, - word32 maxIdx) +CYASSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx) { int length = -1; word32 idx = *inOutIdx; @@ -456,7 +456,8 @@ static int GetSequence(const byte* input, word32* inOutIdx, int* len, } -static int GetSet(const byte* input, word32* inOutIdx, int* len, word32 maxIdx) +CYASSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx) { int length = -1; word32 idx = *inOutIdx; @@ -473,7 +474,7 @@ static int GetSet(const byte* input, word32* inOutIdx, int* len, word32 maxIdx) /* winodws header clash for WinCE using GetVersion */ -static int GetMyVersion(const byte* input, word32* inOutIdx, int* version) +CYASSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx, int* version) { word32 idx = *inOutIdx; @@ -537,7 +538,7 @@ static int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version) } -static int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx, +CYASSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx, word32 maxIdx) { word32 i = *inOutIdx; @@ -593,7 +594,7 @@ static int GetObjectId(const byte* input, word32* inOutIdx, word32* oid, } -static int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, +CYASSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, word32 maxIdx) { int length; @@ -6058,39 +6059,9 @@ int CompareOcspReqResp(OcspRequest* req, OcspResponse* resp) #endif -#ifdef HAVE_CRL - -/* initialize decoded CRL */ -void InitDecodedCRL(DecodedCRL* dcrl) -{ - CYASSL_MSG("InitDecodedCRL"); - - dcrl->certBegin = 0; - dcrl->sigIndex = 0; - dcrl->sigLength = 0; - dcrl->signatureOID = 0; - dcrl->certs = NULL; - dcrl->totalCerts = 0; -} - - -/* free decoded CRL resources */ -void FreeDecodedCRL(DecodedCRL* dcrl) -{ - RevokedCert* tmp = dcrl->certs; - - CYASSL_MSG("FreeDecodedCRL"); - - while(tmp) { - RevokedCert* next = tmp->next; - XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED); - tmp = next; - } -} - - /* store SHA1 hash of NAME */ -static int GetNameHash(const byte* source, word32* idx, byte* hash, int maxIdx) +CYASSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash, + int maxIdx) { Sha sha; int length; /* length of all distinguished names */ @@ -6125,6 +6096,37 @@ static int GetNameHash(const byte* source, word32* idx, byte* hash, int maxIdx) } +#ifdef HAVE_CRL + +/* initialize decoded CRL */ +void InitDecodedCRL(DecodedCRL* dcrl) +{ + CYASSL_MSG("InitDecodedCRL"); + + dcrl->certBegin = 0; + dcrl->sigIndex = 0; + dcrl->sigLength = 0; + dcrl->signatureOID = 0; + dcrl->certs = NULL; + dcrl->totalCerts = 0; +} + + +/* free decoded CRL resources */ +void FreeDecodedCRL(DecodedCRL* dcrl) +{ + RevokedCert* tmp = dcrl->certs; + + CYASSL_MSG("FreeDecodedCRL"); + + while(tmp) { + RevokedCert* next = tmp->next; + XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED); + tmp = next; + } +} + + /* Get Revoked Cert list, 0 on success */ static int GetRevoked(const byte* buff, word32* idx, DecodedCRL* dcrl, int maxIdx) diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index 121af0aef..72d2bfda6 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -445,6 +445,16 @@ CYASSL_LOCAL int ValidateDate(const byte* date, byte format, int dateType); /* ASN.1 helper functions */ CYASSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, word32 maxIdx); +CYASSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx); +CYASSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx); +CYASSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx, + int* version); +CYASSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx, + word32 maxIdx); +CYASSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, + word32 maxIdx); CYASSL_LOCAL word32 SetLength(word32 length, byte* output); CYASSL_LOCAL word32 SetSequence(word32 len, byte* output); CYASSL_LOCAL word32 SetOctetString(word32 len, byte* output); @@ -452,6 +462,8 @@ CYASSL_LOCAL word32 SetSet(word32 len, byte* output); CYASSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz); CYASSL_LOCAL int SetMyVersion(word32 version, byte* output, int header); CYASSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output); +CYASSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash, + int maxIdx); #ifdef HAVE_ECC /* ASN sig helpers */ From 9f7e33e7e118f9244fa1155b54b803fc714113cc Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Tue, 14 Jan 2014 22:57:55 -0700 Subject: [PATCH 5/7] add PKCS7_DecodeEnvelopedData() --- ctaocrypt/src/pkcs7.c | 267 ++++++++++++++++++++++++++++++++++++++- cyassl/ctaocrypt/pkcs7.h | 23 ++-- 2 files changed, 278 insertions(+), 12 deletions(-) diff --git a/ctaocrypt/src/pkcs7.c b/ctaocrypt/src/pkcs7.c index c23e2b39a..801fa48ad 100644 --- a/ctaocrypt/src/pkcs7.c +++ b/ctaocrypt/src/pkcs7.c @@ -106,6 +106,33 @@ CYASSL_LOCAL int SetContentType(int pkcs7TypeOID, byte* output) } +int GetContentType(const byte* input, word32* inOutIdx, word32* oid, + word32 maxIdx) +{ + int length; + word32 i = *inOutIdx; + byte b; + *oid = 0; + + CYASSL_ENTER("GetContentType"); + + 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]; + i++; + } + + *inOutIdx = i; + + return 0; +} + int PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) { @@ -214,6 +241,8 @@ CYASSL_LOCAL int CreateRecipientInfo(const byte* cert, word32 certSz, return ALGO_ID_E; keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, keyType, 0); + if (keyEncAlgSz == 0) + return BAD_FUNC_ARG; /* EncryptedKey */ InitRsaKey(&pubKey, 0); @@ -300,6 +329,13 @@ int PKCS7_EncodeEnvelopeData(PKCS7* pkcs7, byte* output, word32 outputSz) byte contentEncAlgo[MAX_ALGO_SZ]; byte encContentOctet[MAX_OCTET_STR_SZ]; + if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || + pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL) + return BAD_FUNC_ARG; + + if (output == NULL || outputSz == 0) + return BAD_FUNC_ARG; + switch (pkcs7->encryptOID) { case DESb: blockKeySz = DES_KEYLEN; @@ -320,7 +356,7 @@ int PKCS7_EncodeEnvelopeData(PKCS7* pkcs7, byte* output, word32 outputSz) /* version */ verSz = SetMyVersion(0, ver, 0); - /* generate random content enc key */ + /* generate random content encryption key */ InitRng(&rng); RNG_GenerateBlock(&rng, contentKeyPlain, blockKeySz); @@ -338,8 +374,13 @@ int PKCS7_EncodeEnvelopeData(PKCS7* pkcs7, byte* output, word32 outputSz) /* EncryptedContentInfo */ contentTypeSz = SetContentType(pkcs7->contentOID, contentType); + if (contentTypeSz == 0) + return BAD_FUNC_ARG; + contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, blkType, 0); + if (contentEncAlgoSz == 0) + return BAD_FUNC_ARG; /* allocate memory for encrypted content, pad if necessary */ padSz = DES_BLOCK_SIZE - (pkcs7->contentSz % DES_BLOCK_SIZE); @@ -354,7 +395,7 @@ int PKCS7_EncodeEnvelopeData(PKCS7* pkcs7, byte* output, word32 outputSz) dynamicFlag = 1; for (i = 0; i < padSz; i++) { - plain[pkcs7->contentSz + i + 1] = padSz; + plain[pkcs7->contentSz + i] = padSz; } } else { @@ -369,16 +410,17 @@ int PKCS7_EncodeEnvelopeData(PKCS7* pkcs7, byte* output, word32 outputSz) return MEMORY_E; } + /* use NULL iv for now */ byte tmpIv[blockKeySz]; + XMEMSET(tmpIv, 0, sizeof(tmpIv)); + if (pkcs7->encryptOID == DESb) { Des des; - RNG_GenerateBlock(&rng, tmpIv, (word32)sizeof(tmpIv)); Des_SetKey(&des, contentKeyPlain, tmpIv, DES_ENCRYPTION); Des_CbcEncrypt(&des, encryptedContent, plain, desOutSz); } else if (pkcs7->encryptOID == DES3b) { Des3 des3; - RNG_GenerateBlock(&rng, tmpIv, (word32)sizeof(tmpIv)); Des3_SetKey(&des3, contentKeyPlain, tmpIv, DES_ENCRYPTION); Des3_CbcEncrypt(&des3, encryptedContent, plain, desOutSz); } @@ -442,6 +484,10 @@ int PKCS7_EncodeEnvelopeData(PKCS7* pkcs7, byte* output, word32 outputSz) #ifdef NO_RC4 FreeRng(&rng); #endif + + XMEMSET(contentKeyPlain, 0, MAX_CONTENT_KEY_LEN); + XMEMSET(contentKeyEnc, 0, MAX_ENCRYPTED_KEY_SZ); + if (dynamicFlag) XFREE(plain, NULL, DYNAMMIC_TYPE_TMP_BUFFER); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -449,6 +495,219 @@ int PKCS7_EncodeEnvelopeData(PKCS7* pkcs7, byte* output, word32 outputSz) return idx; } +CYASSL_API int PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, byte* output, + word32 outputSz) +{ + int recipFound = 0; + int ret, version, length; + word32 savedIdx = 0, idx = 0; + word32 contentType, encOID; + byte issuerHash[SHA_DIGEST_SIZE]; + mp_int serialNum; + + DecodedCert decoded; + + int encryptedKeySz, keySz; + byte tmpIv[DES3_KEYLEN]; + byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; + byte* decryptedKey = NULL; + + RsaKey privKey; + int encryptedContentSz; + byte padLen; + byte* encryptedContent = NULL; + + if (pkcs7 == NULL || pkcs7->singleCert == NULL || + pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL || + pkcs7->privKeySize == 0) + return BAD_FUNC_ARG; + + if (pkiMsg == NULL || pkiMsgSz == 0 || + output == NULL || outputSz == 0) + return BAD_FUNC_ARG; + + /* parse recipient cert */ + InitDecodedCert(&decoded, pkcs7->singleCert, pkcs7->singleCertSz, 0); + ret = ParseCert(&decoded, CA_TYPE, NO_VERIFY, 0); + if (ret < 0) { + FreeDecodedCert(&decoded); + return ret; + } + + /* load private key */ + InitRsaKey(&privKey, 0); + ret = RsaPrivateKeyDecode(pkcs7->privateKey, &idx, &privKey, + pkcs7->privKeySize); + if (ret != 0) { + CYASSL_MSG("Failed to decode RSA private key"); + return ret; + } + + idx = 0; + + /* read past ContentInfo, verify type */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (contentType != ENVELOPED_DATA) { + CYASSL_MSG("PKCS#7 input not of type EnvelopedData"); + return PKCS7_OID_E; + } + + if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove EnvelopedData */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(pkiMsg, &idx, &version) < 0) + return ASN_PARSE_E; + + if (version != 0) { + CYASSL_MSG("PKCS#7 envelopedData needs to be of version 0"); + return ASN_VERSION_E; + } + + /* walk through RecipientInfo set, find correct recipient */ + if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + savedIdx = idx; + recipFound = 0; + + /* when looking for next recipient, use first sequence and version to + * indicate there is another, if not, move on */ + while(recipFound == 0) { + + /* remove RecipientInfo */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { + if (recipFound == 0) { + return ASN_PARSE_E; + } else { + idx = savedIdx; + break; + } + } + + if (GetMyVersion(pkiMsg, &idx, &version) < 0) { + if (recipFound == 0) { + return ASN_PARSE_E; + } else { + idx = savedIdx; + break; + } + } + + if (version != 0) + return ASN_VERSION_E; + + /* remove IssuerAndSerialNumber */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (XMEMCMP(issuerHash, decoded.issuerHash, SHA_DIGEST_SIZE) == 0) { + recipFound = 1; + } + + if (GetInt(&serialNum, pkiMsg, &idx, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (encOID != RSAk) + return ALGO_ID_E; + + /* read encryptedKey */ + if (pkiMsg[idx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (recipFound == 1) + XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz); + idx += encryptedKeySz; + + /* update good idx */ + savedIdx = idx; + } + + if (recipFound == 0) { + CYASSL_MSG("No recipient found in envelopedData that matches input"); + return PKCS7_RECIP_E; + } + + /* remove EncryptedContentInfo */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* read encryptedContent */ + if (pkiMsg[idx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) + return ASN_PARSE_E; + + encryptedContent = XMALLOC(encryptedContentSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); + + /* decrypt encryptedKey */ + keySz = RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, + &decryptedKey, &privKey); + if (keySz < 0) + return keySz; + + /* decrypt encryptedContent, using NULL iv for now */ + XMEMSET(tmpIv, 0, sizeof(tmpIv)); + + if (encOID == DESb) { + Des des; + Des_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); + Des_CbcDecrypt(&des, encryptedContent, encryptedContent, + encryptedContentSz); + } else if (encOID == DES3b) { + Des3 des; + Des3_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); + Des3_CbcDecrypt(&des, encryptedContent, encryptedContent, + encryptedContentSz); + } else { + CYASSL_MSG("Unsupported content encryption OID type"); + return ALGO_ID_E; + } + + padLen = encryptedContent[encryptedContentSz-1]; + + /* copy plaintext to output */ + XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); + + /* free memory, zero out keys */ + XMEMSET(encryptedKey, 0, MAX_ENCRYPTED_KEY_SZ); + XMEMSET(encryptedContent, 0, encryptedContentSz); + XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return encryptedContentSz - padLen; +} + #else /* HAVE_PKCS7 */ diff --git a/cyassl/ctaocrypt/pkcs7.h b/cyassl/ctaocrypt/pkcs7.h index 496c7321f..ef96c8172 100644 --- a/cyassl/ctaocrypt/pkcs7.h +++ b/cyassl/ctaocrypt/pkcs7.h @@ -63,24 +63,28 @@ typedef struct PKCS7Attrib { typedef struct PKCS7 { - byte* content; - word32 contentSz; - int contentOID; + byte* content; /* inner content, not owner */ + word32 contentSz; /* content size */ + int contentOID; /* PKCS#7 content type OID sum */ int hashOID; - int encryptOID; + int encryptOID; /* key encryption algorithm OID */ - byte* singleCert; - word32 singleCertSz; - byte* issuer; + byte* singleCert; /* recipient cert, DER, not owner */ + word32 singleCertSz; /* size of recipient cert buffer, bytes */ + byte* issuer; word32 issuerSz; + byte* privateKey; /* recipient private key, DER, not owner */ + word32 privKeySize; /* size of private key buffer, bytes */ PKCS7Attrib** signedAttribs; - word32 signedAttribsSz; /* Number of attribs in list */ + word32 signedAttribsSz; /* Number of attribs in list */ } PKCS7; CYASSL_LOCAL int SetContentType(int pkcs7TypeOID, byte* output); +CYASSL_LOCAL int GetContentType(const byte* input, word32* inOutIdx, + word32* oid, word32 maxIdx); CYASSL_LOCAL int CreateRecipientInfo(const byte* cert, word32 certSz, int keyEncAlgo, int blockKeySz, RNG* rng, byte* contentKeyPlain, @@ -93,6 +97,9 @@ CYASSL_API int PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz); CYASSL_API int PKCS7_EncodeEnvelopeData(PKCS7* pkcs7, byte* output, word32 outputSz); +CYASSL_API int PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, byte* output, + word32 outputSz); #ifdef __cplusplus } /* extern "C" */ From d58add7e97ca4da72474762b439f1b0456ab067f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mois=C3=A9s=20Guimar=C3=A3es?= Date: Wed, 15 Jan 2014 10:56:49 -0300 Subject: [PATCH 6/7] added protection to test_CyaSSL_client_server fixed min macro --- src/tls.c | 4 ++-- tests/api.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tls.c b/src/tls.c index 5acc8e648..482271ba6 100644 --- a/src/tls.c +++ b/src/tls.c @@ -974,7 +974,7 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, if (sniType != type) { offset += sniLen; - listLen -= MIN(ENUM_LEN + OPAQUE16_LEN + sniLen, listLen); + listLen -= min(ENUM_LEN + OPAQUE16_LEN + sniLen, listLen); continue; } @@ -985,7 +985,7 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, } } - len16 -= MIN(2 * OPAQUE16_LEN + extLen, len16); + len16 -= min(2 * OPAQUE16_LEN + extLen, len16); } return len16 ? BUFFER_ERROR : SSL_SUCCESS; diff --git a/tests/api.c b/tests/api.c index e37d5e686..3dadad7a1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -440,6 +440,8 @@ void test_CyaSSL_UseSNI(void) CyaSSL_free(ssl); CyaSSL_CTX_free(ctx); +#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + /* Testing success case at ctx */ client_callbacks.ctx_ready = server_callbacks.ctx_ready = use_SNI_at_ctx; server_callbacks.on_result = verify_SNI_real_matching; @@ -473,6 +475,8 @@ void test_CyaSSL_UseSNI(void) test_CyaSSL_client_server(&client_callbacks, &server_callbacks); +#endif + test_CyaSSL_SNI_GetFromBuffer(); } #endif /* HAVE_SNI */ From 46a03daf5f81fbb6dbf8bf615335ba9b35ede021 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 15 Jan 2014 11:05:18 -0700 Subject: [PATCH 7/7] initial PKCS#7 crypto test --- ctaocrypt/test/test.c | 106 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/ctaocrypt/test/test.c b/ctaocrypt/test/test.c index 3d0f52ae3..96468b62b 100644 --- a/ctaocrypt/test/test.c +++ b/ctaocrypt/test/test.c @@ -61,6 +61,9 @@ #ifdef HAVE_LIBZ #include #endif +#ifdef HAVE_PKCS7 + #include +#endif #ifdef _MSC_VER /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */ @@ -174,6 +177,9 @@ int pbkdf2_test(void); #ifdef HAVE_LIBZ int compress_test(void); #endif +#ifdef HAVE_PKCS7 + int pkcs7_test(void); +#endif @@ -458,6 +464,13 @@ void ctaocrypt_test(void* args) printf( "COMPRESS test passed!\n"); #endif +#ifdef HAVE_PKCS7 + if ( (ret = pkcs7_test()) != 0) + err_sys("PKCS7 test failed!\n", ret); + else + printf( "PKCS7 test passed!\n"); +#endif + ((func_args*)args)->return_code = ret; } @@ -4009,4 +4022,97 @@ int compress_test(void) #endif /* HAVE_LIBZ */ +#ifdef HAVE_PKCS7 + +int pkcs7_test(void) +{ + int cipher = DES3b; + int ret, envelopedSz, decodedSz; + PKCS7 pkcs7; + byte* cert; + byte* privKey; + byte enveloped[2048]; + byte decoded[2048]; + + size_t certSz; + size_t privKeySz; + FILE* certFile; + FILE* keyFile; + FILE* pkcs7File; + const char* pkcs7OutFile = "pkcs7envelopedData.der"; + + const byte data[] = { /* Hello World */ + 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f, + 0x72,0x6c,0x64 + }; + + /* read client cert and key in DER format */ + cert = (byte*)malloc(FOURK_BUF); + if (cert == NULL) + return -201; + + privKey = (byte*)malloc(FOURK_BUF); + if (privKey == NULL) + return -202; + + certFile = fopen(clientCert, "rb"); + if (!certFile) + err_sys("can't open ./certs/client-cert.der, " + "Please run from CyaSSL home dir", -42); + + certSz = fread(cert, 1, FOURK_BUF, certFile); + fclose(certFile); + + keyFile = fopen(clientKey, "rb"); + if (!keyFile) + err_sys("can't open ./certs/client-key.der, " + "Please run from CyaSSL home dir", -43); + + privKeySz = fread(privKey, 1, FOURK_BUF, keyFile); + fclose(keyFile); + + PKCS7_InitWithCert(&pkcs7, cert, (word32)certSz); + pkcs7.content = (byte*)data; + pkcs7.contentSz = (word32)sizeof(data); + pkcs7.contentOID = DATA; + pkcs7.encryptOID = cipher; + pkcs7.privateKey = privKey; + pkcs7.privKeySize = (word32)privKeySz; + + /* encode envelopedData */ + envelopedSz = PKCS7_EncodeEnvelopeData(&pkcs7, enveloped, + sizeof(enveloped)); + if (envelopedSz <= 0) + return -203; + + /* decode envelopedData */ + decodedSz = PKCS7_DecodeEnvelopedData(&pkcs7, enveloped, envelopedSz, + decoded, sizeof(decoded)); + if (decodedSz <= 0) + return -204; + + /* test decode result */ + if (memcmp(decoded, data, sizeof(data)) != 0) { + return -205; + } + + /* output pkcs7 envelopedData for external testing */ + pkcs7File = fopen(pkcs7OutFile, "wb"); + if (!pkcs7File) + return -206; + + ret = (int)fwrite(enveloped, envelopedSz, 1, pkcs7File); + fclose(pkcs7File); + + free(cert); + free(privKey); + + if (ret > 0) + return 0; + + return ret; +} + +#endif /* HAVE_PKCS7 */ + #endif /* NO_CRYPT_TEST */