check in v3.8.2 source

This commit is contained in:
2023-11-06 23:46:37 -08:00
parent e2db88c634
commit 2b68369a2b
1216 changed files with 563118 additions and 0 deletions

1622
crypto/cms/cms_asn1.c Normal file

File diff suppressed because it is too large Load Diff

231
crypto/cms/cms_att.c Normal file
View File

@@ -0,0 +1,231 @@
/* $OpenBSD: cms_att.c,v 1.11 2023/07/08 08:26:26 beck Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
#include "cms_local.h"
/* CMS SignedData Attribute utilities */
int
CMS_signed_get_attr_count(const CMS_SignerInfo *si)
{
return X509at_get_attr_count(si->signedAttrs);
}
LCRYPTO_ALIAS(CMS_signed_get_attr_count);
int
CMS_signed_get_attr_by_NID(const CMS_SignerInfo *si, int nid, int lastpos)
{
return X509at_get_attr_by_NID(si->signedAttrs, nid, lastpos);
}
LCRYPTO_ALIAS(CMS_signed_get_attr_by_NID);
int
CMS_signed_get_attr_by_OBJ(const CMS_SignerInfo *si, const ASN1_OBJECT *obj,
int lastpos)
{
return X509at_get_attr_by_OBJ(si->signedAttrs, obj, lastpos);
}
LCRYPTO_ALIAS(CMS_signed_get_attr_by_OBJ);
X509_ATTRIBUTE *
CMS_signed_get_attr(const CMS_SignerInfo *si, int loc)
{
return X509at_get_attr(si->signedAttrs, loc);
}
LCRYPTO_ALIAS(CMS_signed_get_attr);
X509_ATTRIBUTE *
CMS_signed_delete_attr(CMS_SignerInfo *si, int loc)
{
return X509at_delete_attr(si->signedAttrs, loc);
}
LCRYPTO_ALIAS(CMS_signed_delete_attr);
int
CMS_signed_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr)
{
if (X509at_add1_attr(&si->signedAttrs, attr))
return 1;
return 0;
}
LCRYPTO_ALIAS(CMS_signed_add1_attr);
int
CMS_signed_add1_attr_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *obj, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_OBJ(&si->signedAttrs, obj, type, bytes, len))
return 1;
return 0;
}
LCRYPTO_ALIAS(CMS_signed_add1_attr_by_OBJ);
int
CMS_signed_add1_attr_by_NID(CMS_SignerInfo *si, int nid, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_NID(&si->signedAttrs, nid, type, bytes, len))
return 1;
return 0;
}
LCRYPTO_ALIAS(CMS_signed_add1_attr_by_NID);
int
CMS_signed_add1_attr_by_txt(CMS_SignerInfo *si, const char *attrname, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_txt(&si->signedAttrs, attrname, type, bytes, len))
return 1;
return 0;
}
LCRYPTO_ALIAS(CMS_signed_add1_attr_by_txt);
void *
CMS_signed_get0_data_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *oid,
int lastpos, int type)
{
return X509at_get0_data_by_OBJ(si->signedAttrs, oid, lastpos, type);
}
LCRYPTO_ALIAS(CMS_signed_get0_data_by_OBJ);
int
CMS_unsigned_get_attr_count(const CMS_SignerInfo *si)
{
return X509at_get_attr_count(si->unsignedAttrs);
}
LCRYPTO_ALIAS(CMS_unsigned_get_attr_count);
int
CMS_unsigned_get_attr_by_NID(const CMS_SignerInfo *si, int nid, int lastpos)
{
return X509at_get_attr_by_NID(si->unsignedAttrs, nid, lastpos);
}
LCRYPTO_ALIAS(CMS_unsigned_get_attr_by_NID);
int
CMS_unsigned_get_attr_by_OBJ(const CMS_SignerInfo *si, const ASN1_OBJECT *obj,
int lastpos)
{
return X509at_get_attr_by_OBJ(si->unsignedAttrs, obj, lastpos);
}
LCRYPTO_ALIAS(CMS_unsigned_get_attr_by_OBJ);
X509_ATTRIBUTE *
CMS_unsigned_get_attr(const CMS_SignerInfo *si, int loc)
{
return X509at_get_attr(si->unsignedAttrs, loc);
}
LCRYPTO_ALIAS(CMS_unsigned_get_attr);
X509_ATTRIBUTE *
CMS_unsigned_delete_attr(CMS_SignerInfo *si, int loc)
{
return X509at_delete_attr(si->unsignedAttrs, loc);
}
LCRYPTO_ALIAS(CMS_unsigned_delete_attr);
int
CMS_unsigned_add1_attr(CMS_SignerInfo *si, X509_ATTRIBUTE *attr)
{
if (X509at_add1_attr(&si->unsignedAttrs, attr))
return 1;
return 0;
}
LCRYPTO_ALIAS(CMS_unsigned_add1_attr);
int
CMS_unsigned_add1_attr_by_OBJ(CMS_SignerInfo *si, const ASN1_OBJECT *obj,
int type, const void *bytes, int len)
{
if (X509at_add1_attr_by_OBJ(&si->unsignedAttrs, obj, type, bytes, len))
return 1;
return 0;
}
LCRYPTO_ALIAS(CMS_unsigned_add1_attr_by_OBJ);
int
CMS_unsigned_add1_attr_by_NID(CMS_SignerInfo *si, int nid, int type,
const void *bytes, int len)
{
if (X509at_add1_attr_by_NID(&si->unsignedAttrs, nid, type, bytes, len))
return 1;
return 0;
}
LCRYPTO_ALIAS(CMS_unsigned_add1_attr_by_NID);
int
CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si, const char *attrname,
int type, const void *bytes, int len)
{
if (X509at_add1_attr_by_txt(&si->unsignedAttrs, attrname, type,
bytes, len))
return 1;
return 0;
}
LCRYPTO_ALIAS(CMS_unsigned_add1_attr_by_txt);
void *
CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid, int lastpos,
int type)
{
return X509at_get0_data_by_OBJ(si->unsignedAttrs, oid, lastpos, type);
}
LCRYPTO_ALIAS(CMS_unsigned_get0_data_by_OBJ);
/* Specific attribute cases */

150
crypto/cms/cms_dd.c Normal file
View File

@@ -0,0 +1,150 @@
/* $OpenBSD: cms_dd.c,v 1.15 2022/11/26 16:08:51 tb Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <string.h>
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
#include "cms_local.h"
/* CMS DigestedData Utilities */
CMS_ContentInfo *
cms_DigestedData_create(const EVP_MD *md)
{
CMS_ContentInfo *cms;
CMS_DigestedData *dd;
cms = CMS_ContentInfo_new();
if (cms == NULL)
return NULL;
dd = (CMS_DigestedData *)ASN1_item_new(&CMS_DigestedData_it);
if (dd == NULL)
goto err;
cms->contentType = OBJ_nid2obj(NID_pkcs7_digest);
cms->d.digestedData = dd;
dd->version = 0;
dd->encapContentInfo->eContentType = OBJ_nid2obj(NID_pkcs7_data);
X509_ALGOR_set_md(dd->digestAlgorithm, md);
return cms;
err:
CMS_ContentInfo_free(cms);
return NULL;
}
BIO *
cms_DigestedData_init_bio(CMS_ContentInfo *cms)
{
CMS_DigestedData *dd;
dd = cms->d.digestedData;
return cms_DigestAlgorithm_init_bio(dd->digestAlgorithm);
}
int
cms_DigestedData_do_final(CMS_ContentInfo *cms, BIO *chain, int verify)
{
EVP_MD_CTX *mctx = EVP_MD_CTX_new();
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int mdlen;
int r = 0;
CMS_DigestedData *dd;
if (mctx == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
dd = cms->d.digestedData;
if (!cms_DigestAlgorithm_find_ctx(mctx, chain, dd->digestAlgorithm))
goto err;
if (EVP_DigestFinal_ex(mctx, md, &mdlen) <= 0)
goto err;
if (verify) {
if (mdlen != (unsigned int)dd->digest->length) {
CMSerror(CMS_R_MESSAGEDIGEST_WRONG_LENGTH);
goto err;
}
if (memcmp(md, dd->digest->data, mdlen))
CMSerror(CMS_R_VERIFICATION_FAILURE);
else
r = 1;
} else {
if (!ASN1_STRING_set(dd->digest, md, mdlen))
goto err;
r = 1;
}
err:
EVP_MD_CTX_free(mctx);
return r;
}

263
crypto/cms/cms_enc.c Normal file
View File

@@ -0,0 +1,263 @@
/* $OpenBSD: cms_enc.c,v 1.23 2023/07/08 08:26:26 beck Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <string.h>
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
#include <openssl/rand.h>
#include "cms_local.h"
/* CMS EncryptedData Utilities */
/* Return BIO based on EncryptedContentInfo and key */
BIO *
cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
{
BIO *b;
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *ciph;
X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
unsigned char *tkey = NULL;
size_t tkeylen = 0;
int ok = 0;
int enc, keep_key = 0;
enc = ec->cipher ? 1 : 0;
b = BIO_new(BIO_f_cipher());
if (b == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
return NULL;
}
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);
if (!ciph) {
CMSerror(CMS_R_UNKNOWN_CIPHER);
goto err;
}
}
if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) {
CMSerror(CMS_R_CIPHER_INITIALISATION_ERROR);
goto err;
}
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) {
arc4random_buf(iv, ivlen);
piv = iv;
}
} else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) {
CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
goto err;
}
tkeylen = EVP_CIPHER_CTX_key_length(ctx);
/* Generate random session key */
if (!enc || !ec->key) {
tkey = malloc(tkeylen);
if (tkey == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
goto err;
}
if (!ec->key) {
ec->key = tkey;
ec->keylen = tkeylen;
tkey = NULL;
if (enc)
keep_key = 1;
else
ERR_clear_error();
}
if (ec->keylen != tkeylen) {
/* If necessary set key length */
if (!EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen)) {
/*
* Only reveal failure if debugging so we don't leak information
* which may be useful in MMA.
*/
if (enc || ec->debug) {
CMSerror(CMS_R_INVALID_KEY_LENGTH);
goto err;
} else {
/* Use random key */
freezero(ec->key, ec->keylen);
ec->key = tkey;
ec->keylen = tkeylen;
tkey = NULL;
ERR_clear_error();
}
}
}
if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
CMSerror(CMS_R_CIPHER_INITIALISATION_ERROR);
goto err;
}
if (enc) {
calg->parameter = ASN1_TYPE_new();
if (calg->parameter == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) {
CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
goto err;
}
/* If parameter type not set omit parameter */
if (calg->parameter->type == V_ASN1_UNDEF) {
ASN1_TYPE_free(calg->parameter);
calg->parameter = NULL;
}
}
ok = 1;
err:
if (!keep_key || !ok) {
freezero(ec->key, ec->keylen);
ec->key = NULL;
}
freezero(tkey, tkeylen);
if (ok)
return b;
BIO_free(b);
return NULL;
}
int
cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
const EVP_CIPHER *cipher, const unsigned char *key, size_t keylen)
{
ec->cipher = cipher;
if (key) {
if ((ec->key = malloc(keylen)) == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
memcpy(ec->key, key, keylen);
}
ec->keylen = keylen;
if (cipher)
ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
return 1;
}
int
CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
const unsigned char *key, size_t keylen)
{
CMS_EncryptedContentInfo *ec;
if (!key || !keylen) {
CMSerror(CMS_R_NO_KEY);
return 0;
}
if (ciph) {
cms->d.encryptedData = (CMS_EncryptedData *)ASN1_item_new(&CMS_EncryptedData_it);
if (!cms->d.encryptedData) {
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
cms->d.encryptedData->version = 0;
} else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
CMSerror(CMS_R_NOT_ENCRYPTED_DATA);
return 0;
}
ec = cms->d.encryptedData->encryptedContentInfo;
return cms_EncryptedContent_init(ec, ciph, key, keylen);
}
LCRYPTO_ALIAS(CMS_EncryptedData_set1_key);
BIO *
cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
{
CMS_EncryptedData *enc = cms->d.encryptedData;
if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
enc->version = 2;
return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
}

994
crypto/cms/cms_env.c Normal file
View File

