STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms);
int CMS_RecipientInfo_type(CMS_RecipientInfo *ri);
+CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
+CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
+ X509 *recip, unsigned int flags);
int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert);
int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
EVP_PKEY **pk, X509 **recip,
#define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO 111
#define CMS_F_CMS_DIGESTEDDATA_DO_FINAL 112
#define CMS_F_CMS_DIGEST_VERIFY 113
+#define CMS_F_CMS_ENCRYPT 154
#define CMS_F_CMS_ENCRYPTEDCONTENT_DECRYPT_BIO 146
#define CMS_F_CMS_ENCRYPTEDCONTENT_ENCRYPT_BIO 144
#define CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO 148
#define CMS_F_CMS_ENCRYPTEDDATA_INIT_BIO 147
#define CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY 141
#define CMS_F_CMS_ENCRYPTED_DATA_DECRYPT 139
+#define CMS_F_CMS_ENVELOPEDDATA_CREATE 153
+#define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO 156
#define CMS_F_CMS_ENVELOPED_DATA_INIT 114
#define CMS_F_CMS_FINAL 115
#define CMS_F_CMS_GET0_CERTIFICATE_CHOICES 116
#define CMS_F_CMS_GET0_SIGNED 121
#define CMS_F_CMS_RECIPIENTINFO_DECRYPT 150
#define CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP 122
+#define CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT 155
#define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS 123
#define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID 124
#define CMS_F_CMS_SET1_SIGNERIDENTIFIER 125
#define CMS_R_CTRL_FAILURE 108
#define CMS_R_ERROR_GETTING_PUBLIC_KEY 109
#define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 110
+#define CMS_R_ERROR_SETTING_RECIPIENTINFO 150
#define CMS_R_INVALID_KEY_LENGTH 140
#define CMS_R_MD_BIO_INIT_ERROR 111
#define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 112
#define CMS_R_NO_PUBLIC_KEY 121
#define CMS_R_NO_SIGNERS 122
#define CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 123
+#define CMS_R_RECIPIENT_ERROR 149
#define CMS_R_SIGNER_CERTIFICATE_NOT_FOUND 124
#define CMS_R_SIGNFINAL_ERROR 125
#define CMS_R_SMIME_TEXT_ERROR 126
#define CMS_R_UNKNOWN_ID 133
#define CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM 134
#define CMS_R_UNSUPPORTED_CONTENT_TYPE 135
+#define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 151
#define CMS_R_UNSUPPORTED_TYPE 136
#define CMS_R_VERIFICATION_FAILURE 137
BIO_get_cipher_ctx(b, &ctx);
if (enc)
+ {
ciph = ec->cipher;
+ /* If not keeping key set cipher to NULL so subsequent calls
+ * decrypt.
+ */
+ if (ec->key)
+ ec->cipher = NULL;
+ }
else
{
ciph = EVP_get_cipherbyobj(calg->algorithm);
goto err;
}
- if (enc)
- calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
-
if (enc)
{
int ivlen;
+ calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
/* Generate a random IV if we need one */
ivlen = EVP_CIPHER_CTX_iv_length(ctx);
if (ivlen > 0)
}
}
else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0)
- {
- CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
+ {
+ CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
- goto err;
- }
+ goto err;
+ }
if (enc && !ec->key)
return NULL;
}
-static int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
+int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
const EVP_CIPHER *cipher,
const unsigned char *key, size_t keylen)
{
BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
{
CMS_EncryptedData *enc = cms->d.encryptedData;
- if (enc->unprotectedAttrs)
+ if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
enc->version = 2;
return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
}
STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms)
{
CMS_EnvelopedData *env;
- env = cms_enveloped_data_init(cms);
+ env = cms_get0_enveloped(cms);
if (!env)
return NULL;
return env->recipientInfos;
return ri->type;
}
+CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
+ {
+ CMS_ContentInfo *cms;
+ CMS_EnvelopedData *env;
+ cms = CMS_ContentInfo_new();
+ if (!cms)
+ goto merr;
+ env = cms_enveloped_data_init(cms);
+ if (!env)
+ goto merr;
+ if (!cms_EncryptedContent_init(env->encryptedContentInfo,
+ cipher, NULL, 0))
+ goto merr;
+ return cms;
+ merr:
+ if (cms)
+ CMS_ContentInfo_free(cms);
+ CMSerr(CMS_F_CMS_ENVELOPEDDATA_CREATE, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
/* Add a recipient certificate. For now only handle key transport.
* If we ever handle key agreement will need updating.
*/
-#if 0 /* currently unused/undeclared */
CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
X509 *recip, unsigned int flags)
{
CMS_EnvelopedData *env;
EVP_PKEY *pk = NULL;
int i, type;
- /* Init enveloped data */
- env = cms_enveloped_data_init(cms);
+ env = cms_get0_enveloped(cms);
if (!env)
goto err;
- /* Initialized recipient info */
+ /* Initialize recipient info */
ri = M_ASN1_new_of(CMS_RecipientInfo);
if (!ri)
goto merr;
- /* Initialize and add key transrport recipient info */
+ /* Initialize and add key transport recipient info */
ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo);
if (!ri->d.ktri)
goto err;
}
CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509);
- CRYPTO_add(&pk->references, 1, CRYPTO_LOCK_EVP_PKEY);
ktri->pkey = pk;
ktri->recip = recip;
return NULL;
}
-#endif
int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
EVP_PKEY **pk, X509 **recip,
return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert);
}
+/* Encrypt content key in key transport recipient info */
+
+static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri)
+ {
+ CMS_KeyTransRecipientInfo *ktri;
+ CMS_EncryptedContentInfo *ec;
+ EVP_PKEY_CTX *pctx = NULL;
+ unsigned char *ek = NULL;
+ size_t eklen;
+
+ int ret = 0;
+
+ if (ri->type != CMS_RECIPINFO_TRANS)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT,
+ CMS_R_NOT_KEY_TRANSPORT);
+ return 0;
+ }
+ ktri = ri->d.ktri;
+ ec = cms->d.envelopedData->encryptedContentInfo;
+
+ pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
+ if (!pctx)
+ return 0;
+
+ if (EVP_PKEY_encrypt_init(pctx) <= 0)
+ goto err;
+
+ if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
+ EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_CTRL_ERROR);
+ goto err;
+ }
+
+ if (EVP_PKEY_encrypt(pctx, NULL, &eklen, ec->key, ec->keylen) <= 0)
+ goto err;
+
+ ek = OPENSSL_malloc(eklen);
+
+ if (ek == NULL)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (EVP_PKEY_encrypt(pctx, ek, &eklen, ec->key, ec->keylen) <= 0)
+ goto err;
+
+ ASN1_STRING_set0(ktri->encryptedKey, ek, eklen);
+ ek = NULL;
+
+ ret = 1;
+
+ err:
+ if (pctx)
+ EVP_PKEY_CTX_free(pctx);
+ if (ek)
+ OPENSSL_free(ek);
+ return ret;
+
+ }
+
int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
EVP_PKEY *pkey)
{
BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
{
CMS_EncryptedContentInfo *ec;
+ STACK_OF(CMS_RecipientInfo) *rinfos;
+ CMS_RecipientInfo *ri;
+ int i, r, ok = 0;
+ BIO *ret;
+
+ /* Get BIO first to set up key */
+
ec = cms->d.envelopedData->encryptedContentInfo;
- return cms_EncryptedContent_init_bio(ec);
+ ret = cms_EncryptedContent_init_bio(ec);
+
+ /* If error or no cipher end of processing */
+
+ if (!ret || !ec->cipher)
+ return ret;
+
+
+ rinfos = cms->d.envelopedData->recipientInfos;
+
+ for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++)
+ {
+ ri = sk_CMS_RecipientInfo_value(rinfos, i);
+ if (ri->type == CMS_RECIPINFO_TRANS)
+ r = cms_RecipientInfo_ktri_encrypt(cms, ri);
+ else
+ {
+ CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
+ CMS_R_UNSUPPORTED_RECIPIENT_TYPE);
+ goto err;
+ }
+ if (r <= 0)
+ {
+ CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
+ CMS_R_ERROR_SETTING_RECIPIENTINFO);
+ goto err;
+ }
+ }
+
+ ok = 1;
+
+ err:
+ ec->cipher = NULL;
+ if (ec->key)
+ {
+ OPENSSL_cleanse(ec->key, ec->keylen);
+ OPENSSL_free(ec->key);
+ ec->key = NULL;
+ ec->keylen = 0;
+ }
+ if (ok)
+ return ret;
+ BIO_free(ret);
+ return NULL;
+
}
static ERR_STRING_DATA CMS_str_functs[]=
{
{ERR_FUNC(CMS_F_CHECK_CONTENT), "CHECK_CONTENT"},
-{ERR_FUNC(CMS_F_CMS_ADD1_RECIPIENT_CERT), "CMS_ADD1_RECIPIENT_CERT"},
+{ERR_FUNC(CMS_F_CMS_ADD1_RECIPIENT_CERT), "CMS_add1_recipient_cert"},
{ERR_FUNC(CMS_F_CMS_ADD1_SIGNER), "CMS_add1_signer"},
{ERR_FUNC(CMS_F_CMS_ADD1_SIGNINGTIME), "CMS_ADD1_SIGNINGTIME"},
{ERR_FUNC(CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT), "CMS_BIO_TO_ENCRYPTEDCONTENT"},
{ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO), "CMS_DIGESTALGORITHM_INIT_BIO"},
{ERR_FUNC(CMS_F_CMS_DIGESTEDDATA_DO_FINAL), "CMS_DIGESTEDDATA_DO_FINAL"},
{ERR_FUNC(CMS_F_CMS_DIGEST_VERIFY), "CMS_digest_verify"},
+{ERR_FUNC(CMS_F_CMS_ENCRYPT), "CMS_encrypt"},
{ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_DECRYPT_BIO), "CMS_ENCRYPTEDCONTENT_DECRYPT_BIO"},
{ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_ENCRYPT_BIO), "CMS_ENCRYPTEDCONTENT_ENCRYPT_BIO"},
{ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO), "CMS_ENCRYPTEDCONTENT_INIT_BIO"},
{ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_INIT_BIO), "CMS_ENCRYPTEDDATA_INIT_BIO"},
{ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY), "CMS_EncryptedData_set1_key"},
{ERR_FUNC(CMS_F_CMS_ENCRYPTED_DATA_DECRYPT), "CMS_ENCRYPTED_DATA_DECRYPT"},
+{ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_CREATE), "CMS_EnvelopedData_create"},
+{ERR_FUNC(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO), "CMS_ENVELOPEDDATA_INIT_BIO"},
{ERR_FUNC(CMS_F_CMS_ENVELOPED_DATA_INIT), "CMS_ENVELOPED_DATA_INIT"},
{ERR_FUNC(CMS_F_CMS_FINAL), "CMS_final"},
{ERR_FUNC(CMS_F_CMS_GET0_CERTIFICATE_CHOICES), "CMS_GET0_CERTIFICATE_CHOICES"},
{ERR_FUNC(CMS_F_CMS_GET0_SIGNED), "CMS_GET0_SIGNED"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_DECRYPT), "CMS_RecipientInfo_decrypt"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP), "CMS_RecipientInfo_ktri_cert_cmp"},
+{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT), "CMS_RECIPIENTINFO_KTRI_ENCRYPT"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS), "CMS_RecipientInfo_ktri_get0_algs"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID), "CMS_RecipientInfo_ktri_get0_signer_id"},
{ERR_FUNC(CMS_F_CMS_SET1_SIGNERIDENTIFIER), "CMS_SET1_SIGNERIDENTIFIER"},
{ERR_REASON(CMS_R_CTRL_FAILURE) ,"ctrl failure"},
{ERR_REASON(CMS_R_ERROR_GETTING_PUBLIC_KEY),"error getting public key"},
{ERR_REASON(CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE),"error reading messagedigest attribute"},
+{ERR_REASON(CMS_R_ERROR_SETTING_RECIPIENTINFO),"error setting recipientinfo"},
{ERR_REASON(CMS_R_INVALID_KEY_LENGTH) ,"invalid key length"},
{ERR_REASON(CMS_R_MD_BIO_INIT_ERROR) ,"md bio init error"},
{ERR_REASON(CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH),"messagedigest attribute wrong length"},
{ERR_REASON(CMS_R_NO_PUBLIC_KEY) ,"no public key"},
{ERR_REASON(CMS_R_NO_SIGNERS) ,"no signers"},
{ERR_REASON(CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),"private key does not match certificate"},
+{ERR_REASON(CMS_R_RECIPIENT_ERROR) ,"recipient error"},
{ERR_REASON(CMS_R_SIGNER_CERTIFICATE_NOT_FOUND),"signer certificate not found"},
{ERR_REASON(CMS_R_SIGNFINAL_ERROR) ,"signfinal error"},
{ERR_REASON(CMS_R_SMIME_TEXT_ERROR) ,"smime text error"},
{ERR_REASON(CMS_R_UNKNOWN_ID) ,"unknown id"},
{ERR_REASON(CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"},
{ERR_REASON(CMS_R_UNSUPPORTED_CONTENT_TYPE),"unsupported content type"},
+{ERR_REASON(CMS_R_UNSUPPORTED_RECIPIENT_TYPE),"unsupported recipient type"},
{ERR_REASON(CMS_R_UNSUPPORTED_TYPE) ,"unsupported type"},
{ERR_REASON(CMS_R_VERIFICATION_FAILURE) ,"verification failure"},
{0,NULL}
{
ASN1_OBJECT *eContentType;
ASN1_OCTET_STRING *eContent;
+ /* Set to 1 if incomplete structure only part set up */
+ int partial;
};
struct CMS_SignerInfo_st
BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec);
BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms);
+int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
+ const EVP_CIPHER *cipher,
+ const unsigned char *key, size_t keylen);
BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
cms->d.signedData->version = 1;
cms->d.signedData->encapContentInfo->eContentType =
OBJ_nid2obj(NID_pkcs7_data);
+ cms->d.signedData->encapContentInfo->partial = 1;
ASN1_OBJECT_free(cms->contentType);
cms->contentType = OBJ_nid2obj(NID_pkcs7_signed);
return cms->d.signedData;
if (!cms_SignerInfo_content_sign(si, chain))
return 0;
}
+ cms->d.signedData->encapContentInfo->partial = 0;
return 1;
}
sd = cms_get0_signed(cms);
if (!sd)
return NULL;
- cms_sd_set_version(sd);
+ if (cms->d.signedData->encapContentInfo->partial)
+ cms_sd_set_version(sd);
for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++)
{
X509_ALGOR *digestAlgorithm;
return NULL;
}
-/* Placeholder for now... */
-
-CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
+CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
const EVP_CIPHER *cipher, unsigned int flags)
{
+ CMS_ContentInfo *cms;
+ int i;
+ X509 *recip;
+ cms = CMS_EnvelopedData_create(cipher);
+ if (!cms)
+ goto merr;
+ for (i = 0; i < sk_X509_num(certs); i++)
+ {
+ recip = sk_X509_value(certs, i);
+ if (!CMS_add1_recipient_cert(cms, recip, flags))
+ {
+ CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
+ goto err;
+ }
+ }
+
+ if(!(flags & CMS_DETACHED))
+ CMS_set_detached(cms, 0);
+
+ if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, data, flags))
+ return cms;
+
+ return cms;
+
+ merr:
+ CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
+ err:
+ if (cms)
+ CMS_ContentInfo_free(cms);
return NULL;
}
ri = sk_CMS_RecipientInfo_value(ris, i);
if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
continue;
- if (cert)
+ /* If we have a cert try matching RecipientInfo otherwise
+ * try them all.
+ */
+ if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0))
{
- if (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0)
- {
- if (CMS_RecipientInfo_decrypt(cms, ri, pk) <=0)
- return 0;
- else
- break;
- }
+ if (CMS_RecipientInfo_decrypt(cms, ri, pk) > 0)
+ break;
+ else if (cert)
+ return 0;
}
}