mirror of https://github.com/wolfSSL/wolfssl.git
add PKCS7_DecodeEnvelopedData()
parent
d63c58864f
commit
9f7e33e7e1
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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" */
|
||||
|
|
Loading…
Reference in New Issue