@@ -0,0 +1,994 @@
/* $OpenBSD: cms_env.c,v 1.26 2023/07/08 08:26:26 beck Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <string.h>
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
#include <openssl/aes.h>
#include "cms_local.h"
#include "asn1/asn1_local.h"
#include "evp/evp_local.h"
/* CMS EnvelopedData Utilities */
CMS_EnvelopedData *
cms_get0_enveloped(CMS_ContentInfo *cms)
{
if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) {
CMSerror(CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
return NULL;
}
return cms->d.envelopedData;
}
static CMS_EnvelopedData *
cms_enveloped_data_init(CMS_ContentInfo *cms)
{
if (cms->d.other == NULL) {
cms->d.envelopedData = (CMS_EnvelopedData *)ASN1_item_new(&CMS_EnvelopedData_it);
if (!cms->d.envelopedData) {
CMSerror(ERR_R_MALLOC_FAILURE);
return NULL;
}
cms->d.envelopedData->version = 0;
cms->d.envelopedData->encryptedContentInfo->contentType =
OBJ_nid2obj(NID_pkcs7_data);
ASN1_OBJECT_free(cms->contentType);
cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped);
return cms->d.envelopedData;
}
return cms_get0_enveloped(cms);
}
int
cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
{
EVP_PKEY *pkey;
int i;
if (ri->type == CMS_RECIPINFO_TRANS)
pkey = ri->d.ktri->pkey;
else if (ri->type == CMS_RECIPINFO_AGREE) {
EVP_PKEY_CTX *pctx = ri->d.kari->pctx;
if (!pctx)
return 0;
pkey = EVP_PKEY_CTX_get0_pkey(pctx);
if (!pkey)
return 0;
} else
return 0;
if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
return 1;
i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_ENVELOPE, cmd, ri);
if (i == -2) {
CMSerror(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
return 0;
}
if (i <= 0) {
CMSerror(CMS_R_CTRL_FAILURE);
return 0;
}
return 1;
}
STACK_OF(CMS_RecipientInfo) *
CMS_get0_RecipientInfos(CMS_ContentInfo *cms)
{
CMS_EnvelopedData *env;
env = cms_get0_enveloped(cms);
if (!env)
return NULL;
return env->recipientInfos;
}
LCRYPTO_ALIAS(CMS_get0_RecipientInfos);
int
CMS_RecipientInfo_type(CMS_RecipientInfo *ri)
{
return ri->type;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_type);
EVP_PKEY_CTX *
CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri)
{
if (ri->type == CMS_RECIPINFO_TRANS)
return ri->d.ktri->pctx;
else if (ri->type == CMS_RECIPINFO_AGREE)
return ri->d.kari->pctx;
return NULL;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_get0_pkey_ctx);
CMS_ContentInfo *
CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
{
CMS_ContentInfo *cms;
CMS_EnvelopedData *env;
cms = CMS_ContentInfo_new();
if (cms == NULL)
goto merr;
env = cms_enveloped_data_init(cms);
if (env == NULL)
goto merr;
if (!cms_EncryptedContent_init(env->encryptedContentInfo, cipher,
NULL, 0))
goto merr;
return cms;
merr:
CMS_ContentInfo_free(cms);
CMSerror(ERR_R_MALLOC_FAILURE);
return NULL;
}
LCRYPTO_ALIAS(CMS_EnvelopedData_create);
/* Key Transport Recipient Info (KTRI) routines */
/* Initialise a ktri based on passed certificate and key */
static int
cms_RecipientInfo_ktri_init(CMS_RecipientInfo *ri, X509 *recip, EVP_PKEY *pk,
unsigned int flags)
{
CMS_KeyTransRecipientInfo *ktri;
int idtype;
ri->d.ktri = (CMS_KeyTransRecipientInfo *)ASN1_item_new(&CMS_KeyTransRecipientInfo_it);
if (!ri->d.ktri)
return 0;
ri->type = CMS_RECIPINFO_TRANS;
ktri = ri->d.ktri;
if (flags & CMS_USE_KEYID) {
ktri->version = 2;
idtype = CMS_RECIPINFO_KEYIDENTIFIER;
} else {
ktri->version = 0;
idtype = CMS_RECIPINFO_ISSUER_SERIAL;
}
/*
* Not a typo: RecipientIdentifier and SignerIdentifier are the same
* structure.
*/
if (!cms_set1_SignerIdentifier(ktri->rid, recip, idtype))
return 0;
X509_up_ref(recip);
EVP_PKEY_up_ref(pk);
ktri->pkey = pk;
ktri->recip = recip;
if (flags & CMS_KEY_PARAM) {
ktri->pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
if (ktri->pctx == NULL)
return 0;
if (EVP_PKEY_encrypt_init(ktri->pctx) <= 0)
return 0;
} else if (!cms_env_asn1_ctrl(ri, 0))
return 0;
return 1;
}
/*
* Add a recipient certificate using appropriate type of RecipientInfo
*/
CMS_RecipientInfo *
CMS_add1_recipient_cert(CMS_ContentInfo *cms, X509 *recip, unsigned int flags)
{
CMS_RecipientInfo *ri = NULL;
CMS_EnvelopedData *env;
EVP_PKEY *pk = NULL;
env = cms_get0_enveloped(cms);
if (!env)
goto err;
/* Initialize recipient info */
ri = (CMS_RecipientInfo *)ASN1_item_new(&CMS_RecipientInfo_it);
if (!ri)
goto merr;
pk = X509_get0_pubkey(recip);
if (!pk) {
CMSerror(CMS_R_ERROR_GETTING_PUBLIC_KEY);
goto err;
}
switch (cms_pkey_get_ri_type(pk)) {
case CMS_RECIPINFO_TRANS:
if (!cms_RecipientInfo_ktri_init(ri, recip, pk, flags))
goto err;
break;
case CMS_RECIPINFO_AGREE:
if (!cms_RecipientInfo_kari_init(ri, recip, pk, flags))
goto err;
break;
default:
CMSerror(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
goto err;
}
if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
goto merr;
return ri;
merr:
CMSerror(ERR_R_MALLOC_FAILURE);
err:
ASN1_item_free((ASN1_VALUE *)ri, &CMS_RecipientInfo_it);
return NULL;
}
LCRYPTO_ALIAS(CMS_add1_recipient_cert);
int
CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, EVP_PKEY **pk,
X509 **recip, X509_ALGOR **palg)
{
CMS_KeyTransRecipientInfo *ktri;
if (ri->type != CMS_RECIPINFO_TRANS) {
CMSerror(CMS_R_NOT_KEY_TRANSPORT);
return 0;
}
ktri = ri->d.ktri;
if (pk)
*pk = ktri->pkey;
if (recip)
*recip = ktri->recip;
if (palg)
*palg = ktri->keyEncryptionAlgorithm;
return 1;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_ktri_get0_algs);
int
CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
ASN1_OCTET_STRING **keyid, X509_NAME **issuer, ASN1_INTEGER **sno)
{
CMS_KeyTransRecipientInfo *ktri;
if (ri->type != CMS_RECIPINFO_TRANS) {
CMSerror(CMS_R_NOT_KEY_TRANSPORT);
return 0;
}
ktri = ri->d.ktri;
return cms_SignerIdentifier_get0_signer_id(ktri->rid, keyid, issuer, sno);
}
LCRYPTO_ALIAS(CMS_RecipientInfo_ktri_get0_signer_id);
int
CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert)
{
if (ri->type != CMS_RECIPINFO_TRANS) {
CMSerror(CMS_R_NOT_KEY_TRANSPORT);
return -2;
}
return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert);
}
LCRYPTO_ALIAS(CMS_RecipientInfo_ktri_cert_cmp);
int
CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey)
{
if (ri->type != CMS_RECIPINFO_TRANS) {
CMSerror(CMS_R_NOT_KEY_TRANSPORT);
return 0;
}
EVP_PKEY_free(ri->d.ktri->pkey);
ri->d.ktri->pkey = pkey;
return 1;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_set0_pkey);
/* 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;
unsigned char *ek = NULL;
size_t eklen;
int ret = 0;
if (ri->type != CMS_RECIPINFO_TRANS) {
CMSerror(CMS_R_NOT_KEY_TRANSPORT);
return 0;
}
ktri = ri->d.ktri;
ec = cms->d.envelopedData->encryptedContentInfo;
pctx = ktri->pctx;
if (pctx) {
if (!cms_env_asn1_ctrl(ri, 0))
goto err;
} else {
pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
if (pctx == NULL)
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) {
CMSerror(CMS_R_CTRL_ERROR);
goto err;
}
if (EVP_PKEY_encrypt(pctx, NULL, &eklen, ec->key, ec->keylen) <= 0)
goto err;
ek = malloc(eklen);
if (ek == NULL) {
CMSerror(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:
EVP_PKEY_CTX_free(pctx);
ktri->pctx = NULL;
free(ek);
return ret;
}
/* Decrypt content key from KTRI */
static int
cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
{
CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
EVP_PKEY *pkey = ktri->pkey;
unsigned char *ek = NULL;
size_t eklen;
size_t fixlen = 0;
int ret = 0;
CMS_EncryptedContentInfo *ec;
ec = cms->d.envelopedData->encryptedContentInfo;
if (ktri->pkey == NULL) {
CMSerror(CMS_R_NO_PRIVATE_KEY);
return 0;
}
if (cms->d.envelopedData->encryptedContentInfo->havenocert &&
!cms->d.envelopedData->encryptedContentInfo->debug) {
X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
const EVP_CIPHER *ciph;
if ((ciph = EVP_get_cipherbyobj(calg->algorithm)) == NULL) {
CMSerror(CMS_R_UNKNOWN_CIPHER);
return 0;
}
fixlen = EVP_CIPHER_key_length(ciph);
}
ktri->pctx = EVP_PKEY_CTX_new(pkey, NULL);
if (ktri->pctx == NULL)
return 0;
if (EVP_PKEY_decrypt_init(ktri->pctx) <= 0)
goto err;
if (!cms_env_asn1_ctrl(ri, 1))
goto err;
if (EVP_PKEY_CTX_ctrl(ktri->pctx, -1, EVP_PKEY_OP_DECRYPT,
EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0) {
CMSerror(CMS_R_CTRL_ERROR);
goto err;
}
if (EVP_PKEY_decrypt(ktri->pctx, NULL, &eklen, ktri->encryptedKey->data,
ktri->encryptedKey->length) <= 0 || eklen == 0 ||
(fixlen != 0 && eklen != fixlen)) {
CMSerror(CMS_R_CMS_LIB);
goto err;
}
ek = malloc(eklen);
if (ek == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (EVP_PKEY_decrypt(ktri->pctx, ek, &eklen, ktri->encryptedKey->data,
ktri->encryptedKey->length) <= 0) {
CMSerror(CMS_R_CMS_LIB);
goto err;
}
ret = 1;
freezero(ec->key, ec->keylen);
ec->key = ek;
ec->keylen = eklen;
err:
EVP_PKEY_CTX_free(ktri->pctx);
ktri->pctx = NULL;
if (!ret)
free(ek);
return ret;
}
/* Key Encrypted Key (KEK) RecipientInfo routines */
int
CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, const unsigned char *id,
size_t idlen)
{
ASN1_OCTET_STRING tmp_os;
CMS_KEKRecipientInfo *kekri;
if (ri->type != CMS_RECIPINFO_KEK) {
CMSerror(CMS_R_NOT_KEK);
return -2;
}
kekri = ri->d.kekri;
tmp_os.type = V_ASN1_OCTET_STRING;
tmp_os.flags = 0;
tmp_os.data = (unsigned char *)id;
tmp_os.length = (int)idlen;
return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier);
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kekri_id_cmp);
/* For now hard code AES key wrap info */
static size_t
aes_wrap_keylen(int nid)
{
switch (nid) {
case NID_id_aes128_wrap:
return 16;
case NID_id_aes192_wrap:
return 24;
case NID_id_aes256_wrap:
return 32;
default:
return 0;
}
}
CMS_RecipientInfo *
CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, unsigned char *key,
size_t keylen, unsigned char *id, size_t idlen, ASN1_GENERALIZEDTIME *date,
ASN1_OBJECT *otherTypeId, ASN1_TYPE *otherType)
{
CMS_RecipientInfo *ri = NULL;
CMS_EnvelopedData *env;
CMS_KEKRecipientInfo *kekri;
env = cms_get0_enveloped(cms);
if (!env)
goto err;
if (nid == NID_undef) {
switch (keylen) {
case 16:
nid = NID_id_aes128_wrap;
break;
case 24:
nid = NID_id_aes192_wrap;
break;
case 32:
nid = NID_id_aes256_wrap;
break;
default:
CMSerror(CMS_R_INVALID_KEY_LENGTH);
goto err;
}
} else {
size_t exp_keylen = aes_wrap_keylen(nid);
if (!exp_keylen) {
CMSerror(CMS_R_UNSUPPORTED_KEK_ALGORITHM);
goto err;
}
if (keylen != exp_keylen) {
CMSerror(CMS_R_INVALID_KEY_LENGTH);
goto err;
}
}
/* Initialize recipient info */
ri = (CMS_RecipientInfo *)ASN1_item_new(&CMS_RecipientInfo_it);
if (!ri)
goto merr;
ri->d.kekri = (CMS_KEKRecipientInfo *)ASN1_item_new(&CMS_KEKRecipientInfo_it);
if (!ri->d.kekri)
goto merr;
ri->type = CMS_RECIPINFO_KEK;
kekri = ri->d.kekri;
if (otherTypeId) {
kekri->kekid->other = (CMS_OtherKeyAttribute *)ASN1_item_new(&CMS_OtherKeyAttribute_it);
if (kekri->kekid->other == NULL)
goto merr;
}
if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
goto merr;
/* After this point no calls can fail */
kekri->version = 4;
kekri->key = key;
kekri->keylen = keylen;
ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen);
kekri->kekid->date = date;
if (kekri->kekid->other) {
kekri->kekid->other->keyAttrId = otherTypeId;
kekri->kekid->other->keyAttr = otherType;
}
X509_ALGOR_set0(kekri->keyEncryptionAlgorithm,
OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL);
return ri;
merr:
CMSerror(ERR_R_MALLOC_FAILURE);
err:
ASN1_item_free((ASN1_VALUE *)ri, &CMS_RecipientInfo_it);
return NULL;
}
LCRYPTO_ALIAS(CMS_add0_recipient_key);
int
CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri, X509_ALGOR **palg,
ASN1_OCTET_STRING **pid, ASN1_GENERALIZEDTIME **pdate,
ASN1_OBJECT **potherid, ASN1_TYPE **pothertype)
{
CMS_KEKIdentifier *rkid;
if (ri->type != CMS_RECIPINFO_KEK) {
CMSerror(CMS_R_NOT_KEK);
return 0;
}
rkid = ri->d.kekri->kekid;
if (palg)
*palg = ri->d.kekri->keyEncryptionAlgorithm;
if (pid)
*pid = rkid->keyIdentifier;
if (pdate)
*pdate = rkid->date;
if (potherid) {
if (rkid->other)
*potherid = rkid->other->keyAttrId;
else
*potherid = NULL;
}
if (pothertype) {
if (rkid->other)
*pothertype = rkid->other->keyAttr;
else
*pothertype = NULL;
}
return 1;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kekri_get0_id);
int
CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri, unsigned char *key,
size_t keylen)
{
CMS_KEKRecipientInfo *kekri;
if (ri->type != CMS_RECIPINFO_KEK) {
CMSerror(CMS_R_NOT_KEK);
return 0;
}
kekri = ri->d.kekri;
kekri->key = key;
kekri->keylen = keylen;
return 1;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_set0_key);
/* Encrypt content key in KEK recipient info */
static int
cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
{
CMS_EncryptedContentInfo *ec;
CMS_KEKRecipientInfo *kekri;
AES_KEY actx;
unsigned char *wkey = NULL;
int wkeylen;
int r = 0;
ec = cms->d.envelopedData->encryptedContentInfo;
kekri = ri->d.kekri;
if (!kekri->key) {
CMSerror(CMS_R_NO_KEY);
return 0;
}
if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx)) {
CMSerror(CMS_R_ERROR_SETTING_KEY);
goto err;
}
wkey = malloc(ec->keylen + 8);
if (wkey == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen);
if (wkeylen <= 0) {
CMSerror(CMS_R_WRAP_ERROR);
goto err;
}
ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen);
r = 1;
err:
if (!r)
free(wkey);
explicit_bzero(&actx, sizeof(actx));
return r;
}
/* Decrypt content key in KEK recipient info */
static int
cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
{
CMS_EncryptedContentInfo *ec;
CMS_KEKRecipientInfo *kekri;
AES_KEY actx;
unsigned char *ukey = NULL;
int ukeylen;
int r = 0, wrap_nid;
ec = cms->d.envelopedData->encryptedContentInfo;
kekri = ri->d.kekri;
if (!kekri->key) {
CMSerror(CMS_R_NO_KEY);
return 0;
}
wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm);
if (aes_wrap_keylen(wrap_nid) != kekri->keylen) {
CMSerror(CMS_R_INVALID_KEY_LENGTH);
return 0;
}
/* If encrypted key length is invalid don't bother */
if (kekri->encryptedKey->length < 16) {
CMSerror(CMS_R_INVALID_ENCRYPTED_KEY_LENGTH);
goto err;
}
if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx)) {
CMSerror(CMS_R_ERROR_SETTING_KEY);
goto err;
}
ukey = malloc(kekri->encryptedKey->length - 8);
if (ukey == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
ukeylen = AES_unwrap_key(&actx, NULL, ukey, kekri->encryptedKey->data,
kekri->encryptedKey->length);
if (ukeylen <= 0) {
CMSerror(CMS_R_UNWRAP_ERROR);
goto err;
}
freezero(ec->key, ec->keylen);
ec->key = ukey;
ec->keylen = ukeylen;
r = 1;
err:
if (!r)
free(ukey);
explicit_bzero(&actx, sizeof(actx));
return r;
}
int
CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
{
switch (ri->type) {
case CMS_RECIPINFO_TRANS:
return cms_RecipientInfo_ktri_decrypt(cms, ri);
case CMS_RECIPINFO_KEK:
return cms_RecipientInfo_kekri_decrypt(cms, ri);
case CMS_RECIPINFO_PASS:
return cms_RecipientInfo_pwri_crypt(cms, ri, 0);
default:
CMSerror(CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE);
return 0;
}
}
LCRYPTO_ALIAS(CMS_RecipientInfo_decrypt);
int
CMS_RecipientInfo_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
{
switch (ri->type) {
case CMS_RECIPINFO_TRANS:
return cms_RecipientInfo_ktri_encrypt(cms, ri);
case CMS_RECIPINFO_AGREE:
return cms_RecipientInfo_kari_encrypt(cms, ri);
case CMS_RECIPINFO_KEK:
return cms_RecipientInfo_kekri_encrypt(cms, ri);
case CMS_RECIPINFO_PASS:
return cms_RecipientInfo_pwri_crypt(cms, ri, 1);
default:
CMSerror(CMS_R_UNSUPPORTED_RECIPIENT_TYPE);
return 0;
}
}
LCRYPTO_ALIAS(CMS_RecipientInfo_encrypt);
/* Check structures and fixup version numbers (if necessary) */
static void
cms_env_set_originfo_version(CMS_EnvelopedData *env)
{
CMS_OriginatorInfo *org = env->originatorInfo;
int i;
if (org == NULL)
return;
for (i = 0; i < sk_CMS_CertificateChoices_num(org->certificates); i++) {
CMS_CertificateChoices *cch;
cch = sk_CMS_CertificateChoices_value(org->certificates, i);
if (cch->type == CMS_CERTCHOICE_OTHER) {
env->version = 4;
return;
} else if (cch->type == CMS_CERTCHOICE_V2ACERT) {
if (env->version < 3)
env->version = 3;
}
}
for (i = 0; i < sk_CMS_RevocationInfoChoice_num(org->crls); i++) {
CMS_RevocationInfoChoice *rch;
rch = sk_CMS_RevocationInfoChoice_value(org->crls, i);
if (rch->type == CMS_REVCHOICE_OTHER) {
env->version = 4;
return;
}
}
}
static void
cms_env_set_version(CMS_EnvelopedData *env)
{
int i;
CMS_RecipientInfo *ri;
/*
* Can't set version higher than 4 so if 4 or more already nothing to do.
*/
if (env->version >= 4)
return;
cms_env_set_originfo_version(env);
if (env->version >= 3)
return;
for (i = 0; i < sk_CMS_RecipientInfo_num(env->recipientInfos); i++) {
ri = sk_CMS_RecipientInfo_value(env->recipientInfos, i);
if (ri->type == CMS_RECIPINFO_PASS || ri->type == CMS_RECIPINFO_OTHER) {
env->version = 3;
return;
} else if (ri->type != CMS_RECIPINFO_TRANS
|| ri->d.ktri->version != 0) {
env->version = 2;
}
}
if (env->originatorInfo || env->unprotectedAttrs)
env->version = 2;
if (env->version == 2)
return;
env->version = 0;
}
BIO *
cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
{
CMS_EncryptedContentInfo *ec;
STACK_OF(CMS_RecipientInfo) *rinfos;
CMS_RecipientInfo *ri;
int i, ok = 0;
BIO *ret;
/* Get BIO first to set up key */
ec = cms->d.envelopedData->encryptedContentInfo;
ret = cms_EncryptedContent_init_bio(ec);
/* If error or no cipher end of processing */
if (!ret || !ec->cipher)
return ret;
/* Now encrypt content key according to each RecipientInfo type */
rinfos = cms->d.envelopedData->recipientInfos;
for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) {
ri = sk_CMS_RecipientInfo_value(rinfos, i);
if (CMS_RecipientInfo_encrypt(cms, ri) <= 0) {
CMSerror(CMS_R_ERROR_SETTING_RECIPIENTINFO);
goto err;
}
}
cms_env_set_version(cms->d.envelopedData);
ok = 1;
err:
ec->cipher = NULL;
freezero(ec->key, ec->keylen);
ec->key = NULL;
ec->keylen = 0;
if (ok)
return ret;
BIO_free(ret);
return NULL;
}
/*
* Get RecipientInfo type (if any) supported by a key (public or private). To
* retain compatibility with previous behaviour if the ctrl value isn't
* supported we assume key transport.
*/
int
cms_pkey_get_ri_type(EVP_PKEY *pk)
{
if (pk->ameth && pk->ameth->pkey_ctrl) {
int i, r;
i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_RI_TYPE, 0, &r);
if (i > 0)
return r;
}
return CMS_RECIPINFO_TRANS;
}

