diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index af42451d3..a7d0bc45a 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; @@ -6064,39 +6065,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 */ @@ -6131,6 +6102,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/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; } 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/ctaocrypt/src/pkcs7.c b/ctaocrypt/src/pkcs7.c index 960389309..bc6f80e12 100644 --- a/ctaocrypt/src/pkcs7.c +++ b/ctaocrypt/src/pkcs7.c @@ -114,6 +114,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) { @@ -556,6 +583,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); @@ -642,6 +671,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; @@ -662,7 +698,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); @@ -680,8 +716,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); @@ -696,7 +737,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 { @@ -711,16 +752,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); } @@ -784,6 +826,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); @@ -791,6 +837,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/ctaocrypt/test/test.c b/ctaocrypt/test/test.c index 16588da4b..2ac13908f 100644 --- a/ctaocrypt/test/test.c +++ b/ctaocrypt/test/test.c @@ -4027,106 +4027,193 @@ int compress_test(void) int pkcs7_test(void) { int ret = 0; - byte* cert; - byte out[2048]; - char data[] = "Hello World"; - word32 dataSz, outSz; - PKCS7 msg; - RNG rng; - word32 certSz; - FILE* file; - FILE* pkcs7File; - - byte transIdOid[] = - { 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, - 0x09, 0x07 }; - byte messageTypeOid[] = - { 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, - 0x09, 0x02 }; - byte senderNonceOid[] = - { 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, - 0x09, 0x05 }; - byte pkiStatusOid[] = - { 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, - 0x09, 0x03 }; - byte transId[(SHA_DIGEST_SIZE + 1) * 2 + 1]; - byte messageType[] = { 0x13, 2, '1', '9' }; - byte senderNonce[34]; - byte pkiStatus[] = { 0x13, 1, '0' }; - - PKCS7Attrib attribs[] = + /* Test the PKCS7 Signed-Data */ { - { transIdOid, sizeof(transIdOid), - transId, sizeof(transId) - 1 }, /* take off the null */ - { messageTypeOid, sizeof(messageTypeOid), - messageType, sizeof(messageType) }, - { senderNonceOid, sizeof(senderNonceOid), - senderNonce, sizeof(senderNonce) }, - { pkiStatusOid, sizeof(pkiStatusOid), - pkiStatus, sizeof(pkiStatus) } - }; + byte* cert; + byte out[2048]; + char data[] = "Hello World"; + word32 dataSz, outSz; + PKCS7 msg; + RNG rng; - dataSz = (word32) strlen(data); - outSz = sizeof(out); + word32 certSz; + FILE* file; + FILE* pkcs7File; - cert = (byte*)malloc(FOURK_BUF); - if (cert == NULL) - return -40; + byte transIdOid[] = + { 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, + 0x09, 0x07 }; + byte messageTypeOid[] = + { 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, + 0x09, 0x02 }; + byte senderNonceOid[] = + { 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, + 0x09, 0x05 }; + byte pkiStatusOid[] = + { 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, + 0x09, 0x03 }; + byte transId[(SHA_DIGEST_SIZE + 1) * 2 + 1]; + byte messageType[] = { 0x13, 2, '1', '9' }; + byte senderNonce[34]; + byte pkiStatus[] = { 0x13, 1, '0' }; - /* read in DER cert of recipient, into cert of size certSz */ - file = fopen(clientCert, "rb"); + PKCS7Attrib attribs[] = + { + { transIdOid, sizeof(transIdOid), + transId, sizeof(transId) - 1 }, /* take off the null */ + { messageTypeOid, sizeof(messageTypeOid), + messageType, sizeof(messageType) }, + { senderNonceOid, sizeof(senderNonceOid), + senderNonce, sizeof(senderNonce) }, + { pkiStatusOid, sizeof(pkiStatusOid), + pkiStatus, sizeof(pkiStatus) } + }; - if (!file) - err_sys("can't open ./certs/client-cert.der, " - "Please run from CyaSSL home dir", -40); + dataSz = (word32) strlen(data); + outSz = sizeof(out); - certSz = (word32)fread(cert, 1, FOURK_BUF, file); - fclose(file); + cert = (byte*)malloc(FOURK_BUF); + if (cert == NULL) + return -40; - ret = InitRng(&rng); - senderNonce[0] = 0x04; - senderNonce[1] = 0x20; - RNG_GenerateBlock(&rng, &senderNonce[2], 32); + /* read in DER cert of recipient, into cert of size certSz */ + file = fopen(clientCert, "rb"); - PKCS7_InitWithCert(&msg, cert, certSz); - msg.content = (byte*)data; - msg.contentSz = dataSz; - msg.hashOID = SHAh; - msg.encryptOID = RSAk; - msg.signedAttribs = attribs; - msg.signedAttribsSz = sizeof(attribs)/sizeof(PKCS7Attrib); - msg.rng = &rng; - { - Sha sha; - byte digest[SHA_DIGEST_SIZE]; - int i,j; + if (!file) + err_sys("can't open ./certs/client-cert.der, " + "Please run from CyaSSL home dir", -40); - transId[0] = 0x13; - transId[1] = SHA_DIGEST_SIZE * 2; + certSz = (word32)fread(cert, 1, FOURK_BUF, file); + fclose(file); - InitSha(&sha); - ShaUpdate(&sha, msg.publicKey, msg.publicKeySz); - ShaFinal(&sha, digest); + ret = InitRng(&rng); + senderNonce[0] = 0x04; + senderNonce[1] = 0x20; + RNG_GenerateBlock(&rng, &senderNonce[2], 32); - for (i = 0, j = 2; i < SHA_DIGEST_SIZE; i++, j += 2) { - snprintf((char*)&transId[j], 3, "%02x", digest[i]); + PKCS7_InitWithCert(&msg, cert, certSz); + msg.content = (byte*)data; + msg.contentSz = dataSz; + msg.hashOID = SHAh; + msg.encryptOID = RSAk; + msg.signedAttribs = attribs; + msg.signedAttribsSz = sizeof(attribs)/sizeof(PKCS7Attrib); + msg.rng = &rng; + { + Sha sha; + byte digest[SHA_DIGEST_SIZE]; + int i,j; + + transId[0] = 0x13; + transId[1] = SHA_DIGEST_SIZE * 2; + + InitSha(&sha); + ShaUpdate(&sha, msg.publicKey, msg.publicKeySz); + ShaFinal(&sha, digest); + + for (i = 0, j = 2; i < SHA_DIGEST_SIZE; i++, j += 2) { + snprintf((char*)&transId[j], 3, "%02x", digest[i]); + } } - } - ret = PKCS7_EncodeSignedData(&msg, out, outSz); - if (ret < 0) { - printf("Pkcs7_encrypt failed\n"); - return -42; - } - else - outSz = ret; + ret = PKCS7_EncodeSignedData(&msg, out, outSz); + if (ret < 0) { + printf("Pkcs7_encrypt failed\n"); + return -42; + } + else + outSz = ret; - /* write PKCS#7 to output file for more testing */ - pkcs7File = fopen("./pkcs7test.der", "wb"); - if (!pkcs7File) - return -43; - ret = (int)fwrite(out, outSz, 1, pkcs7File); - fclose(pkcs7File); + /* write PKCS#7 to output file for more testing */ + pkcs7File = fopen("./pkcs7test.der", "wb"); + if (!pkcs7File) + return -43; + ret = (int)fwrite(out, outSz, 1, pkcs7File); + fclose(pkcs7File); + } + /* Test the PKCS7 Enveloped-Data */ + { + int cipher = DES3b; + int 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; diff --git a/cyassl/ctaocrypt/asn.h b/cyassl/ctaocrypt/asn.h index 1373c46e4..e5c153295 100644 --- a/cyassl/ctaocrypt/asn.h +++ b/cyassl/ctaocrypt/asn.h @@ -446,6 +446,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); @@ -454,6 +464,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 */ 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 */ }; diff --git a/cyassl/ctaocrypt/pkcs7.h b/cyassl/ctaocrypt/pkcs7.h index 4cd984b12..73fc96b4e 100644 --- a/cyassl/ctaocrypt/pkcs7.h +++ b/cyassl/ctaocrypt/pkcs7.h @@ -63,19 +63,21 @@ 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 */ RNG* rng; 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 */ byte issuerSn[MAX_SN_SZ]; word32 issuerSnSz; byte publicKey[512]; @@ -87,6 +89,8 @@ typedef struct 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, @@ -99,6 +103,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" */ 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)); 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 */