164
crypto/cms/cms_err.c Normal file
View File

@@ -0,0 +1,164 @@
/* $OpenBSD: cms_err.c,v 1.14 2023/07/08 08:26:26 beck Exp $ */
/*
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/cms.h>
#include <openssl/err.h>
#ifndef OPENSSL_NO_ERR
#define ERR_FUNC(func) ERR_PACK(ERR_LIB_CMS,func,0)
#define ERR_REASON(reason) ERR_PACK(ERR_LIB_CMS,0,reason)
static ERR_STRING_DATA CMS_str_functs[] = {
{ERR_FUNC(0xfff), "CRYPTO_internal"},
{0, NULL}
};
static ERR_STRING_DATA CMS_str_reasons[] = {
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ADD_SIGNER_ERROR), "add signer error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CERTIFICATE_ALREADY_PRESENT),
"certificate already present"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CERTIFICATE_HAS_NO_KEYID),
"certificate has no keyid"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CERTIFICATE_VERIFY_ERROR),
"certificate verify error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CIPHER_INITIALISATION_ERROR),
"cipher initialisation error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR),
"cipher parameter initialisation error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CMS_DATAFINAL_ERROR),
"cms datafinal error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CMS_LIB), "cms lib"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CONTENTIDENTIFIER_MISMATCH),
"contentidentifier mismatch"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CONTENT_NOT_FOUND), "content not found"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CONTENT_TYPE_MISMATCH),
"content type mismatch"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA),
"content type not compressed data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA),
"content type not enveloped data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA),
"content type not signed data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CONTENT_VERIFY_ERROR),
"content verify error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CTRL_ERROR), "ctrl error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CTRL_FAILURE), "ctrl failure"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_DECRYPT_ERROR), "decrypt error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_GETTING_PUBLIC_KEY),
"error getting public key"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE),
"error reading messagedigest attribute"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_SETTING_KEY), "error setting key"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_ERROR_SETTING_RECIPIENTINFO),
"error setting recipientinfo"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_ENCRYPTED_KEY_LENGTH),
"invalid encrypted key length"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER),
"invalid key encryption parameter"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_KEY_LENGTH), "invalid key length"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_MD_BIO_INIT_ERROR), "md bio init error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH),
"messagedigest attribute wrong length"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_MESSAGEDIGEST_WRONG_LENGTH),
"messagedigest wrong length"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_MSGSIGDIGEST_ERROR), "msgsigdigest error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE),
"msgsigdigest verification failure"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_MSGSIGDIGEST_WRONG_LENGTH),
"msgsigdigest wrong length"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NEED_ONE_SIGNER), "need one signer"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NOT_A_SIGNED_RECEIPT),
"not a signed receipt"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NOT_ENCRYPTED_DATA), "not encrypted data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NOT_KEK), "not kek"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NOT_KEY_AGREEMENT), "not key agreement"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NOT_KEY_TRANSPORT), "not key transport"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NOT_PWRI), "not pwri"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),
"not supported for this key type"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_CIPHER), "no cipher"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_CONTENT), "no content"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_CONTENT_TYPE), "no content type"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_DEFAULT_DIGEST), "no default digest"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_DIGEST_SET), "no digest set"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_KEY), "no key"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_KEY_OR_CERT), "no key or cert"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_MATCHING_DIGEST), "no matching digest"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_MATCHING_RECIPIENT),
"no matching recipient"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_MATCHING_SIGNATURE),
"no matching signature"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_MSGSIGDIGEST), "no msgsigdigest"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_PASSWORD), "no password"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_PRIVATE_KEY), "no private key"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_PUBLIC_KEY), "no public key"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_RECEIPT_REQUEST), "no receipt request"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_NO_SIGNERS), "no signers"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE),
"private key does not match certificate"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_RECEIPT_DECODE_ERROR),
"receipt decode error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_RECIPIENT_ERROR), "recipient error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND),
"signer certificate not found"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_SIGNFINAL_ERROR), "signfinal error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_SMIME_TEXT_ERROR), "smime text error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_STORE_INIT_ERROR), "store init error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_TYPE_NOT_COMPRESSED_DATA),
"type not compressed data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_TYPE_NOT_DATA), "type not data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_TYPE_NOT_DIGESTED_DATA),
"type not digested data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_TYPE_NOT_ENCRYPTED_DATA),
"type not encrypted data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_TYPE_NOT_ENVELOPED_DATA),
"type not enveloped data"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNABLE_TO_FINALIZE_CONTEXT),
"unable to finalize context"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNKNOWN_CIPHER), "unknown cipher"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNKNOWN_DIGEST_ALGORITHM),
"unknown digest algorithm"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNKNOWN_ID), "unknown id"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM),
"unsupported compression algorithm"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_CONTENT_TYPE),
"unsupported content type"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_KEK_ALGORITHM),
"unsupported kek algorithm"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM),
"unsupported key encryption algorithm"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE),
"unsupported recipientinfo type"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_RECIPIENT_TYPE),
"unsupported recipient type"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_TYPE), "unsupported type"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNWRAP_ERROR), "unwrap error"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNWRAP_FAILURE), "unwrap failure"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_VERIFICATION_FAILURE),
"verification failure"},
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_WRAP_ERROR), "wrap error"},
{0, NULL}
};
#endif
int
ERR_load_CMS_strings(void)
{
#ifndef OPENSSL_NO_ERR
if (ERR_func_error_string(CMS_str_functs[0].error) == NULL) {
ERR_load_strings(ERR_LIB_CMS, CMS_str_functs);
ERR_load_strings(ERR_LIB_CMS, CMS_str_reasons);
}
#endif
return 1;
}
LCRYPTO_ALIAS(ERR_load_CMS_strings);

408
crypto/cms/cms_ess.c Normal file
View File

@@ -0,0 +1,408 @@
/* $OpenBSD: cms_ess.c,v 1.23 2023/07/08 08:26:26 beck Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <string.h>
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
#include "cms_local.h"
CMS_ReceiptRequest *
d2i_CMS_ReceiptRequest(CMS_ReceiptRequest **a, const unsigned char **in, long len)
{
return (CMS_ReceiptRequest *)ASN1_item_d2i((ASN1_VALUE **)a, in, len,
&CMS_ReceiptRequest_it);
}
LCRYPTO_ALIAS(d2i_CMS_ReceiptRequest);
int
i2d_CMS_ReceiptRequest(CMS_ReceiptRequest *a, unsigned char **out)
{
return ASN1_item_i2d((ASN1_VALUE *)a, out, &CMS_ReceiptRequest_it);
}
LCRYPTO_ALIAS(i2d_CMS_ReceiptRequest);
CMS_ReceiptRequest *
CMS_ReceiptRequest_new(void)
{
return (CMS_ReceiptRequest *)ASN1_item_new(&CMS_ReceiptRequest_it);
}
LCRYPTO_ALIAS(CMS_ReceiptRequest_new);
void
CMS_ReceiptRequest_free(CMS_ReceiptRequest *a)
{
ASN1_item_free((ASN1_VALUE *)a, &CMS_ReceiptRequest_it);
}
LCRYPTO_ALIAS(CMS_ReceiptRequest_free);
/* ESS services: for now just Signed Receipt related */
int
CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr)
{
ASN1_STRING *str;
CMS_ReceiptRequest *rr = NULL;
if (prr)
*prr = NULL;
str = CMS_signed_get0_data_by_OBJ(si,
OBJ_nid2obj(NID_id_smime_aa_receiptRequest), -3, V_ASN1_SEQUENCE);
if (!str)
return 0;
rr = ASN1_item_unpack(str, &CMS_ReceiptRequest_it);
if (!rr)
return -1;
if (prr)
*prr = rr;
else
CMS_ReceiptRequest_free(rr);
return 1;
}
CMS_ReceiptRequest *
CMS_ReceiptRequest_create0(unsigned char *id, int idlen, int allorfirst,
STACK_OF(GENERAL_NAMES) *receiptList, STACK_OF(GENERAL_NAMES) *receiptsTo)
{
CMS_ReceiptRequest *rr = NULL;
rr = CMS_ReceiptRequest_new();
if (rr == NULL)
goto merr;
if (id)
ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
else {
if (!ASN1_STRING_set(rr->signedContentIdentifier, NULL, 32))
goto merr;
arc4random_buf(rr->signedContentIdentifier->data, 32);
}
sk_GENERAL_NAMES_pop_free(rr->receiptsTo, GENERAL_NAMES_free);
rr->receiptsTo = receiptsTo;
if (receiptList) {
rr->receiptsFrom->type = 1;
rr->receiptsFrom->d.receiptList = receiptList;
} else {
rr->receiptsFrom->type = 0;
rr->receiptsFrom->d.allOrFirstTier = allorfirst;
}
return rr;
merr:
CMSerror(ERR_R_MALLOC_FAILURE);
CMS_ReceiptRequest_free(rr);
return NULL;
}
int
CMS_add1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest *rr)
{
unsigned char *rrder = NULL;
int rrderlen, r = 0;
rrderlen = i2d_CMS_ReceiptRequest(rr, &rrder);
if (rrderlen < 0)
goto merr;
if (!CMS_signed_add1_attr_by_NID(si, NID_id_smime_aa_receiptRequest,
V_ASN1_SEQUENCE, rrder, rrderlen))
goto merr;
r = 1;
merr:
if (!r)
CMSerror(ERR_R_MALLOC_FAILURE);
free(rrder);
return r;
}
void
CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr, ASN1_STRING **pcid,
int *pallorfirst, STACK_OF(GENERAL_NAMES) **plist,
STACK_OF(GENERAL_NAMES) **prto)
{
if (pcid)
*pcid = rr->signedContentIdentifier;
if (rr->receiptsFrom->type == 0) {
if (pallorfirst)
*pallorfirst = (int)rr->receiptsFrom->d.allOrFirstTier;
if (plist)
*plist = NULL;
} else {
if (pallorfirst)
*pallorfirst = -1;
if (plist)
*plist = rr->receiptsFrom->d.receiptList;
}
if (prto)
*prto = rr->receiptsTo;
}
/* Digest a SignerInfo structure for msgSigDigest attribute processing */
static int
cms_msgSigDigest(CMS_SignerInfo *si, unsigned char *dig, unsigned int *diglen)
{
const EVP_MD *md;
md = EVP_get_digestbyobj(si->digestAlgorithm->algorithm);
if (md == NULL)
return 0;
if (!ASN1_item_digest(&CMS_Attributes_Verify_it, md,
si->signedAttrs, dig, diglen))
return 0;
return 1;
}
/* Add a msgSigDigest attribute to a SignerInfo */
int
cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src)
{
unsigned char dig[EVP_MAX_MD_SIZE];
unsigned int diglen;
if (!cms_msgSigDigest(src, dig, &diglen)) {
CMSerror(CMS_R_MSGSIGDIGEST_ERROR);
return 0;
}
if (!CMS_signed_add1_attr_by_NID(dest, NID_id_smime_aa_msgSigDigest,
V_ASN1_OCTET_STRING, dig, diglen)) {
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
return 1;
}
/* Verify signed receipt after it has already passed normal CMS verify */
int
cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms)
{
int r = 0, i;
CMS_ReceiptRequest *rr = NULL;
CMS_Receipt *rct = NULL;
STACK_OF(CMS_SignerInfo) *sis, *osis;
CMS_SignerInfo *si, *osi = NULL;
ASN1_OCTET_STRING *msig, **pcont;
ASN1_OBJECT *octype;
unsigned char dig[EVP_MAX_MD_SIZE];
unsigned int diglen;
/* Get SignerInfos, also checks SignedData content type */
osis = CMS_get0_SignerInfos(req_cms);
sis = CMS_get0_SignerInfos(cms);
if (!osis || !sis)
goto err;
if (sk_CMS_SignerInfo_num(sis) != 1) {
CMSerror(CMS_R_NEED_ONE_SIGNER);
goto err;
}
/* Check receipt content type */
if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_id_smime_ct_receipt) {
CMSerror(CMS_R_NOT_A_SIGNED_RECEIPT);
goto err;
}
/* Extract and decode receipt content */
pcont = CMS_get0_content(cms);
if (!pcont || !*pcont) {
CMSerror(CMS_R_NO_CONTENT);
goto err;
}
rct = ASN1_item_unpack(*pcont, &CMS_Receipt_it);
if (!rct) {
CMSerror(CMS_R_RECEIPT_DECODE_ERROR);
goto err;
}
/* Locate original request */
for (i = 0; i < sk_CMS_SignerInfo_num(osis); i++) {
osi = sk_CMS_SignerInfo_value(osis, i);
if (!ASN1_STRING_cmp(osi->signature, rct->originatorSignatureValue))
break;
}
if (i == sk_CMS_SignerInfo_num(osis)) {
CMSerror(CMS_R_NO_MATCHING_SIGNATURE);
goto err;
}
si = sk_CMS_SignerInfo_value(sis, 0);
/* Get msgSigDigest value and compare */
msig = CMS_signed_get0_data_by_OBJ(si,
OBJ_nid2obj(NID_id_smime_aa_msgSigDigest), -3, V_ASN1_OCTET_STRING);
if (!msig) {
CMSerror(CMS_R_NO_MSGSIGDIGEST);
goto err;
}
if (!cms_msgSigDigest(osi, dig, &diglen)) {
CMSerror(CMS_R_MSGSIGDIGEST_ERROR);
goto err;
}
if (diglen != (unsigned int)msig->length) {
CMSerror(CMS_R_MSGSIGDIGEST_WRONG_LENGTH);
goto err;
}
if (memcmp(dig, msig->data, diglen)) {
CMSerror(CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE);
goto err;
}
/* Compare content types */
octype = CMS_signed_get0_data_by_OBJ(osi,
OBJ_nid2obj(NID_pkcs9_contentType), -3, V_ASN1_OBJECT);
if (!octype) {
CMSerror(CMS_R_NO_CONTENT_TYPE);
goto err;
}
/* Compare details in receipt request */
if (OBJ_cmp(octype, rct->contentType)) {
CMSerror(CMS_R_CONTENT_TYPE_MISMATCH);
goto err;
}
/* Get original receipt request details */
if (CMS_get1_ReceiptRequest(osi, &rr) <= 0) {
CMSerror(CMS_R_NO_RECEIPT_REQUEST);
goto err;
}
if (ASN1_STRING_cmp(rr->signedContentIdentifier,
rct->signedContentIdentifier)) {
CMSerror(CMS_R_CONTENTIDENTIFIER_MISMATCH);
goto err;
}
r = 1;
err:
CMS_ReceiptRequest_free(rr);
ASN1_item_free((ASN1_VALUE *)rct, &CMS_Receipt_it);
return r;
}
/*
* Encode a Receipt into an OCTET STRING read for including into content of a
* SignedData ContentInfo.
*/
ASN1_OCTET_STRING *
cms_encode_Receipt(CMS_SignerInfo *si)
{
CMS_Receipt rct;
CMS_ReceiptRequest *rr = NULL;
ASN1_OBJECT *ctype;
ASN1_OCTET_STRING *os = NULL;
/* Get original receipt request */
/* Get original receipt request details */
if (CMS_get1_ReceiptRequest(si, &rr) <= 0) {
CMSerror(CMS_R_NO_RECEIPT_REQUEST);
goto err;
}
/* Get original content type */
ctype = CMS_signed_get0_data_by_OBJ(si,
OBJ_nid2obj(NID_pkcs9_contentType), -3, V_ASN1_OBJECT);
if (!ctype) {
CMSerror(CMS_R_NO_CONTENT_TYPE);
goto err;
}
rct.version = 1;
rct.contentType = ctype;
rct.signedContentIdentifier = rr->signedContentIdentifier;
rct.originatorSignatureValue = si->signature;
os = ASN1_item_pack(&rct, &CMS_Receipt_it, NULL);
err:
CMS_ReceiptRequest_free(rr);
return os;
}

176
crypto/cms/cms_io.c Normal file
View File

@@ -0,0 +1,176 @@
/* $OpenBSD: cms_io.c,v 1.20 2023/07/08 08:26:26 beck Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/asn1t.h>
#include <openssl/cms.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include "asn1_local.h"
#include "cms_local.h"
int
CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms)
{
ASN1_OCTET_STRING **pos;
if ((pos = CMS_get0_content(cms)) == NULL)
return 0;
if (*pos == NULL)
*pos = ASN1_OCTET_STRING_new();
if (*pos == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
(*pos)->flags |= ASN1_STRING_FLAG_NDEF;
(*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
*boundary = &(*pos)->data;
return 1;
}
LCRYPTO_ALIAS(CMS_stream);
CMS_ContentInfo *
d2i_CMS_bio(BIO *bp, CMS_ContentInfo **cms)
{
return ASN1_item_d2i_bio(&CMS_ContentInfo_it, bp, cms);
}
LCRYPTO_ALIAS(d2i_CMS_bio);
int
i2d_CMS_bio(BIO *bp, CMS_ContentInfo *cms)
{
return ASN1_item_i2d_bio(&CMS_ContentInfo_it, bp, cms);
}
LCRYPTO_ALIAS(i2d_CMS_bio);
CMS_ContentInfo *
PEM_read_bio_CMS(BIO *bp, CMS_ContentInfo **x, pem_password_cb *cb, void *u)
{
return PEM_ASN1_read_bio((d2i_of_void *)d2i_CMS_ContentInfo,
PEM_STRING_CMS, bp, (void **)x, cb, u);
}
CMS_ContentInfo *
PEM_read_CMS(FILE *fp, CMS_ContentInfo **x, pem_password_cb *cb, void *u)
{
return PEM_ASN1_read((d2i_of_void *)d2i_CMS_ContentInfo,
PEM_STRING_CMS, fp, (void **)x, cb, u);
}
int
PEM_write_bio_CMS(BIO *bp, const CMS_ContentInfo *x)
{
return PEM_ASN1_write_bio((i2d_of_void *)i2d_CMS_ContentInfo,
PEM_STRING_CMS, bp, (void *)x, NULL, NULL, 0, NULL, NULL);
}
int
PEM_write_CMS(FILE *fp, const CMS_ContentInfo *x)
{
return PEM_ASN1_write((i2d_of_void *)i2d_CMS_ContentInfo,
PEM_STRING_CMS, fp, (void *)x, NULL, NULL, 0, NULL, NULL);
}
BIO *
BIO_new_CMS(BIO *out, CMS_ContentInfo *cms)
{
return BIO_new_NDEF(out, (ASN1_VALUE *)cms, &CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(BIO_new_CMS);
/* CMS wrappers round generalised stream and MIME routines */
int
i2d_CMS_bio_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags)
{
return i2d_ASN1_bio_stream(out, (ASN1_VALUE *)cms, in, flags,
&CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(i2d_CMS_bio_stream);
int
PEM_write_bio_CMS_stream(BIO *out, CMS_ContentInfo *cms, BIO *in, int flags)
{
return PEM_write_bio_ASN1_stream(out, (ASN1_VALUE *)cms, in, flags,
"CMS", &CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(PEM_write_bio_CMS_stream);
int
SMIME_write_CMS(BIO *bio, CMS_ContentInfo *cms, BIO *data, int flags)
{
STACK_OF(X509_ALGOR) *mdalgs = NULL;
int ctype_nid = OBJ_obj2nid(cms->contentType);
int econt_nid = OBJ_obj2nid(CMS_get0_eContentType(cms));
if (ctype_nid == NID_pkcs7_signed)
mdalgs = cms->d.signedData->digestAlgorithms;
return SMIME_write_ASN1(bio, (ASN1_VALUE *)cms, data, flags, ctype_nid,
econt_nid, mdalgs, &CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(SMIME_write_CMS);
CMS_ContentInfo *
SMIME_read_CMS(BIO *bio, BIO **bcont)
{
return (CMS_ContentInfo *)SMIME_read_ASN1(bio, bcont,
&CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(SMIME_read_CMS);

492
crypto/cms/cms_kari.c Normal file
View File

@@ -0,0 +1,492 @@
/* $OpenBSD: cms_kari.c,v 1.15 2023/07/08 08:26:26 beck Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2013 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <string.h>
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
#include <openssl/aes.h>
#include "cms_local.h"
#include "asn1/asn1_local.h"
/* Key Agreement Recipient Info (KARI) routines */
int
CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri, X509_ALGOR **palg,
ASN1_OCTET_STRING **pukm)
{
if (ri->type != CMS_RECIPINFO_AGREE) {
CMSerror(CMS_R_NOT_KEY_AGREEMENT);
return 0;
}
if (palg)
*palg = ri->d.kari->keyEncryptionAlgorithm;
if (pukm)
*pukm = ri->d.kari->ukm;
return 1;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kari_get0_alg);
/* Retrieve recipient encrypted keys from a kari */
STACK_OF(CMS_RecipientEncryptedKey) *
CMS_RecipientInfo_kari_get0_reks(CMS_RecipientInfo *ri)
{
if (ri->type != CMS_RECIPINFO_AGREE) {
CMSerror(CMS_R_NOT_KEY_AGREEMENT);
return NULL;
}
return ri->d.kari->recipientEncryptedKeys;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kari_get0_reks);
int
CMS_RecipientInfo_kari_get0_orig_id(CMS_RecipientInfo *ri, X509_ALGOR **pubalg,
ASN1_BIT_STRING **pubkey, ASN1_OCTET_STRING **keyid, X509_NAME **issuer,
ASN1_INTEGER **sno)
{
CMS_OriginatorIdentifierOrKey *oik;
if (ri->type != CMS_RECIPINFO_AGREE) {
CMSerror(CMS_R_NOT_KEY_AGREEMENT);
return 0;
}
oik = ri->d.kari->originator;
if (issuer)
*issuer = NULL;
if (sno)
*sno = NULL;
if (keyid)
*keyid = NULL;
if (pubalg)
*pubalg = NULL;
if (pubkey)
*pubkey = NULL;
if (oik->type == CMS_OIK_ISSUER_SERIAL) {
if (issuer)
*issuer = oik->d.issuerAndSerialNumber->issuer;
if (sno)
*sno = oik->d.issuerAndSerialNumber->serialNumber;
} else if (oik->type == CMS_OIK_KEYIDENTIFIER) {
if (keyid)
*keyid = oik->d.subjectKeyIdentifier;
} else if (oik->type == CMS_OIK_PUBKEY) {
if (pubalg)
*pubalg = oik->d.originatorKey->algorithm;
if (pubkey)
*pubkey = oik->d.originatorKey->publicKey;
} else
return 0;
return 1;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kari_get0_orig_id);
int
CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo *ri, X509 *cert)
{
CMS_OriginatorIdentifierOrKey *oik;
if (ri->type != CMS_RECIPINFO_AGREE) {
CMSerror(CMS_R_NOT_KEY_AGREEMENT);
return -2;
}
oik = ri->d.kari->originator;
if (oik->type == CMS_OIK_ISSUER_SERIAL)
return cms_ias_cert_cmp(oik->d.issuerAndSerialNumber, cert);
else if (oik->type == CMS_OIK_KEYIDENTIFIER)
return cms_keyid_cert_cmp(oik->d.subjectKeyIdentifier, cert);
return -1;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kari_orig_id_cmp);
int
CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek,
ASN1_OCTET_STRING **keyid, ASN1_GENERALIZEDTIME **tm,
CMS_OtherKeyAttribute **other, X509_NAME **issuer, ASN1_INTEGER **sno)
{
CMS_KeyAgreeRecipientIdentifier *rid = rek->rid;
if (rid->type == CMS_REK_ISSUER_SERIAL) {
if (issuer)
*issuer = rid->d.issuerAndSerialNumber->issuer;
if (sno)
*sno = rid->d.issuerAndSerialNumber->serialNumber;
if (keyid)
*keyid = NULL;
if (tm)
*tm = NULL;
if (other)
*other = NULL;
} else if (rid->type == CMS_REK_KEYIDENTIFIER) {
if (keyid)
*keyid = rid->d.rKeyId->subjectKeyIdentifier;
if (tm)
*tm = rid->d.rKeyId->date;
if (other)
*other = rid->d.rKeyId->other;
if (issuer)
*issuer = NULL;
if (sno)
*sno = NULL;
} else
return 0;
return 1;
}
LCRYPTO_ALIAS(CMS_RecipientEncryptedKey_get0_id);
int
CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek, X509 *cert)
{
CMS_KeyAgreeRecipientIdentifier *rid = rek->rid;
if (rid->type == CMS_REK_ISSUER_SERIAL)
return cms_ias_cert_cmp(rid->d.issuerAndSerialNumber, cert);
else if (rid->type == CMS_REK_KEYIDENTIFIER)
return cms_keyid_cert_cmp(rid->d.rKeyId->subjectKeyIdentifier, cert);
else
return -1;
}
LCRYPTO_ALIAS(CMS_RecipientEncryptedKey_cert_cmp);
int
CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
{
EVP_PKEY_CTX *pctx;
CMS_KeyAgreeRecipientInfo *kari = ri->d.kari;
EVP_PKEY_CTX_free(kari->pctx);
kari->pctx = NULL;
if (!pk)
return 1;
pctx = EVP_PKEY_CTX_new(pk, NULL);
if (!pctx || !EVP_PKEY_derive_init(pctx))
goto err;
kari->pctx = pctx;
return 1;
err:
EVP_PKEY_CTX_free(pctx);
return 0;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kari_set0_pkey);
EVP_CIPHER_CTX *
CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri)
{
if (ri->type == CMS_RECIPINFO_AGREE)
return ri->d.kari->ctx;
return NULL;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kari_get0_ctx);
/*
* Derive KEK and decrypt/encrypt with it to produce either the original CEK
* or the encrypted CEK.
*/
static int
cms_kek_cipher(unsigned char **pout, size_t *poutlen, const unsigned char *in,
size_t inlen, CMS_KeyAgreeRecipientInfo *kari, int enc)
{
/* Key encryption key */
unsigned char kek[EVP_MAX_KEY_LENGTH];
size_t keklen;
int rv = 0;
unsigned char *out = NULL;
int outlen;
keklen = EVP_CIPHER_CTX_key_length(kari->ctx);
if (keklen > EVP_MAX_KEY_LENGTH)
return 0;
/* Derive KEK */
if (EVP_PKEY_derive(kari->pctx, kek, &keklen) <= 0)
goto err;
/* Set KEK in context */
if (!EVP_CipherInit_ex(kari->ctx, NULL, NULL, kek, NULL, enc))
goto err;
/* obtain output length of ciphered key */
if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen))
goto err;
out = malloc(outlen);
if (out == NULL)
goto err;
if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, inlen))
goto err;
*pout = out;
*poutlen = (size_t)outlen;
rv = 1;
err:
explicit_bzero(kek, keklen);
if (!rv)
free(out);
EVP_CIPHER_CTX_reset(kari->ctx);
/* FIXME: WHY IS kari->pctx freed here? /RL */
EVP_PKEY_CTX_free(kari->pctx);
kari->pctx = NULL;
return rv;
}
int
CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
CMS_RecipientEncryptedKey *rek)
{
int rv = 0;
unsigned char *enckey = NULL, *cek = NULL;
size_t enckeylen;
size_t ceklen;
CMS_EncryptedContentInfo *ec;
enckeylen = rek->encryptedKey->length;
enckey = rek->encryptedKey->data;
/* Setup all parameters to derive KEK */
if (!cms_env_asn1_ctrl(ri, 1))
goto err;
/* Attempt to decrypt CEK */
if (!cms_kek_cipher(&cek, &ceklen, enckey, enckeylen, ri->d.kari, 0))
goto err;
ec = cms->d.envelopedData->encryptedContentInfo;
freezero(ec->key, ec->keylen);
ec->key = cek;
ec->keylen = ceklen;
cek = NULL;
rv = 1;
err:
free(cek);
return rv;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_kari_decrypt);
/* Create ephemeral key and initialise context based on it */
static int
cms_kari_create_ephemeral_key(CMS_KeyAgreeRecipientInfo *kari, EVP_PKEY *pk)
{
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *ekey = NULL;
int rv = 0;
pctx = EVP_PKEY_CTX_new(pk, NULL);
if (!pctx)
goto err;
if (EVP_PKEY_keygen_init(pctx) <= 0)
goto err;
if (EVP_PKEY_keygen(pctx, &ekey) <= 0)
goto err;
EVP_PKEY_CTX_free(pctx);
pctx = EVP_PKEY_CTX_new(ekey, NULL);
if (!pctx)
goto err;
if (EVP_PKEY_derive_init(pctx) <= 0)
goto err;
kari->pctx = pctx;
rv = 1;
err:
if (!rv)
EVP_PKEY_CTX_free(pctx);
EVP_PKEY_free(ekey);
return rv;
}
/* Initialise a kari based on passed certificate and key */
int
cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip, EVP_PKEY *pk,
unsigned int flags)
{
CMS_KeyAgreeRecipientInfo *kari;
CMS_RecipientEncryptedKey *rek = NULL;
ri->d.kari = (CMS_KeyAgreeRecipientInfo *)ASN1_item_new(&CMS_KeyAgreeRecipientInfo_it);
if (!ri->d.kari)
return 0;
ri->type = CMS_RECIPINFO_AGREE;
kari = ri->d.kari;
kari->version = 3;
rek = (CMS_RecipientEncryptedKey *)ASN1_item_new(&CMS_RecipientEncryptedKey_it);
if (rek == NULL)
return 0;
if (!sk_CMS_RecipientEncryptedKey_push(kari->recipientEncryptedKeys, rek)) {
ASN1_item_free((ASN1_VALUE *)rek, &CMS_RecipientEncryptedKey_it);
return 0;
}
if (flags & CMS_USE_KEYID) {
rek->rid->type = CMS_REK_KEYIDENTIFIER;
rek->rid->d.rKeyId = (CMS_RecipientKeyIdentifier *)ASN1_item_new(&CMS_RecipientKeyIdentifier_it);
if (rek->rid->d.rKeyId == NULL)
return 0;
if (!cms_set1_keyid(&rek->rid->d.rKeyId->subjectKeyIdentifier, recip))
return 0;
} else {
rek->rid->type = CMS_REK_ISSUER_SERIAL;
if (!cms_set1_ias(&rek->rid->d.issuerAndSerialNumber, recip))
return 0;
}
/* Create ephemeral key */
if (!cms_kari_create_ephemeral_key(kari, pk))
return 0;
EVP_PKEY_up_ref(pk);
rek->pkey = pk;
return 1;
}
static int
cms_wrap_init(CMS_KeyAgreeRecipientInfo *kari, const EVP_CIPHER *cipher)
{
EVP_CIPHER_CTX *ctx = kari->ctx;
const EVP_CIPHER *kekcipher;
int keylen = EVP_CIPHER_key_length(cipher);
/* If a suitable wrap algorithm is already set nothing to do */
kekcipher = EVP_CIPHER_CTX_cipher(ctx);
if (kekcipher) {
if (EVP_CIPHER_CTX_mode(ctx) != EVP_CIPH_WRAP_MODE)
return 0;
return 1;
}
/*
* Pick a cipher based on content encryption cipher. If it is DES3 use
* DES3 wrap otherwise use AES wrap similar to key size.
*/
#ifndef OPENSSL_NO_DES
#if 0
/*
* XXX - we do not currently support DES3 wrap and probably should just
* drop this code.
*/
if (EVP_CIPHER_type(cipher) == NID_des_ede3_cbc)
kekcipher = EVP_des_ede3_wrap();
else
#endif
#endif
if (keylen <= 16)
kekcipher = EVP_aes_128_wrap();
else if (keylen <= 24)
kekcipher = EVP_aes_192_wrap();
else
kekcipher = EVP_aes_256_wrap();
return EVP_EncryptInit_ex(ctx, kekcipher, NULL, NULL, NULL);
}
/* Encrypt content key in key agreement recipient info */
int
cms_RecipientInfo_kari_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
{
CMS_KeyAgreeRecipientInfo *kari;
CMS_EncryptedContentInfo *ec;
CMS_RecipientEncryptedKey *rek;
STACK_OF(CMS_RecipientEncryptedKey) *reks;
int i;
if (ri->type != CMS_RECIPINFO_AGREE) {
CMSerror(CMS_R_NOT_KEY_AGREEMENT);
return 0;
}
kari = ri->d.kari;
reks = kari->recipientEncryptedKeys;
ec = cms->d.envelopedData->encryptedContentInfo;
/* Initialise wrap algorithm parameters */
if (!cms_wrap_init(kari, ec->cipher))
return 0;
/*
* If no originator key set up initialise for ephemeral key the public key
* ASN1 structure will set the actual public key value.
*/
if (kari->originator->type == -1) {
CMS_OriginatorIdentifierOrKey *oik = kari->originator;
oik->type = CMS_OIK_PUBKEY;
oik->d.originatorKey = (CMS_OriginatorPublicKey *)ASN1_item_new(&CMS_OriginatorPublicKey_it);
if (!oik->d.originatorKey)
return 0;
}
/* Initialise KDF algorithm */
if (!cms_env_asn1_ctrl(ri, 0))
return 0;
/* For each rek, derive KEK, encrypt CEK */
for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) {
unsigned char *enckey;
size_t enckeylen;
rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
if (EVP_PKEY_derive_set_peer(kari->pctx, rek->pkey) <= 0)
return 0;
if (!cms_kek_cipher(&enckey, &enckeylen, ec->key, ec->keylen,
kari, 1))
return 0;
ASN1_STRING_set0(rek->encryptedKey, enckey, enckeylen);
}
return 1;
}

776
crypto/cms/cms_lib.c Normal file
View File

@@ -0,0 +1,776 @@
/* $OpenBSD: cms_lib.c,v 1.24 2023/08/24 04:56:36 tb Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/asn1.h>
#include <openssl/cms.h>
#include "cms_local.h"
#include "x509_local.h"
CMS_ContentInfo *
d2i_CMS_ContentInfo(CMS_ContentInfo **a, const unsigned char **in, long len)
{
return (CMS_ContentInfo *)ASN1_item_d2i((ASN1_VALUE **)a, in, len,
&CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(d2i_CMS_ContentInfo);
int
i2d_CMS_ContentInfo(CMS_ContentInfo *a, unsigned char **out)
{
return ASN1_item_i2d((ASN1_VALUE *)a, out, &CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(i2d_CMS_ContentInfo);
CMS_ContentInfo *
CMS_ContentInfo_new(void)
{
return (CMS_ContentInfo *)ASN1_item_new(&CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(CMS_ContentInfo_new);
void
CMS_ContentInfo_free(CMS_ContentInfo *a)
{
ASN1_item_free((ASN1_VALUE *)a, &CMS_ContentInfo_it);
}
LCRYPTO_ALIAS(CMS_ContentInfo_free);
int
CMS_ContentInfo_print_ctx(BIO *out, CMS_ContentInfo *x, int indent, const ASN1_PCTX *pctx)
{
return ASN1_item_print(out, (ASN1_VALUE *)x, indent,
&CMS_ContentInfo_it, pctx);
}
LCRYPTO_ALIAS(CMS_ContentInfo_print_ctx);
const ASN1_OBJECT *
CMS_get0_type(const CMS_ContentInfo *cms)
{
return cms->contentType;
}
LCRYPTO_ALIAS(CMS_get0_type);
CMS_ContentInfo *
cms_Data_create(void)
{
CMS_ContentInfo *cms;
cms = CMS_ContentInfo_new();
if (cms != NULL) {
cms->contentType = OBJ_nid2obj(NID_pkcs7_data);
/* Never detached */
CMS_set_detached(cms, 0);
}
return cms;
}
static BIO *
cms_content_bio(CMS_ContentInfo *cms)
{
ASN1_OCTET_STRING **pos;
if ((pos = CMS_get0_content(cms)) == NULL)
return NULL;
/* If content is detached, data goes nowhere: create null BIO. */
if (*pos == NULL)
return BIO_new(BIO_s_null());
/* If content is not detached and was created, return memory BIO. */
if ((*pos)->flags == ASN1_STRING_FLAG_CONT)
return BIO_new(BIO_s_mem());
/* Else content was read in: return read-only BIO for it. */
return BIO_new_mem_buf((*pos)->data, (*pos)->length);
}
BIO *
CMS_dataInit(CMS_ContentInfo *cms, BIO *in_content_bio)
{
BIO *cms_bio = NULL, *content_bio = NULL;
if ((content_bio = in_content_bio) == NULL)
content_bio = cms_content_bio(cms);
if (content_bio == NULL) {
CMSerror(CMS_R_NO_CONTENT);
goto err;
}
switch (OBJ_obj2nid(cms->contentType)) {
case NID_pkcs7_data:
return content_bio;
case NID_pkcs7_signed:
if ((cms_bio = cms_SignedData_init_bio(cms)) == NULL)
goto err;
break;
case NID_pkcs7_digest:
if ((cms_bio = cms_DigestedData_init_bio(cms)) == NULL)
goto err;
break;
case NID_pkcs7_encrypted:
if ((cms_bio = cms_EncryptedData_init_bio(cms)) == NULL)
goto err;
break;
case NID_pkcs7_enveloped:
if ((cms_bio = cms_EnvelopedData_init_bio(cms)) == NULL)
goto err;
break;
default:
CMSerror(CMS_R_UNSUPPORTED_TYPE);
goto err;
}
return BIO_push(cms_bio, content_bio);
err:
if (content_bio != in_content_bio)
BIO_free(content_bio);
return NULL;
}
LCRYPTO_ALIAS(CMS_dataInit);
int
CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
{
ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
if (!pos)
return 0;
/* If embedded content find memory BIO and set content */
if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT)) {
BIO *mbio;
unsigned char *cont;
long contlen;
mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM);
if (!mbio) {
CMSerror(CMS_R_CONTENT_NOT_FOUND);
return 0;
}
contlen = BIO_get_mem_data(mbio, &cont);
/* Set bio as read only so its content can't be clobbered */
BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY);
BIO_set_mem_eof_return(mbio, 0);
ASN1_STRING_set0(*pos, cont, contlen);
(*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
}
switch (OBJ_obj2nid(cms->contentType)) {
case NID_pkcs7_data:
case NID_pkcs7_enveloped:
case NID_pkcs7_encrypted:
case NID_id_smime_ct_compressedData:
/* Nothing to do */
return 1;
case NID_pkcs7_signed:
return cms_SignedData_final(cms, cmsbio);
case NID_pkcs7_digest:
return cms_DigestedData_do_final(cms, cmsbio, 0);
default:
CMSerror(CMS_R_UNSUPPORTED_TYPE);
return 0;
}
}
LCRYPTO_ALIAS(CMS_dataFinal);
int
CMS_get_version(const CMS_ContentInfo *cms, long *version)
{
switch (OBJ_obj2nid(cms->contentType)) {
case NID_pkcs7_signed:
*version = cms->d.signedData->version;
return 1;
case NID_pkcs7_enveloped:
*version = cms->d.envelopedData->version;
return 1;
case NID_pkcs7_digest:
*version = cms->d.digestedData->version;
return 1;
case NID_pkcs7_encrypted:
*version = cms->d.encryptedData->version;
return 1;
case NID_id_smime_ct_authData:
*version = cms->d.authenticatedData->version;
return 1;
case NID_id_smime_ct_compressedData:
*version = cms->d.compressedData->version;
return 1;
default:
CMSerror(CMS_R_UNSUPPORTED_TYPE);
return 0;
}
}
LCRYPTO_ALIAS(CMS_get_version);
int
CMS_SignerInfo_get_version(const CMS_SignerInfo *si, long *version)
{
*version = si->version;
return 1;
}
LCRYPTO_ALIAS(CMS_SignerInfo_get_version);
/*
* Return an OCTET STRING pointer to content. This allows it to be accessed
* or set later.
*/
ASN1_OCTET_STRING **
CMS_get0_content(CMS_ContentInfo *cms)
{
switch (OBJ_obj2nid(cms->contentType)) {
case NID_pkcs7_data:
return &cms->d.data;
case NID_pkcs7_signed:
return &cms->d.signedData->encapContentInfo->eContent;
case NID_pkcs7_enveloped:
return &cms->d.envelopedData->encryptedContentInfo->encryptedContent;
case NID_pkcs7_digest:
return &cms->d.digestedData->encapContentInfo->eContent;
case NID_pkcs7_encrypted:
return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
case NID_id_smime_ct_authData:
return &cms->d.authenticatedData->encapContentInfo->eContent;
case NID_id_smime_ct_compressedData:
return &cms->d.compressedData->encapContentInfo->eContent;
default:
if (cms->d.other->type == V_ASN1_OCTET_STRING)
return &cms->d.other->value.octet_string;
CMSerror(CMS_R_UNSUPPORTED_CONTENT_TYPE);
return NULL;
}
}
/*
* Return an ASN1_OBJECT pointer to content type. This allows it to be
* accessed or set later.
*/
static ASN1_OBJECT **
cms_get0_econtent_type(CMS_ContentInfo *cms)
{
switch (OBJ_obj2nid(cms->contentType)) {
case NID_pkcs7_signed:
return &cms->d.signedData->encapContentInfo->eContentType;
case NID_pkcs7_enveloped:
return &cms->d.envelopedData->encryptedContentInfo->contentType;
case NID_pkcs7_digest:
return &cms->d.digestedData->encapContentInfo->eContentType;
case NID_pkcs7_encrypted:
return &cms->d.encryptedData->encryptedContentInfo->contentType;
case NID_id_smime_ct_authData:
return &cms->d.authenticatedData->encapContentInfo->eContentType;
case NID_id_smime_ct_compressedData:
return &cms->d.compressedData->encapContentInfo->eContentType;
default:
CMSerror(CMS_R_UNSUPPORTED_CONTENT_TYPE);
return NULL;
}
}
const ASN1_OBJECT *
CMS_get0_eContentType(CMS_ContentInfo *cms)
{
ASN1_OBJECT **petype;
petype = cms_get0_econtent_type(cms);
if (petype)
return *petype;
return NULL;
}
LCRYPTO_ALIAS(CMS_get0_eContentType);
int
CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid)
{
ASN1_OBJECT **petype, *etype;
petype = cms_get0_econtent_type(cms);
if (!petype)
return 0;
if (!oid)
return 1;
etype = OBJ_dup(oid);
if (!etype)
return 0;
ASN1_OBJECT_free(*petype);
*petype = etype;
return 1;
}
LCRYPTO_ALIAS(CMS_set1_eContentType);
int
CMS_is_detached(CMS_ContentInfo *cms)
{
ASN1_OCTET_STRING **pos;
pos = CMS_get0_content(cms);
if (!pos)
return -1;
if (*pos)
return 0;
return 1;
}
LCRYPTO_ALIAS(CMS_is_detached);
int
CMS_set_detached(CMS_ContentInfo *cms, int detached)
{
ASN1_OCTET_STRING **pos;
pos = CMS_get0_content(cms);
if (!pos)
return 0;
if (detached) {
ASN1_OCTET_STRING_free(*pos);
*pos = NULL;
return 1;
}
if (*pos == NULL)
*pos = ASN1_OCTET_STRING_new();
if (*pos != NULL) {
/*
* NB: special flag to show content is created and not read in.
*/
(*pos)->flags |= ASN1_STRING_FLAG_CONT;
return 1;
}
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
LCRYPTO_ALIAS(CMS_set_detached);
/* Create a digest BIO from an X509_ALGOR structure */
BIO *
cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
{
BIO *mdbio = NULL;
const ASN1_OBJECT *digestoid;
const EVP_MD *digest;
X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
digest = EVP_get_digestbyobj(digestoid);
if (!digest) {
CMSerror(CMS_R_UNKNOWN_DIGEST_ALGORITHM);
goto err;
}
mdbio = BIO_new(BIO_f_md());
if (mdbio == NULL || !BIO_set_md(mdbio, digest)) {
CMSerror(CMS_R_MD_BIO_INIT_ERROR);
goto err;
}
return mdbio;
err:
BIO_free(mdbio);
return NULL;
}
/* Locate a message digest content from a BIO chain based on SignerInfo */
int
cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain, X509_ALGOR *mdalg)
{
int nid;
const ASN1_OBJECT *mdoid;
X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
nid = OBJ_obj2nid(mdoid);
/* Look for digest type to match signature */
for (;;) {
EVP_MD_CTX *mtmp;
chain = BIO_find_type(chain, BIO_TYPE_MD);
if (chain == NULL) {
CMSerror(CMS_R_NO_MATCHING_DIGEST);
return 0;
}
BIO_get_md_ctx(chain, &mtmp);
if (EVP_MD_CTX_type(mtmp) == nid
/*
* Workaround for broken implementations that use signature
* algorithm OID instead of digest.
*/
|| EVP_MD_pkey_type(EVP_MD_CTX_md(mtmp)) == nid)
return EVP_MD_CTX_copy_ex(mctx, mtmp);
chain = BIO_next(chain);
}
}
static STACK_OF(CMS_CertificateChoices) **
cms_get0_certificate_choices(CMS_ContentInfo *cms)
{
switch (OBJ_obj2nid(cms->contentType)) {
case NID_pkcs7_signed:
return &cms->d.signedData->certificates;
case NID_pkcs7_enveloped:
if (cms->d.envelopedData->originatorInfo == NULL)
return NULL;
return &cms->d.envelopedData->originatorInfo->certificates;
default:
CMSerror(CMS_R_UNSUPPORTED_CONTENT_TYPE);
return NULL;
}
}
CMS_CertificateChoices *
CMS_add0_CertificateChoices(CMS_ContentInfo *cms)
{
STACK_OF(CMS_CertificateChoices) **pcerts;
CMS_CertificateChoices *cch;
pcerts = cms_get0_certificate_choices(cms);
if (!pcerts)
return NULL;
if (!*pcerts)
*pcerts = sk_CMS_CertificateChoices_new_null();
if (!*pcerts)
return NULL;
cch = (CMS_CertificateChoices *)ASN1_item_new(&CMS_CertificateChoices_it);
if (!cch)
return NULL;
if (!sk_CMS_CertificateChoices_push(*pcerts, cch)) {
ASN1_item_free((ASN1_VALUE *)cch, &CMS_CertificateChoices_it);
return NULL;
}
return cch;
}
LCRYPTO_ALIAS(CMS_add0_CertificateChoices);
int
CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
{
CMS_CertificateChoices *cch;
STACK_OF(CMS_CertificateChoices) **pcerts;
int i;
pcerts = cms_get0_certificate_choices(cms);
if (!pcerts)
return 0;
for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
cch = sk_CMS_CertificateChoices_value(*pcerts, i);
if (cch->type == CMS_CERTCHOICE_CERT) {
if (!X509_cmp(cch->d.certificate, cert)) {
CMSerror(CMS_R_CERTIFICATE_ALREADY_PRESENT);
return 0;
}
}
}
cch = CMS_add0_CertificateChoices(cms);
if (!cch)
return 0;
cch->type = CMS_CERTCHOICE_CERT;
cch->d.certificate = cert;
return 1;
}
LCRYPTO_ALIAS(CMS_add0_cert);
int
CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
{
int r;
r = CMS_add0_cert(cms, cert);
if (r > 0)
X509_up_ref(cert);
return r;
}
LCRYPTO_ALIAS(CMS_add1_cert);
static STACK_OF(CMS_RevocationInfoChoice) **
cms_get0_revocation_choices(CMS_ContentInfo *cms)
{
switch (OBJ_obj2nid(cms->contentType)) {
case NID_pkcs7_signed:
return &cms->d.signedData->crls;
case NID_pkcs7_enveloped:
if (cms->d.envelopedData->originatorInfo == NULL)
return NULL;
return &cms->d.envelopedData->originatorInfo->crls;
default:
CMSerror(CMS_R_UNSUPPORTED_CONTENT_TYPE);
return NULL;
}
}
CMS_RevocationInfoChoice *
CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)
{
STACK_OF(CMS_RevocationInfoChoice) **pcrls;
CMS_RevocationInfoChoice *rch;
pcrls = cms_get0_revocation_choices(cms);
if (!pcrls)
return NULL;
if (!*pcrls)
*pcrls = sk_CMS_RevocationInfoChoice_new_null();
if (!*pcrls)
return NULL;
rch = (CMS_RevocationInfoChoice *)ASN1_item_new(&CMS_RevocationInfoChoice_it);
if (!rch)
return NULL;
if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch)) {
ASN1_item_free((ASN1_VALUE *)rch, &CMS_RevocationInfoChoice_it);
return NULL;
}
return rch;
}
LCRYPTO_ALIAS(CMS_add0_RevocationInfoChoice);
int
CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
{
CMS_RevocationInfoChoice *rch;
rch = CMS_add0_RevocationInfoChoice(cms);
if (!rch)
return 0;
rch->type = CMS_REVCHOICE_CRL;
rch->d.crl = crl;
return 1;
}
LCRYPTO_ALIAS(CMS_add0_crl);
int
CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl)
{
int r;
r = CMS_add0_crl(cms, crl);
if (r > 0)
X509_CRL_up_ref(crl);
return r;
}
LCRYPTO_ALIAS(CMS_add1_crl);
STACK_OF(X509) *
CMS_get1_certs(CMS_ContentInfo *cms)
{
STACK_OF(X509) *certs = NULL;
CMS_CertificateChoices *cch;
STACK_OF(CMS_CertificateChoices) **pcerts;
int i;
pcerts = cms_get0_certificate_choices(cms);
if (!pcerts)
return NULL;
for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
cch = sk_CMS_CertificateChoices_value(*pcerts, i);
if (cch->type == 0) {
if (!certs) {
certs = sk_X509_new_null();
if (!certs)
return NULL;
}
if (!sk_X509_push(certs, cch->d.certificate)) {
sk_X509_pop_free(certs, X509_free);
return NULL;
}
X509_up_ref(cch->d.certificate);
}
}
return certs;
}
LCRYPTO_ALIAS(CMS_get1_certs);
STACK_OF(X509_CRL) *
CMS_get1_crls(CMS_ContentInfo *cms)
{
STACK_OF(X509_CRL) *crls = NULL;
STACK_OF(CMS_RevocationInfoChoice) **pcrls;
CMS_RevocationInfoChoice *rch;
int i;
pcrls = cms_get0_revocation_choices(cms);
if (!pcrls)
return NULL;
for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++) {
rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
if (rch->type == 0) {
if (!crls) {
crls = sk_X509_CRL_new_null();
if (!crls)
return NULL;
}
if (!sk_X509_CRL_push(crls, rch->d.crl)) {
sk_X509_CRL_pop_free(crls, X509_CRL_free);
return NULL;
}
X509_CRL_up_ref(rch->d.crl);
}
}
return crls;
}
LCRYPTO_ALIAS(CMS_get1_crls);
static const ASN1_OCTET_STRING *
cms_X509_get0_subject_key_id(X509 *x)
{
/* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(x, -1, -1);
return x->skid;
}
int
cms_ias_cert_cmp(CMS_IssuerAndSerialNumber *ias, X509 *cert)
{
int ret;
ret = X509_NAME_cmp(ias->issuer, X509_get_issuer_name(cert));
if (ret)
return ret;
return ASN1_INTEGER_cmp(ias->serialNumber, X509_get_serialNumber(cert));
}
int
cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert)
{
const ASN1_OCTET_STRING *cert_keyid = cms_X509_get0_subject_key_id(cert);
if (cert_keyid == NULL)
return -1;
return ASN1_OCTET_STRING_cmp(keyid, cert_keyid);
}
int
cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert)
{
CMS_IssuerAndSerialNumber *ias;
ias = (CMS_IssuerAndSerialNumber *)ASN1_item_new(&CMS_IssuerAndSerialNumber_it);
if (!ias)
goto err;
if (!X509_NAME_set(&ias->issuer, X509_get_issuer_name(cert)))
goto err;
if (!ASN1_STRING_copy(ias->serialNumber, X509_get_serialNumber(cert)))
goto err;
ASN1_item_free((ASN1_VALUE *)*pias, &CMS_IssuerAndSerialNumber_it);
*pias = ias;
return 1;
err:
ASN1_item_free((ASN1_VALUE *)ias, &CMS_IssuerAndSerialNumber_it);
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
int
cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert)
{
ASN1_OCTET_STRING *keyid = NULL;
const ASN1_OCTET_STRING *cert_keyid;
cert_keyid = cms_X509_get0_subject_key_id(cert);
if (cert_keyid == NULL) {
CMSerror(CMS_R_CERTIFICATE_HAS_NO_KEYID);
return 0;
}
keyid = ASN1_STRING_dup(cert_keyid);
if (!keyid) {
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
ASN1_OCTET_STRING_free(*pkeyid);
*pkeyid = keyid;
return 1;
}

477
crypto/cms/cms_local.h Normal file
View File

@@ -0,0 +1,477 @@
/* $OpenBSD: cms_local.h,v 1.5 2023/08/24 04:56:36 tb Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#ifndef HEADER_CMS_LOCAL_H
#define HEADER_CMS_LOCAL_H
#include <openssl/x509.h>
/*
* Cryptographic message syntax (CMS) structures: taken from RFC3852
*/
/* Forward references */
typedef struct CMS_IssuerAndSerialNumber_st CMS_IssuerAndSerialNumber;
typedef struct CMS_EncapsulatedContentInfo_st CMS_EncapsulatedContentInfo;
typedef struct CMS_SignerIdentifier_st CMS_SignerIdentifier;
typedef struct CMS_SignedData_st CMS_SignedData;
typedef struct CMS_OtherRevocationInfoFormat_st CMS_OtherRevocationInfoFormat;
typedef struct CMS_OriginatorInfo_st CMS_OriginatorInfo;
typedef struct CMS_EncryptedContentInfo_st CMS_EncryptedContentInfo;
typedef struct CMS_EnvelopedData_st CMS_EnvelopedData;
typedef struct CMS_DigestedData_st CMS_DigestedData;
typedef struct CMS_EncryptedData_st CMS_EncryptedData;
typedef struct CMS_AuthenticatedData_st CMS_AuthenticatedData;
typedef struct CMS_CompressedData_st CMS_CompressedData;
typedef struct CMS_OtherCertificateFormat_st CMS_OtherCertificateFormat;
typedef struct CMS_KeyTransRecipientInfo_st CMS_KeyTransRecipientInfo;
typedef struct CMS_OriginatorPublicKey_st CMS_OriginatorPublicKey;
typedef struct CMS_OriginatorIdentifierOrKey_st CMS_OriginatorIdentifierOrKey;
typedef struct CMS_KeyAgreeRecipientInfo_st CMS_KeyAgreeRecipientInfo;
typedef struct CMS_RecipientKeyIdentifier_st CMS_RecipientKeyIdentifier;
typedef struct CMS_KeyAgreeRecipientIdentifier_st
CMS_KeyAgreeRecipientIdentifier;
typedef struct CMS_KEKIdentifier_st CMS_KEKIdentifier;
typedef struct CMS_KEKRecipientInfo_st CMS_KEKRecipientInfo;
typedef struct CMS_PasswordRecipientInfo_st CMS_PasswordRecipientInfo;
typedef struct CMS_OtherRecipientInfo_st CMS_OtherRecipientInfo;
typedef struct CMS_ReceiptsFrom_st CMS_ReceiptsFrom;
struct CMS_ContentInfo_st {
ASN1_OBJECT *contentType;
union {
ASN1_OCTET_STRING *data;
CMS_SignedData *signedData;
CMS_EnvelopedData *envelopedData;
CMS_DigestedData *digestedData;
CMS_EncryptedData *encryptedData;
CMS_AuthenticatedData *authenticatedData;
CMS_CompressedData *compressedData;
ASN1_TYPE *other;
/* Other types ... */
void *otherData;
} d;
};
DECLARE_STACK_OF(CMS_CertificateChoices)
struct CMS_SignedData_st {
long version;
STACK_OF(X509_ALGOR) *digestAlgorithms;
CMS_EncapsulatedContentInfo *encapContentInfo;
STACK_OF(CMS_CertificateChoices) *certificates;
STACK_OF(CMS_RevocationInfoChoice) *crls;
STACK_OF(CMS_SignerInfo) *signerInfos;
};
struct CMS_EncapsulatedContentInfo_st {
ASN1_OBJECT *eContentType;
ASN1_OCTET_STRING *eContent;
/* Set to 1 if incomplete structure only part set up */
int partial;
};
struct CMS_SignerInfo_st {
long version;
CMS_SignerIdentifier *sid;
X509_ALGOR *digestAlgorithm;
STACK_OF(X509_ATTRIBUTE) *signedAttrs;
X509_ALGOR *signatureAlgorithm;
ASN1_OCTET_STRING *signature;
STACK_OF(X509_ATTRIBUTE) *unsignedAttrs;
/* Signing certificate and key */
X509 *signer;
EVP_PKEY *pkey;
/* Digest and public key context for alternative parameters */
EVP_MD_CTX *mctx;
EVP_PKEY_CTX *pctx;
};
struct CMS_SignerIdentifier_st {
int type;
union {
CMS_IssuerAndSerialNumber *issuerAndSerialNumber;
ASN1_OCTET_STRING *subjectKeyIdentifier;
} d;
};
struct CMS_EnvelopedData_st {
long version;
CMS_OriginatorInfo *originatorInfo;
STACK_OF(CMS_RecipientInfo) *recipientInfos;
CMS_EncryptedContentInfo *encryptedContentInfo;
STACK_OF(X509_ATTRIBUTE) *unprotectedAttrs;
};
struct CMS_OriginatorInfo_st {
STACK_OF(CMS_CertificateChoices) *certificates;
STACK_OF(CMS_RevocationInfoChoice) *crls;
};
struct CMS_EncryptedContentInfo_st {
ASN1_OBJECT *contentType;
X509_ALGOR *contentEncryptionAlgorithm;
ASN1_OCTET_STRING *encryptedContent;
/* Content encryption algorithm and key */
const EVP_CIPHER *cipher;
unsigned char *key;
size_t keylen;
/* Set to 1 if we are debugging decrypt and don't fake keys for MMA */
int debug;
/* Set to 1 if we have no cert and need extra safety measures for MMA */
int havenocert;
};
struct CMS_RecipientInfo_st {
int type;
union {
CMS_KeyTransRecipientInfo *ktri;
CMS_KeyAgreeRecipientInfo *kari;
CMS_KEKRecipientInfo *kekri;
CMS_PasswordRecipientInfo *pwri;
CMS_OtherRecipientInfo *ori;
} d;
};
typedef CMS_SignerIdentifier CMS_RecipientIdentifier;
struct CMS_KeyTransRecipientInfo_st {
long version;
CMS_RecipientIdentifier *rid;
X509_ALGOR *keyEncryptionAlgorithm;
ASN1_OCTET_STRING *encryptedKey;
/* Recipient Key and cert */
X509 *recip;
EVP_PKEY *pkey;
/* Public key context for this operation */
EVP_PKEY_CTX *pctx;
};
struct CMS_KeyAgreeRecipientInfo_st {
long version;
CMS_OriginatorIdentifierOrKey *originator;
ASN1_OCTET_STRING *ukm;
X509_ALGOR *keyEncryptionAlgorithm;
STACK_OF(CMS_RecipientEncryptedKey) *recipientEncryptedKeys;
/* Public key context associated with current operation */
EVP_PKEY_CTX *pctx;
/* Cipher context for CEK wrapping */
EVP_CIPHER_CTX *ctx;
};
struct CMS_OriginatorIdentifierOrKey_st {
int type;
union {
CMS_IssuerAndSerialNumber *issuerAndSerialNumber;
ASN1_OCTET_STRING *subjectKeyIdentifier;
CMS_OriginatorPublicKey *originatorKey;
} d;
};
struct CMS_OriginatorPublicKey_st {
X509_ALGOR *algorithm;
ASN1_BIT_STRING *publicKey;
};
struct CMS_RecipientEncryptedKey_st {
CMS_KeyAgreeRecipientIdentifier *rid;
ASN1_OCTET_STRING *encryptedKey;
/* Public key associated with this recipient */
EVP_PKEY *pkey;
};
struct CMS_KeyAgreeRecipientIdentifier_st {
int type;
union {
CMS_IssuerAndSerialNumber *issuerAndSerialNumber;
CMS_RecipientKeyIdentifier *rKeyId;
} d;
};
struct CMS_RecipientKeyIdentifier_st {
ASN1_OCTET_STRING *subjectKeyIdentifier;
ASN1_GENERALIZEDTIME *date;
CMS_OtherKeyAttribute *other;
};
struct CMS_KEKRecipientInfo_st {
long version;
CMS_KEKIdentifier *kekid;
X509_ALGOR *keyEncryptionAlgorithm;
ASN1_OCTET_STRING *encryptedKey;
/* Extra info: symmetric key to use */
unsigned char *key;
size_t keylen;
};
struct CMS_KEKIdentifier_st {
ASN1_OCTET_STRING *keyIdentifier;
ASN1_GENERALIZEDTIME *date;
CMS_OtherKeyAttribute *other;
};
struct CMS_PasswordRecipientInfo_st {
long version;
X509_ALGOR *keyDerivationAlgorithm;
X509_ALGOR *keyEncryptionAlgorithm;
ASN1_OCTET_STRING *encryptedKey;
/* Extra info: password to use */
unsigned char *pass;
size_t passlen;
};
struct CMS_OtherRecipientInfo_st {
ASN1_OBJECT *oriType;
ASN1_TYPE *oriValue;
};
struct CMS_DigestedData_st {
long version;
X509_ALGOR *digestAlgorithm;
CMS_EncapsulatedContentInfo *encapContentInfo;
ASN1_OCTET_STRING *digest;
};
struct CMS_EncryptedData_st {
long version;
CMS_EncryptedContentInfo *encryptedContentInfo;
STACK_OF(X509_ATTRIBUTE) *unprotectedAttrs;
};
struct CMS_AuthenticatedData_st {
long version;
CMS_OriginatorInfo *originatorInfo;
STACK_OF(CMS_RecipientInfo) *recipientInfos;
X509_ALGOR *macAlgorithm;
X509_ALGOR *digestAlgorithm;
CMS_EncapsulatedContentInfo *encapContentInfo;
STACK_OF(X509_ATTRIBUTE) *authAttrs;
ASN1_OCTET_STRING *mac;
STACK_OF(X509_ATTRIBUTE) *unauthAttrs;
};
struct CMS_CompressedData_st {
long version;
X509_ALGOR *compressionAlgorithm;
STACK_OF(CMS_RecipientInfo) *recipientInfos;
CMS_EncapsulatedContentInfo *encapContentInfo;
};
struct CMS_RevocationInfoChoice_st {
int type;
union {
X509_CRL *crl;
CMS_OtherRevocationInfoFormat *other;
} d;
};
#define CMS_REVCHOICE_CRL 0
#define CMS_REVCHOICE_OTHER 1
struct CMS_OtherRevocationInfoFormat_st {
ASN1_OBJECT *otherRevInfoFormat;
ASN1_TYPE *otherRevInfo;
};
struct CMS_CertificateChoices {
int type;
union {
X509 *certificate;
ASN1_STRING *extendedCertificate; /* Obsolete */
ASN1_STRING *v1AttrCert; /* Left encoded for now */
ASN1_STRING *v2AttrCert; /* Left encoded for now */
CMS_OtherCertificateFormat *other;
} d;
};
#define CMS_CERTCHOICE_CERT 0
#define CMS_CERTCHOICE_EXCERT 1
#define CMS_CERTCHOICE_V1ACERT 2
#define CMS_CERTCHOICE_V2ACERT 3
#define CMS_CERTCHOICE_OTHER 4
struct CMS_OtherCertificateFormat_st {
ASN1_OBJECT *otherCertFormat;
ASN1_TYPE *otherCert;
};
/*
* This is also defined in pkcs7.h but we duplicate it to allow the CMS code
* to be independent of PKCS#7
*/
struct CMS_IssuerAndSerialNumber_st {
X509_NAME *issuer;
ASN1_INTEGER *serialNumber;
};
struct CMS_OtherKeyAttribute_st {
ASN1_OBJECT *keyAttrId;
ASN1_TYPE *keyAttr;
};
/* ESS structures */
#ifdef HEADER_X509V3_H
struct CMS_ReceiptRequest_st {
ASN1_OCTET_STRING *signedContentIdentifier;
CMS_ReceiptsFrom *receiptsFrom;
STACK_OF(GENERAL_NAMES) *receiptsTo;
};
struct CMS_ReceiptsFrom_st {
int type;
union {
long allOrFirstTier;
STACK_OF(GENERAL_NAMES) *receiptList;
} d;
};
#endif
struct CMS_Receipt_st {
long version;
ASN1_OBJECT *contentType;
ASN1_OCTET_STRING *signedContentIdentifier;
ASN1_OCTET_STRING *originatorSignatureValue;
};
extern const ASN1_ITEM CMS_SignerInfo_it;
extern const ASN1_ITEM CMS_IssuerAndSerialNumber_it;
extern const ASN1_ITEM CMS_Attributes_Sign_it;
extern const ASN1_ITEM CMS_Attributes_Verify_it;
extern const ASN1_ITEM CMS_RecipientInfo_it;
extern const ASN1_ITEM CMS_PasswordRecipientInfo_it;
CMS_IssuerAndSerialNumber *CMS_IssuerAndSerialNumber_new(void);
void CMS_IssuerAndSerialNumber_free(CMS_IssuerAndSerialNumber *a);
#define CMS_SIGNERINFO_ISSUER_SERIAL 0
#define CMS_SIGNERINFO_KEYIDENTIFIER 1
#define CMS_RECIPINFO_ISSUER_SERIAL 0
#define CMS_RECIPINFO_KEYIDENTIFIER 1
#define CMS_REK_ISSUER_SERIAL 0
#define CMS_REK_KEYIDENTIFIER 1
#define CMS_OIK_ISSUER_SERIAL 0
#define CMS_OIK_KEYIDENTIFIER 1
#define CMS_OIK_PUBKEY 2
CMS_ContentInfo *cms_Data_create(void);
CMS_ContentInfo *cms_DigestedData_create(const EVP_MD *md);
BIO *cms_DigestedData_init_bio(CMS_ContentInfo *cms);
int cms_DigestedData_do_final(CMS_ContentInfo *cms, BIO *chain, int verify);
BIO *cms_SignedData_init_bio(CMS_ContentInfo *cms);
int cms_SignedData_final(CMS_ContentInfo *cms, BIO *chain);
int cms_set1_SignerIdentifier(CMS_SignerIdentifier *sid, X509 *cert, int type);
int cms_SignerIdentifier_get0_signer_id(CMS_SignerIdentifier *sid,
ASN1_OCTET_STRING **keyid, X509_NAME **issuer, ASN1_INTEGER **sno);
int cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert);
CMS_ContentInfo *cms_CompressedData_create(int comp_nid);
BIO *cms_CompressedData_init_bio(CMS_ContentInfo *cms);
BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm);
int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
X509_ALGOR *mdalg);
int cms_ias_cert_cmp(CMS_IssuerAndSerialNumber *ias, X509 *cert);
int cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert);
int cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert);
int cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert);
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);
int cms_Receipt_verify(CMS_ContentInfo *cms, CMS_ContentInfo *req_cms);
int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src);
ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si);
BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms);
int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd);
int cms_pkey_get_ri_type(EVP_PKEY *pk);
/* KARI routines */
int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip,
EVP_PKEY *pk, unsigned int flags);
int cms_RecipientInfo_kari_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
/* PWRI routines */
int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
int en_de);
extern const ASN1_ITEM CMS_CertificateChoices_it;
extern const ASN1_ITEM CMS_DigestedData_it;
extern const ASN1_ITEM CMS_EncryptedData_it;
extern const ASN1_ITEM CMS_EnvelopedData_it;
extern const ASN1_ITEM CMS_KEKRecipientInfo_it;
extern const ASN1_ITEM CMS_KeyAgreeRecipientInfo_it;
extern const ASN1_ITEM CMS_KeyTransRecipientInfo_it;
extern const ASN1_ITEM CMS_OriginatorPublicKey_it;
extern const ASN1_ITEM CMS_OtherKeyAttribute_it;
extern const ASN1_ITEM CMS_Receipt_it;
extern const ASN1_ITEM CMS_ReceiptRequest_it;
extern const ASN1_ITEM CMS_RecipientEncryptedKey_it;
extern const ASN1_ITEM CMS_RecipientKeyIdentifier_it;
extern const ASN1_ITEM CMS_RevocationInfoChoice_it;
extern const ASN1_ITEM CMS_SignedData_it;
extern const ASN1_ITEM CMS_CompressedData_it;
#endif /* !HEADER_CMS_LOCAL_H */

435
crypto/cms/cms_pwri.c Normal file
View File

@@ -0,0 +1,435 @@
/* $OpenBSD: cms_pwri.c,v 1.29 2023/07/08 08:26:26 beck Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2009 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <string.h>
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
#include <openssl/rand.h>
#include <openssl/aes.h>
#include "cms_local.h"
#include "asn1/asn1_local.h"
int
CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri, unsigned char *pass,
ssize_t passlen)
{
CMS_PasswordRecipientInfo *pwri;
if (ri->type != CMS_RECIPINFO_PASS) {
CMSerror(CMS_R_NOT_PWRI);
return 0;
}
pwri = ri->d.pwri;
pwri->pass = pass;
if (pass && passlen < 0)
passlen = strlen((char *)pass);
pwri->passlen = passlen;
return 1;
}
LCRYPTO_ALIAS(CMS_RecipientInfo_set0_password);
CMS_RecipientInfo *
CMS_add0_recipient_password(CMS_ContentInfo *cms, int iter, int wrap_nid,
int pbe_nid, unsigned char *pass, ssize_t passlen,
const EVP_CIPHER *kekciph)
{
CMS_RecipientInfo *ri = NULL;
CMS_EnvelopedData *env;
CMS_PasswordRecipientInfo *pwri;
EVP_CIPHER_CTX *ctx = NULL;
X509_ALGOR *encalg = NULL;
unsigned char iv[EVP_MAX_IV_LENGTH];
int ivlen;
env = cms_get0_enveloped(cms);
if (!env)
return NULL;
if (wrap_nid <= 0)
wrap_nid = NID_id_alg_PWRI_KEK;
if (pbe_nid <= 0)
pbe_nid = NID_id_pbkdf2;
/* Get from enveloped data */
if (kekciph == NULL)
kekciph = env->encryptedContentInfo->cipher;
if (kekciph == NULL) {
CMSerror(CMS_R_NO_CIPHER);
return NULL;
}
if (wrap_nid != NID_id_alg_PWRI_KEK) {
CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
return NULL;
}
/* Setup algorithm identifier for cipher */
encalg = X509_ALGOR_new();
if (encalg == NULL) {
goto merr;
}
if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
goto merr;
if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) {
CMSerror(ERR_R_EVP_LIB);
goto err;
}
ivlen = EVP_CIPHER_CTX_iv_length(ctx);
if (ivlen > 0) {
arc4random_buf(iv, ivlen);
if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) {
CMSerror(ERR_R_EVP_LIB);
goto err;
}
encalg->parameter = ASN1_TYPE_new();
if (!encalg->parameter) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) {
CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
goto err;
}
}
encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
EVP_CIPHER_CTX_free(ctx);
ctx = NULL;
/* Initialize recipient info */
ri = (CMS_RecipientInfo *)ASN1_item_new(&CMS_RecipientInfo_it);
if (ri == NULL)
goto merr;
ri->d.pwri = (CMS_PasswordRecipientInfo *)ASN1_item_new(&CMS_PasswordRecipientInfo_it);
if (ri->d.pwri == NULL)
goto merr;
ri->type = CMS_RECIPINFO_PASS;
pwri = ri->d.pwri;
/* Since this is overwritten, free up empty structure already there */
X509_ALGOR_free(pwri->keyEncryptionAlgorithm);
pwri->keyEncryptionAlgorithm = X509_ALGOR_new();
if (pwri->keyEncryptionAlgorithm == NULL)
goto merr;
pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
if (pwri->keyEncryptionAlgorithm->parameter == NULL)
goto merr;
if (!ASN1_item_pack(encalg, &X509_ALGOR_it,
&pwri->keyEncryptionAlgorithm->parameter->value.sequence))
goto merr;
pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;
X509_ALGOR_free(encalg);
encalg = NULL;
/* Setup PBE algorithm */
pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1);
if (!pwri->keyDerivationAlgorithm)
goto err;
CMS_RecipientInfo_set0_password(ri, pass, passlen);
pwri->version = 0;
if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
goto merr;
return ri;
merr:
CMSerror(ERR_R_MALLOC_FAILURE);
err:
EVP_CIPHER_CTX_free(ctx);
if (ri)
ASN1_item_free((ASN1_VALUE *)ri, &CMS_RecipientInfo_it);
X509_ALGOR_free(encalg);
return NULL;
}
LCRYPTO_ALIAS(CMS_add0_recipient_password);
/*
* This is an implementation of the key wrapping mechanism in RFC3211, at
* some point this should go into EVP.
*/
static int
kek_unwrap_key(unsigned char *out, size_t *outlen, const unsigned char *in,
size_t inlen, EVP_CIPHER_CTX *ctx)
{
size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
unsigned char *tmp;
int outl, rv = 0;
if (inlen < 2 * blocklen) {
/* too small */
return 0;
}
if (inlen % blocklen) {
/* Invalid size */
return 0;
}
if ((tmp = malloc(inlen)) == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
/* setup IV by decrypting last two blocks */
if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
in + inlen - 2 * blocklen, blocklen * 2)
/*
* Do a decrypt of last decrypted block to set IV to correct value
* output it to start of buffer so we don't corrupt decrypted block
* this works because buffer is at least two block lengths long.
*/
|| !EVP_DecryptUpdate(ctx, tmp, &outl, tmp + inlen - blocklen, blocklen)
/* Can now decrypt first n - 1 blocks */
|| !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen)
/* Reset IV to original value */
|| !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL)
/* Decrypt again */
|| !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen))
goto err;
/* Check check bytes */
if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) {
/* Check byte failure */
goto err;
}
if (inlen < (size_t)(tmp[0] - 4)) {
/* Invalid length value */
goto err;
}
*outlen = (size_t)tmp[0];
memcpy(out, tmp + 4, *outlen);
rv = 1;
err:
freezero(tmp, inlen);
return rv;
}
static int
kek_wrap_key(unsigned char *out, size_t *outlen, const unsigned char *in,
size_t inlen, EVP_CIPHER_CTX *ctx)
{
size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
size_t olen;
int dummy;
/*
* First decide length of output buffer: need header and round up to
* multiple of block length.
*/
olen = (inlen + 4 + blocklen - 1) / blocklen;
olen *= blocklen;
if (olen < 2 * blocklen) {
/* Key too small */
return 0;
}
if (inlen > 0xFF) {
/* Key too large */
return 0;
}
if (out) {
/* Set header */
out[0] = (unsigned char)inlen;
out[1] = in[0] ^ 0xFF;
out[2] = in[1] ^ 0xFF;
out[3] = in[2] ^ 0xFF;
memcpy(out + 4, in, inlen);
/* Add random padding to end */
if (olen > inlen + 4)
arc4random_buf(out + 4 + inlen, olen - 4 - inlen);
/* Encrypt twice */
if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen) ||
!EVP_EncryptUpdate(ctx, out, &dummy, out, olen))
return 0;
}
*outlen = olen;
return 1;
}
/* Encrypt/Decrypt content key in PWRI recipient info */
int
cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
int en_de)
{
CMS_EncryptedContentInfo *ec;
CMS_PasswordRecipientInfo *pwri;
int r = 0;
X509_ALGOR *algtmp, *kekalg = NULL;
EVP_CIPHER_CTX *kekctx = NULL;
const EVP_CIPHER *kekcipher;
unsigned char *key = NULL;
size_t keylen;
ec = cms->d.envelopedData->encryptedContentInfo;
pwri = ri->d.pwri;
if (!pwri->pass) {
CMSerror(CMS_R_NO_PASSWORD);
return 0;
}
algtmp = pwri->keyEncryptionAlgorithm;
if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) {
CMSerror(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
return 0;
}
if (algtmp->parameter != NULL &&
algtmp->parameter->type == V_ASN1_SEQUENCE &&
algtmp->parameter->value.sequence != NULL)
kekalg = ASN1_item_unpack(algtmp->parameter->value.sequence,
&X509_ALGOR_it);
if (kekalg == NULL) {
CMSerror(CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);
return 0;
}
kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
if (!kekcipher) {
CMSerror(CMS_R_UNKNOWN_CIPHER);
return 0;
}
kekctx = EVP_CIPHER_CTX_new();
if (kekctx == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
return 0;
}
/* Fixup cipher based on AlgorithmIdentifier to set IV etc */
if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de))
goto err;
EVP_CIPHER_CTX_set_padding(kekctx, 0);
if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) {
CMSerror(CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
goto err;
}
algtmp = pwri->keyDerivationAlgorithm;
/* Finish password based key derivation to setup key in "ctx" */
if (EVP_PBE_CipherInit(algtmp->algorithm, (char *)pwri->pass,
pwri->passlen, algtmp->parameter, kekctx, en_de) < 0) {
CMSerror(ERR_R_EVP_LIB);
goto err;
}
/* Finally wrap/unwrap the key */
if (en_de) {
if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx))
goto err;
key = malloc(keylen);
if (key == NULL)
goto err;
if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx))
goto err;
pwri->encryptedKey->data = key;
pwri->encryptedKey->length = keylen;
} else {
key = malloc(pwri->encryptedKey->length);
if (key == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
if (!kek_unwrap_key(key, &keylen, pwri->encryptedKey->data,
pwri->encryptedKey->length, kekctx)) {
CMSerror(CMS_R_UNWRAP_FAILURE);
goto err;
}
freezero(ec->key, ec->keylen);
ec->key = key;
ec->keylen = keylen;
}
r = 1;
err:
EVP_CIPHER_CTX_free(kekctx);
if (!r)
free(key);
X509_ALGOR_free(kekalg);
return r;
}

1029
crypto/cms/cms_sd.c Normal file

File diff suppressed because it is too large Load Diff

901
crypto/cms/cms_smime.c Normal file
View File

@@ -0,0 +1,901 @@
/* $OpenBSD: cms_smime.c,v 1.27 2023/07/08 08:26:26 beck Exp $ */
/*
* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
* project.
*/
/* ====================================================================
* Copyright (c) 2008 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include "cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/cms.h>
#include "cms_local.h"
#include "asn1/asn1_local.h"
static BIO *
cms_get_text_bio(BIO *out, unsigned int flags)
{
BIO *rbio;
if (out == NULL)
rbio = BIO_new(BIO_s_null());
else if (flags & CMS_TEXT) {
rbio = BIO_new(BIO_s_mem());
BIO_set_mem_eof_return(rbio, 0);
} else
rbio = out;
return rbio;
}
static int
cms_copy_content(BIO *out, BIO *in, unsigned int flags)
{
unsigned char buf[4096];
int r = 0, i;
BIO *tmpout;
tmpout = cms_get_text_bio(out, flags);
if (tmpout == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
/* Read all content through chain to process digest, decrypt etc */
for (;;) {
i = BIO_read(in, buf, sizeof(buf));
if (i <= 0) {
if (BIO_method_type(in) == BIO_TYPE_CIPHER) {
if (!BIO_get_cipher_status(in))
goto err;
}
if (i < 0)
goto err;
break;
}
if (tmpout && (BIO_write(tmpout, buf, i) != i))
goto err;
}
if (flags & CMS_TEXT) {
if (!SMIME_text(tmpout, out)) {
CMSerror(CMS_R_SMIME_TEXT_ERROR);
goto err;
}
}
r = 1;
err:
if (tmpout != out)
BIO_free(tmpout);
return r;
}
static int
check_content(CMS_ContentInfo *cms)
{
ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
if (!pos || !*pos) {
CMSerror(CMS_R_NO_CONTENT);
return 0;
}
return 1;
}
static void
do_free_upto(BIO *f, BIO *upto)
{
if (upto) {
BIO *tbio;
do {
tbio = BIO_pop(f);
BIO_free(f);
f = tbio;
}
while (f && f != upto);
} else
BIO_free_all(f);
}
int
CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
{
BIO *cont;
int r;
if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) {
CMSerror(CMS_R_TYPE_NOT_DATA);
return 0;
}
cont = CMS_dataInit(cms, NULL);
if (!cont)
return 0;
r = cms_copy_content(out, cont, flags);
BIO_free_all(cont);
return r;
}
LCRYPTO_ALIAS(CMS_data);
CMS_ContentInfo *
CMS_data_create(BIO *in, unsigned int flags)
{
CMS_ContentInfo *cms;
cms = cms_Data_create();
if (!cms)
return NULL;
if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
return cms;
CMS_ContentInfo_free(cms);
return NULL;
}
LCRYPTO_ALIAS(CMS_data_create);
int
CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out, unsigned int flags)
{
BIO *cont;
int r;
if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) {
CMSerror(CMS_R_TYPE_NOT_DIGESTED_DATA);
return 0;
}
if (!dcont && !check_content(cms))
return 0;
cont = CMS_dataInit(cms, dcont);
if (!cont)
return 0;
r = cms_copy_content(out, cont, flags);
if (r)
r = cms_DigestedData_do_final(cms, cont, 1);
do_free_upto(cont, dcont);
return r;
}
LCRYPTO_ALIAS(CMS_digest_verify);
CMS_ContentInfo *
CMS_digest_create(BIO *in, const EVP_MD *md, unsigned int flags)
{
CMS_ContentInfo *cms;
if (!md)
md = EVP_sha1();
cms = cms_DigestedData_create(md);
if (!cms)
return NULL;
if (!(flags & CMS_DETACHED))
CMS_set_detached(cms, 0);
if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
return cms;
CMS_ContentInfo_free(cms);
return NULL;
}
LCRYPTO_ALIAS(CMS_digest_create);
int
CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, const unsigned char *key,
size_t keylen, BIO *dcont, BIO *out, unsigned int flags)
{
BIO *cont;
int r;
if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) {
CMSerror(CMS_R_TYPE_NOT_ENCRYPTED_DATA);
return 0;
}
if (!dcont && !check_content(cms))
return 0;
if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
return 0;
cont = CMS_dataInit(cms, dcont);
if (!cont)
return 0;
r = cms_copy_content(out, cont, flags);
do_free_upto(cont, dcont);
return r;
}
LCRYPTO_ALIAS(CMS_EncryptedData_decrypt);
CMS_ContentInfo *
CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
const unsigned char *key, size_t keylen, unsigned int flags)
{
CMS_ContentInfo *cms;
if (!cipher) {
CMSerror(CMS_R_NO_CIPHER);
return NULL;
}
cms = CMS_ContentInfo_new();
if (cms == NULL)
return NULL;
if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
return NULL;
if (!(flags & CMS_DETACHED))
CMS_set_detached(cms, 0);
if ((flags & (CMS_STREAM | CMS_PARTIAL)) ||
CMS_final(cms, in, NULL, flags))
return cms;
CMS_ContentInfo_free(cms);
return NULL;
}
LCRYPTO_ALIAS(CMS_EncryptedData_encrypt);
static int
cms_signerinfo_verify_cert(CMS_SignerInfo *si, X509_STORE *store,
STACK_OF(X509) *certs, STACK_OF(X509_CRL) *crls)
{
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
X509 *signer;
int i, j, r = 0;
if (ctx == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
if (!X509_STORE_CTX_init(ctx, store, signer, certs)) {
CMSerror(CMS_R_STORE_INIT_ERROR);
goto err;
}
X509_STORE_CTX_set_default(ctx, "smime_sign");
if (crls)
X509_STORE_CTX_set0_crls(ctx, crls);
i = X509_verify_cert(ctx);
if (i <= 0) {
j = X509_STORE_CTX_get_error(ctx);
CMSerror(CMS_R_CERTIFICATE_VERIFY_ERROR);
ERR_asprintf_error_data("Verify error: %s",
X509_verify_cert_error_string(j));
goto err;
}
r = 1;
err:
X509_STORE_CTX_free(ctx);
return r;
}
int
CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, X509_STORE *store,
BIO *dcont, BIO *out, unsigned int flags)
{
CMS_SignerInfo *si;
STACK_OF(CMS_SignerInfo) *sinfos;
STACK_OF(X509) *cms_certs = NULL;
STACK_OF(X509_CRL) *crls = NULL;
X509 *signer;
int i, scount = 0, ret = 0;
BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL;
if (!dcont && !check_content(cms))
return 0;
if (dcont && !(flags & CMS_BINARY)) {
const ASN1_OBJECT *coid = CMS_get0_eContentType(cms);
if (OBJ_obj2nid(coid) == NID_id_ct_asciiTextWithCRLF)
flags |= CMS_ASCIICRLF;
}
/* Attempt to find all signer certificates */
sinfos = CMS_get0_SignerInfos(cms);
if (sk_CMS_SignerInfo_num(sinfos) <= 0) {
CMSerror(CMS_R_NO_SIGNERS);
goto err;
}
for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
si = sk_CMS_SignerInfo_value(sinfos, i);
CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
if (signer)
scount++;
}
if (scount != sk_CMS_SignerInfo_num(sinfos))
scount += CMS_set1_signers_certs(cms, certs, flags);
if (scount != sk_CMS_SignerInfo_num(sinfos)) {
CMSerror(CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
goto err;
}
/* Attempt to verify all signers certs */
if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) {
cms_certs = CMS_get1_certs(cms);
if (!(flags & CMS_NOCRL))
crls = CMS_get1_crls(cms);
for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
si = sk_CMS_SignerInfo_value(sinfos, i);
if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls))
goto err;
}
}
/* Attempt to verify all SignerInfo signed attribute signatures */
if (!(flags & CMS_NO_ATTR_VERIFY)) {
for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
si = sk_CMS_SignerInfo_value(sinfos, i);
if (CMS_signed_get_attr_count(si) < 0)
continue;
if (CMS_SignerInfo_verify(si) <= 0)
goto err;
}
}
/*
* Performance optimization: if the content is a memory BIO then store
* its contents in a temporary read only memory BIO. This avoids
* potentially large numbers of slow copies of data which will occur when
* reading from a read write memory BIO when signatures are calculated.
*/
if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) {
char *ptr;
long len;
len = BIO_get_mem_data(dcont, &ptr);
tmpin = BIO_new_mem_buf(ptr, len);
if (tmpin == NULL) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err2;
}
} else
tmpin = dcont;
/*
* If not binary mode and detached generate digests by *writing* through
* the BIO. That makes it possible to canonicalise the input.
*/
if (!(flags & SMIME_BINARY) && dcont) {
/*
* Create output BIO so we can either handle text or to ensure
* included content doesn't override detached content.
*/
tmpout = cms_get_text_bio(out, flags);
if (!tmpout) {
CMSerror(ERR_R_MALLOC_FAILURE);
goto err;
}
cmsbio = CMS_dataInit(cms, tmpout);
if (!cmsbio)
goto err;
/*
* Don't use SMIME_TEXT for verify: it adds headers and we want to
* remove them.
*/
SMIME_crlf_copy(dcont, cmsbio, flags & ~SMIME_TEXT);
if (flags & CMS_TEXT) {
if (!SMIME_text(tmpout, out)) {
CMSerror(CMS_R_SMIME_TEXT_ERROR);
goto err;
}
}
} else {
cmsbio = CMS_dataInit(cms, tmpin);
if (!cmsbio)
goto err;
if (!cms_copy_content(out, cmsbio, flags))
goto err;
}
if (!(flags & CMS_NO_CONTENT_VERIFY)) {
for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
si = sk_CMS_SignerInfo_value(sinfos, i);
if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) {
CMSerror(CMS_R_CONTENT_VERIFY_ERROR);
goto err;
}
}
}
ret = 1;
err:
if (!(flags & SMIME_BINARY) && dcont) {
do_free_upto(cmsbio, tmpout);
if (tmpin != dcont)
BIO_free(tmpin);
} else {
if (dcont && (tmpin == dcont))
do_free_upto(cmsbio, dcont);
else
BIO_free_all(cmsbio);
}
if (out != tmpout)
BIO_free_all(tmpout);
err2:
sk_X509_pop_free(cms_certs, X509_free);
sk_X509_CRL_pop_free(crls, X509_CRL_free);
return ret;
}
LCRYPTO_ALIAS(CMS_verify);
int
CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
STACK_OF(X509) *certs, X509_STORE *store, unsigned int flags)
{
int r;
flags &= ~(CMS_DETACHED | CMS_TEXT);
r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
if (r <= 0)
return r;
return cms_Receipt_verify(rcms, ocms);
}
LCRYPTO_ALIAS(CMS_verify_receipt);
CMS_ContentInfo *
CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, BIO *data,
unsigned int flags)
{
CMS_ContentInfo *cms;
int i;
cms = CMS_ContentInfo_new();
if (cms == NULL || !CMS_SignedData_init(cms))
goto merr;
if (flags & CMS_ASCIICRLF &&
!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_ct_asciiTextWithCRLF)))
goto err;
if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) {
CMSerror(CMS_R_ADD_SIGNER_ERROR);
goto err;
}
for (i = 0; i < sk_X509_num(certs); i++) {
X509 *x = sk_X509_value(certs, i);
if (!CMS_add1_cert(cms, x))
goto merr;
}
if (!(flags & CMS_DETACHED))
CMS_set_detached(cms, 0);
if ((flags & (CMS_STREAM | CMS_PARTIAL)) ||
CMS_final(cms, data, NULL, flags))
return cms;
else
goto err;
merr:
CMSerror(ERR_R_MALLOC_FAILURE);
err:
CMS_ContentInfo_free(cms);
return NULL;
}
LCRYPTO_ALIAS(CMS_sign);
CMS_ContentInfo *
CMS_sign_receipt(CMS_SignerInfo *si, X509 *signcert, EVP_PKEY *pkey,
STACK_OF(X509) *certs, unsigned int flags)
{
CMS_SignerInfo *rct_si;
CMS_ContentInfo *cms = NULL;
ASN1_OCTET_STRING **pos, *os;
BIO *rct_cont = NULL;
int r = 0;
flags &= ~(CMS_STREAM | CMS_TEXT);
/* Not really detached but avoids content being allocated */
flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED;
if (!pkey || !signcert) {
CMSerror(CMS_R_NO_KEY_OR_CERT);
return NULL;
}
/* Initialize signed data */
cms = CMS_sign(NULL, NULL, certs, NULL, flags);
if (!cms)
goto err;
/* Set inner content type to signed receipt */
if (!CMS_set1_eContentType(cms, OBJ_nid2obj(NID_id_smime_ct_receipt)))
goto err;
rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
if (!rct_si) {
CMSerror(CMS_R_ADD_SIGNER_ERROR);
goto err;
}
os = cms_encode_Receipt(si);
if (!os)
goto err;
/* Set content to digest */
rct_cont = BIO_new_mem_buf(os->data, os->length);
if (!rct_cont)
goto err;
/* Add msgSigDigest attribute */
if (!cms_msgSigDigest_add1(rct_si, si))
goto err;
/* Finalize structure */
if (!CMS_final(cms, rct_cont, NULL, flags))
goto err;
/* Set embedded content */
pos = CMS_get0_content(cms);
*pos = os;
r = 1;
err:
BIO_free(rct_cont);
if (r)
return cms;
CMS_ContentInfo_free(cms);
return NULL;
}
LCRYPTO_ALIAS(CMS_sign_receipt);
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)) {
CMSerror(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, NULL, flags))
return cms;
else
goto err;
merr:
CMSerror(ERR_R_MALLOC_FAILURE);
err:
CMS_ContentInfo_free(cms);
return NULL;
}
LCRYPTO_ALIAS(CMS_encrypt);
static int
cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri, EVP_PKEY *pk,
X509 *cert)
{
int i;
STACK_OF(CMS_RecipientEncryptedKey) *reks;
CMS_RecipientEncryptedKey *rek;
reks = CMS_RecipientInfo_kari_get0_reks(ri);
for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) {
int rv;
rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
if (cert != NULL && CMS_RecipientEncryptedKey_cert_cmp(rek, cert))
continue;
CMS_RecipientInfo_kari_set0_pkey(ri, pk);
rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek);
CMS_RecipientInfo_kari_set0_pkey(ri, NULL);
if (rv > 0)
return 1;
return cert == NULL ? 0 : -1;
}
return 0;
}
int
CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
{
STACK_OF(CMS_RecipientInfo) *ris;
CMS_RecipientInfo *ri;
int i, r, ri_type;
int debug = 0, match_ri = 0;
ris = CMS_get0_RecipientInfos(cms);
if (ris)
debug = cms->d.envelopedData->encryptedContentInfo->debug;
ri_type = cms_pkey_get_ri_type(pk);
if (ri_type == CMS_RECIPINFO_NONE) {
CMSerror(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
return 0;
}
for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
ri = sk_CMS_RecipientInfo_value(ris, i);
if (CMS_RecipientInfo_type(ri) != ri_type)
continue;
match_ri = 1;
if (ri_type == CMS_RECIPINFO_AGREE) {
r = cms_kari_set1_pkey(cms, ri, pk, cert);
if (r > 0)
return 1;
if (r < 0)
return 0;
}
/*
* If we have a cert try matching RecipientInfo otherwise try them
* all.
*/
else if (!cert || !CMS_RecipientInfo_ktri_cert_cmp(ri, cert)) {
EVP_PKEY_up_ref(pk);
CMS_RecipientInfo_set0_pkey(ri, pk);
r = CMS_RecipientInfo_decrypt(cms, ri);
CMS_RecipientInfo_set0_pkey(ri, NULL);
if (cert) {
/*
* If not debugging clear any error and return success to
* avoid leaking of information useful to MMA
*/
if (!debug) {
ERR_clear_error();
return 1;
}
if (r > 0)
return 1;
CMSerror(CMS_R_DECRYPT_ERROR);
return 0;
}
/*
* If no cert and not debugging don't leave loop after first
* successful decrypt. Always attempt to decrypt all recipients
* to avoid leaking timing of a successful decrypt.
*/
else if (r > 0 && debug)
return 1;
}
}
/* If no cert, key transport and not debugging always return success */
if (cert == NULL && ri_type == CMS_RECIPINFO_TRANS && match_ri && !debug) {
ERR_clear_error();
return 1;
}
CMSerror(CMS_R_NO_MATCHING_RECIPIENT);
return 0;
}
LCRYPTO_ALIAS(CMS_decrypt_set1_pkey);
int
CMS_decrypt_set1_key(CMS_ContentInfo *cms, unsigned char *key, size_t keylen,
const unsigned char *id, size_t idlen)
{
STACK_OF(CMS_RecipientInfo) *ris;
CMS_RecipientInfo *ri;
int i, r;
ris = CMS_get0_RecipientInfos(cms);
for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
ri = sk_CMS_RecipientInfo_value(ris, i);
if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_KEK)
continue;
/*
* If we have an id try matching RecipientInfo otherwise try them
* all.
*/
if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) {
CMS_RecipientInfo_set0_key(ri, key, keylen);
r = CMS_RecipientInfo_decrypt(cms, ri);
CMS_RecipientInfo_set0_key(ri, NULL, 0);
if (r > 0)
return 1;
if (id) {
CMSerror(CMS_R_DECRYPT_ERROR);
return 0;
}
ERR_clear_error();
}
}
CMSerror(CMS_R_NO_MATCHING_RECIPIENT);
return 0;
}
LCRYPTO_ALIAS(CMS_decrypt_set1_key);
int
CMS_decrypt_set1_password(CMS_ContentInfo *cms, unsigned char *pass,
ssize_t passlen)
{
STACK_OF(CMS_RecipientInfo) *ris;
CMS_RecipientInfo *ri;
int i, r;
ris = CMS_get0_RecipientInfos(cms);
for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
ri = sk_CMS_RecipientInfo_value(ris, i);
if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS)
continue;
CMS_RecipientInfo_set0_password(ri, pass, passlen);
r = CMS_RecipientInfo_decrypt(cms, ri);
CMS_RecipientInfo_set0_password(ri, NULL, 0);
if (r > 0)
return 1;
}
CMSerror(CMS_R_NO_MATCHING_RECIPIENT);
return 0;
}
LCRYPTO_ALIAS(CMS_decrypt_set1_password);
int
CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, BIO *dcont,
BIO *out, unsigned int flags)
{
int r;
BIO *cont;
if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) {
CMSerror(CMS_R_TYPE_NOT_ENVELOPED_DATA);
return 0;
}
if (!dcont && !check_content(cms))
return 0;
if (flags & CMS_DEBUG_DECRYPT)
cms->d.envelopedData->encryptedContentInfo->debug = 1;
else
cms->d.envelopedData->encryptedContentInfo->debug = 0;
if (!cert)
cms->d.envelopedData->encryptedContentInfo->havenocert = 1;
else
cms->d.envelopedData->encryptedContentInfo->havenocert = 0;
if (!pk && !cert && !dcont && !out)
return 1;
if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
return 0;
cont = CMS_dataInit(cms, dcont);
if (!cont)
return 0;
r = cms_copy_content(out, cont, flags);
do_free_upto(cont, dcont);
return r;
}
LCRYPTO_ALIAS(CMS_decrypt);
int
CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
{
BIO *cmsbio;
int ret = 0;
if ((cmsbio = CMS_dataInit(cms, dcont)) == NULL) {
CMSerror(CMS_R_CMS_LIB);
return 0;
}
SMIME_crlf_copy(data, cmsbio, flags);
(void)BIO_flush(cmsbio);
if (!CMS_dataFinal(cms, cmsbio)) {
CMSerror(CMS_R_CMS_DATAFINAL_ERROR);
goto err;
}
ret = 1;
err:
do_free_upto(cmsbio, dcont);
return ret;
}
LCRYPTO_ALIAS(CMS_final);
int
CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out, unsigned int flags)
{
CMSerror(CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
return 0;
}
LCRYPTO_ALIAS(CMS_uncompress);
CMS_ContentInfo *
CMS_compress(BIO *in, int comp_nid, unsigned int flags)
{
CMSerror(CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
return NULL;
}
LCRYPTO_ALIAS(CMS_compress);