mirror of
https://github.com/openssl/openssl.git
synced 2024-12-04 15:34:41 +08:00
Move CMS enveloping code out of the algorithms and into CMS
There is quite a large amount of algorithm specific CMS code sitting in the algorithm directories. However, this seems to break layering. Algorithms really have no business knowing anything about CMS. Really it should be the other way around. Where there is algorithm specific CMS code it is the CMS layer that should know how to handle different algorithms. Therefore we move this code into the CMS layer. Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/13088)
This commit is contained in:
parent
99b3b762c3
commit
0b3a4ef27a
@ -171,6 +171,7 @@ static const ERR_STRING_DATA ASN1_str_reasons[] = {
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNEXPECTED_EOC), "unexpected eoc"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH),
|
||||
"universalstring is wrong length"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_DIGEST), "unknown digest"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_FORMAT), "unknown format"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM),
|
||||
"unknown message digest algorithm"},
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/err.h>
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/evp.h"
|
||||
|
||||
ASN1_SEQUENCE(X509_ALGOR) = {
|
||||
@ -125,3 +127,64 @@ int X509_ALGOR_copy(X509_ALGOR *dest, const X509_ALGOR *src)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* allocate and set algorithm ID from EVP_MD, default SHA1 */
|
||||
int x509_algor_new_from_md(X509_ALGOR **palg, const EVP_MD *md)
|
||||
{
|
||||
/* Default is SHA1 so no need to create it - still success */
|
||||
if (md == NULL || EVP_MD_is_a(md, "SHA1"))
|
||||
return 1;
|
||||
*palg = X509_ALGOR_new();
|
||||
if (*palg == NULL)
|
||||
return 0;
|
||||
X509_ALGOR_set_md(*palg, md);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* convert algorithm ID to EVP_MD, default SHA1 */
|
||||
const EVP_MD *x509_algor_get_md(X509_ALGOR *alg)
|
||||
{
|
||||
const EVP_MD *md;
|
||||
|
||||
if (alg == NULL)
|
||||
return EVP_sha1();
|
||||
md = EVP_get_digestbyobj(alg->algorithm);
|
||||
if (md == NULL)
|
||||
ASN1err(0, ASN1_R_UNKNOWN_DIGEST);
|
||||
return md;
|
||||
}
|
||||
|
||||
X509_ALGOR *x509_algor_mgf1_decode(X509_ALGOR *alg)
|
||||
{
|
||||
if (OBJ_obj2nid(alg->algorithm) != NID_mgf1)
|
||||
return NULL;
|
||||
return ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),
|
||||
alg->parameter);
|
||||
}
|
||||
|
||||
/* Allocate and set MGF1 algorithm ID from EVP_MD */
|
||||
int x509_algor_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md)
|
||||
{
|
||||
X509_ALGOR *algtmp = NULL;
|
||||
ASN1_STRING *stmp = NULL;
|
||||
|
||||
*palg = NULL;
|
||||
if (mgf1md == NULL || EVP_MD_is_a(mgf1md, "SHA1"))
|
||||
return 1;
|
||||
/* need to embed algorithm ID inside another */
|
||||
if (!x509_algor_new_from_md(&algtmp, mgf1md))
|
||||
goto err;
|
||||
if (ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp) == NULL)
|
||||
goto err;
|
||||
*palg = X509_ALGOR_new();
|
||||
if (*palg == NULL)
|
||||
goto err;
|
||||
X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp);
|
||||
stmp = NULL;
|
||||
err:
|
||||
ASN1_STRING_free(stmp);
|
||||
X509_ALGOR_free(algtmp);
|
||||
if (*palg)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2,4 +2,11 @@ LIBS=../../libcrypto
|
||||
SOURCE[../../libcrypto]= \
|
||||
cms_lib.c cms_asn1.c cms_att.c cms_io.c cms_smime.c cms_err.c \
|
||||
cms_sd.c cms_dd.c cms_cd.c cms_env.c cms_enc.c cms_ess.c \
|
||||
cms_pwri.c cms_kari.c
|
||||
cms_pwri.c cms_kari.c cms_rsa.c
|
||||
|
||||
IF[{- !$disabled{dh} -}]
|
||||
SOURCE[../../libcrypto]=cms_dh.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{ed} -}]
|
||||
SOURCE[../../libcrypto]=cms_ecdh.c
|
||||
ENDIF
|
322
crypto/cms/cms_dh.c
Normal file
322
crypto/cms/cms_dh.c
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (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>
|
||||
#include <openssl/core_names.h>
|
||||
#include "cms_local.h"
|
||||
|
||||
static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
|
||||
X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
|
||||
{
|
||||
const ASN1_OBJECT *aoid;
|
||||
int atype;
|
||||
const void *aval;
|
||||
ASN1_INTEGER *public_key = NULL;
|
||||
int rv = 0;
|
||||
EVP_PKEY *pkpeer = NULL, *pk = NULL;
|
||||
const unsigned char *p;
|
||||
int plen;
|
||||
|
||||
X509_ALGOR_get0(&aoid, &atype, &aval, alg);
|
||||
if (OBJ_obj2nid(aoid) != NID_dhpublicnumber)
|
||||
goto err;
|
||||
/* Only absent parameters allowed in RFC XXXX */
|
||||
if (atype != V_ASN1_UNDEF && atype == V_ASN1_NULL)
|
||||
goto err;
|
||||
|
||||
pk = EVP_PKEY_CTX_get0_pkey(pctx);
|
||||
if (pk == NULL)
|
||||
goto err;
|
||||
if (!EVP_PKEY_is_a(pk, "DHX"))
|
||||
goto err;
|
||||
|
||||
/* Get public key */
|
||||
plen = ASN1_STRING_length(pubkey);
|
||||
p = ASN1_STRING_get0_data(pubkey);
|
||||
if (p == NULL || plen == 0)
|
||||
goto err;
|
||||
|
||||
pkpeer = EVP_PKEY_new();
|
||||
if (pkpeer == NULL
|
||||
|| !EVP_PKEY_copy_parameters(pkpeer, pk)
|
||||
/*
|
||||
* TODO(3.0): This is badly named!! Can we make this more
|
||||
* generic and not TLS specific?
|
||||
*/
|
||||
|| !EVP_PKEY_set1_tls_encodedpoint(pkpeer, p, plen))
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
|
||||
rv = 1;
|
||||
err:
|
||||
ASN1_INTEGER_free(public_key);
|
||||
EVP_PKEY_free(pkpeer);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
|
||||
{
|
||||
int rv = 0;
|
||||
X509_ALGOR *alg, *kekalg = NULL;
|
||||
ASN1_OCTET_STRING *ukm;
|
||||
const unsigned char *p;
|
||||
unsigned char *dukm = NULL;
|
||||
size_t dukmlen = 0;
|
||||
int keylen, plen;
|
||||
const EVP_CIPHER *kekcipher;
|
||||
EVP_CIPHER_CTX *kekctx;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* For DH we only have one OID permissible. If ever any more get defined
|
||||
* we will need something cleverer.
|
||||
*/
|
||||
if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) {
|
||||
CMSerr(0, CMS_R_KDF_PARAMETER_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0)
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0)
|
||||
goto err;
|
||||
|
||||
if (alg->parameter->type != V_ASN1_SEQUENCE)
|
||||
goto err;
|
||||
|
||||
p = alg->parameter->value.sequence->data;
|
||||
plen = alg->parameter->value.sequence->length;
|
||||
kekalg = d2i_X509_ALGOR(NULL, &p, plen);
|
||||
if (kekalg == NULL)
|
||||
goto err;
|
||||
kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
||||
if (kekctx == NULL)
|
||||
goto err;
|
||||
kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
|
||||
if (kekcipher == NULL || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
|
||||
goto err;
|
||||
if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
|
||||
goto err;
|
||||
if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
|
||||
goto err;
|
||||
|
||||
keylen = EVP_CIPHER_CTX_key_length(kekctx);
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
|
||||
goto err;
|
||||
/* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */
|
||||
if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx,
|
||||
OBJ_nid2obj(EVP_CIPHER_type(kekcipher)))
|
||||
<= 0)
|
||||
goto err;
|
||||
|
||||
if (ukm != NULL) {
|
||||
dukmlen = ASN1_STRING_length(ukm);
|
||||
dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
|
||||
if (dukm == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
|
||||
goto err;
|
||||
dukm = NULL;
|
||||
|
||||
rv = 1;
|
||||
err:
|
||||
X509_ALGOR_free(kekalg);
|
||||
OPENSSL_free(dukm);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int dh_cms_decrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx;
|
||||
|
||||
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
|
||||
if (pctx == NULL)
|
||||
return 0;
|
||||
/* See if we need to set peer key */
|
||||
if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
|
||||
X509_ALGOR *alg;
|
||||
ASN1_BIT_STRING *pubkey;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
|
||||
NULL, NULL, NULL))
|
||||
return 0;
|
||||
if (alg == NULL || pubkey == NULL)
|
||||
return 0;
|
||||
if (!dh_cms_set_peerkey(pctx, alg, pubkey)) {
|
||||
DHerr(DH_F_DH_CMS_DECRYPT, DH_R_PEER_KEY_ERROR);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Set DH derivation parameters and initialise unwrap context */
|
||||
if (!dh_cms_set_shared_info(pctx, ri)) {
|
||||
DHerr(DH_F_DH_CMS_DECRYPT, DH_R_SHARED_INFO_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dh_cms_encrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx;
|
||||
EVP_PKEY *pkey;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
int keylen;
|
||||
X509_ALGOR *talg, *wrap_alg = NULL;
|
||||
const ASN1_OBJECT *aoid;
|
||||
ASN1_BIT_STRING *pubkey;
|
||||
ASN1_STRING *wrap_str;
|
||||
ASN1_OCTET_STRING *ukm;
|
||||
unsigned char *penc = NULL, *dukm = NULL;
|
||||
int penclen;
|
||||
size_t dukmlen = 0;
|
||||
int rv = 0;
|
||||
int kdf_type, wrap_nid;
|
||||
const EVP_MD *kdf_md;
|
||||
|
||||
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
if (pctx == NULL)
|
||||
return 0;
|
||||
/* Get ephemeral key */
|
||||
pkey = EVP_PKEY_CTX_get0_pkey(pctx);
|
||||
if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
|
||||
NULL, NULL, NULL))
|
||||
goto err;
|
||||
X509_ALGOR_get0(&aoid, NULL, NULL, talg);
|
||||
/* Is everything uninitialised? */
|
||||
if (aoid == OBJ_nid2obj(NID_undef)) {
|
||||
BIGNUM *bn_pub_key = NULL;
|
||||
ASN1_INTEGER *pubk;
|
||||
|
||||
if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &bn_pub_key))
|
||||
goto err;
|
||||
|
||||
pubk = BN_to_ASN1_INTEGER(bn_pub_key, NULL);
|
||||
BN_free(bn_pub_key);
|
||||
if (pubk == NULL)
|
||||
goto err;
|
||||
/* Set the key */
|
||||
|
||||
penclen = i2d_ASN1_INTEGER(pubk, &penc);
|
||||
ASN1_INTEGER_free(pubk);
|
||||
if (penclen <= 0)
|
||||
goto err;
|
||||
ASN1_STRING_set0(pubkey, penc, penclen);
|
||||
pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
|
||||
pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
|
||||
|
||||
penc = NULL;
|
||||
X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber),
|
||||
V_ASN1_UNDEF, NULL);
|
||||
}
|
||||
|
||||
/* See if custom parameters set */
|
||||
kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx);
|
||||
if (kdf_type <= 0)
|
||||
goto err;
|
||||
if (!EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md))
|
||||
goto err;
|
||||
|
||||
if (kdf_type == EVP_PKEY_DH_KDF_NONE) {
|
||||
kdf_type = EVP_PKEY_DH_KDF_X9_42;
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0)
|
||||
goto err;
|
||||
} else if (kdf_type != EVP_PKEY_DH_KDF_X9_42)
|
||||
/* Unknown KDF */
|
||||
goto err;
|
||||
if (kdf_md == NULL) {
|
||||
/* Only SHA1 supported */
|
||||
kdf_md = EVP_sha1();
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0)
|
||||
goto err;
|
||||
} else if (EVP_MD_type(kdf_md) != NID_sha1)
|
||||
/* Unsupported digest */
|
||||
goto err;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
|
||||
goto err;
|
||||
|
||||
/* Get wrap NID */
|
||||
ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
||||
wrap_nid = EVP_CIPHER_CTX_type(ctx);
|
||||
if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0)
|
||||
goto err;
|
||||
keylen = EVP_CIPHER_CTX_key_length(ctx);
|
||||
|
||||
/* Package wrap algorithm in an AlgorithmIdentifier */
|
||||
|
||||
wrap_alg = X509_ALGOR_new();
|
||||
if (wrap_alg == NULL)
|
||||
goto err;
|
||||
wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
|
||||
wrap_alg->parameter = ASN1_TYPE_new();
|
||||
if (wrap_alg->parameter == NULL)
|
||||
goto err;
|
||||
if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
|
||||
goto err;
|
||||
if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
|
||||
ASN1_TYPE_free(wrap_alg->parameter);
|
||||
wrap_alg->parameter = NULL;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
|
||||
goto err;
|
||||
|
||||
if (ukm != NULL) {
|
||||
dukmlen = ASN1_STRING_length(ukm);
|
||||
dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
|
||||
if (dukm == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
|
||||
goto err;
|
||||
dukm = NULL;
|
||||
|
||||
/*
|
||||
* Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
|
||||
* of another AlgorithmIdentifier.
|
||||
*/
|
||||
penc = NULL;
|
||||
penclen = i2d_X509_ALGOR(wrap_alg, &penc);
|
||||
if (penc == NULL || penclen == 0)
|
||||
goto err;
|
||||
wrap_str = ASN1_STRING_new();
|
||||
if (wrap_str == NULL)
|
||||
goto err;
|
||||
ASN1_STRING_set0(wrap_str, penc, penclen);
|
||||
penc = NULL;
|
||||
X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH),
|
||||
V_ASN1_SEQUENCE, wrap_str);
|
||||
|
||||
rv = 1;
|
||||
|
||||
err:
|
||||
OPENSSL_free(penc);
|
||||
X509_ALGOR_free(wrap_alg);
|
||||
OPENSSL_free(dukm);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int cms_dh_envelope(CMS_RecipientInfo *ri, int decrypt)
|
||||
{
|
||||
if (decrypt == 1)
|
||||
return dh_cms_decrypt(ri);
|
||||
else if (decrypt == 0)
|
||||
return dh_cms_encrypt(ri);
|
||||
|
||||
CMSerr(0, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
|
||||
return 0;
|
||||
}
|
391
crypto/cms/cms_ecdh.c
Normal file
391
crypto/cms/cms_ecdh.c
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (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>
|
||||
#include <openssl/decoder.h>
|
||||
#include "cms_local.h"
|
||||
#include "crypto/evp.h"
|
||||
|
||||
|
||||
static EVP_PKEY *pkey_type2param(int ptype, const void *pval,
|
||||
OPENSSL_CTX *libctx, const char *propq)
|
||||
{
|
||||
EVP_PKEY *pkey = NULL;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
|
||||
if (ptype == V_ASN1_SEQUENCE) {
|
||||
const ASN1_STRING *pstr = pval;
|
||||
const unsigned char *pm = pstr->data;
|
||||
int pmlen = pstr->length;
|
||||
OSSL_DECODER_CTX *ctx = NULL;
|
||||
BIO *membio = NULL;
|
||||
|
||||
/* TODO(3.0): Need to be able to specify here that only params will do */
|
||||
ctx = OSSL_DECODER_CTX_new_by_EVP_PKEY(&pkey, "DER", "EC", libctx,
|
||||
propq);
|
||||
membio = BIO_new_mem_buf(pm, pmlen);
|
||||
OSSL_DECODER_from_bio(ctx, membio);
|
||||
BIO_free(membio);
|
||||
OSSL_DECODER_CTX_free(ctx);
|
||||
} else if (ptype == V_ASN1_OBJECT) {
|
||||
const ASN1_OBJECT *poid = pval;
|
||||
const char *groupname;
|
||||
|
||||
/*
|
||||
* type == V_ASN1_OBJECT => the parameters are given by an asn1 OID
|
||||
*/
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
|
||||
|
||||
if (pctx == NULL)
|
||||
goto err;
|
||||
if (EVP_PKEY_paramgen_init(pctx) <= 0)
|
||||
goto err;
|
||||
groupname = OBJ_nid2sn(OBJ_obj2nid(poid));
|
||||
if (groupname == NULL
|
||||
|| !EVP_PKEY_CTX_set_group_name(pctx, groupname)) {
|
||||
CMSerr(0, CMS_R_DECODE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if (EVP_PKEY_paramgen(pctx, &pkey) <= 0) {
|
||||
EVP_PKEY_free(pkey);
|
||||
pkey = NULL;
|
||||
}
|
||||
} else {
|
||||
CMSerr(0, CMS_R_DECODE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return pkey;
|
||||
|
||||
err:
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ecdh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
|
||||
X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
|
||||
{
|
||||
const ASN1_OBJECT *aoid;
|
||||
int atype;
|
||||
const void *aval;
|
||||
int rv = 0;
|
||||
EVP_PKEY *pkpeer = NULL;
|
||||
const unsigned char *p;
|
||||
int plen;
|
||||
|
||||
X509_ALGOR_get0(&aoid, &atype, &aval, alg);
|
||||
if (OBJ_obj2nid(aoid) != NID_X9_62_id_ecPublicKey)
|
||||
goto err;
|
||||
/* If absent parameters get group from main key */
|
||||
if (atype == V_ASN1_UNDEF || atype == V_ASN1_NULL) {
|
||||
EVP_PKEY *pk;
|
||||
pk = EVP_PKEY_CTX_get0_pkey(pctx);
|
||||
if (pk == NULL)
|
||||
goto err;
|
||||
|
||||
pkpeer = EVP_PKEY_new();
|
||||
if (pkpeer == NULL)
|
||||
goto err;
|
||||
if (!EVP_PKEY_copy_parameters(pkpeer, pk))
|
||||
goto err;
|
||||
} else {
|
||||
/* TODO(3.0): Should the get0_libctx/propq calls actually be public API? */
|
||||
pkpeer = pkey_type2param(atype, aval,
|
||||
evp_pkey_ctx_get0_libctx(pctx),
|
||||
evp_pkey_ctx_get0_propq(pctx));
|
||||
if (pkpeer == NULL)
|
||||
goto err;
|
||||
}
|
||||
/* We have parameters now set public key */
|
||||
plen = ASN1_STRING_length(pubkey);
|
||||
p = ASN1_STRING_get0_data(pubkey);
|
||||
if (p == NULL || plen == 0)
|
||||
goto err;
|
||||
|
||||
/* TODO(3.0): Terrible name. We need a non-tls specific name */
|
||||
if (!EVP_PKEY_set1_tls_encodedpoint(pkpeer, p, plen))
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
|
||||
rv = 1;
|
||||
err:
|
||||
EVP_PKEY_free(pkpeer);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Set KDF parameters based on KDF NID */
|
||||
static int ecdh_cms_set_kdf_param(EVP_PKEY_CTX *pctx, int eckdf_nid)
|
||||
{
|
||||
int kdf_nid, kdfmd_nid, cofactor;
|
||||
const EVP_MD *kdf_md;
|
||||
if (eckdf_nid == NID_undef)
|
||||
return 0;
|
||||
|
||||
/* Lookup KDF type, cofactor mode and digest */
|
||||
if (!OBJ_find_sigid_algs(eckdf_nid, &kdfmd_nid, &kdf_nid))
|
||||
return 0;
|
||||
|
||||
if (kdf_nid == NID_dh_std_kdf)
|
||||
cofactor = 0;
|
||||
else if (kdf_nid == NID_dh_cofactor_kdf)
|
||||
cofactor = 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (EVP_PKEY_CTX_set_ecdh_cofactor_mode(pctx, cofactor) <= 0)
|
||||
return 0;
|
||||
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, EVP_PKEY_ECDH_KDF_X9_63) <= 0)
|
||||
return 0;
|
||||
|
||||
kdf_md = EVP_get_digestbynid(kdfmd_nid);
|
||||
if (!kdf_md)
|
||||
return 0;
|
||||
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
X509_ALGOR *alg, *kekalg = NULL;
|
||||
ASN1_OCTET_STRING *ukm;
|
||||
const unsigned char *p;
|
||||
unsigned char *der = NULL;
|
||||
int plen, keylen;
|
||||
EVP_CIPHER *kekcipher = NULL;
|
||||
EVP_CIPHER_CTX *kekctx;
|
||||
const char *name;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
|
||||
return 0;
|
||||
|
||||
if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) {
|
||||
CMSerr(0, CMS_R_KDF_PARAMETER_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (alg->parameter->type != V_ASN1_SEQUENCE)
|
||||
return 0;
|
||||
|
||||
p = alg->parameter->value.sequence->data;
|
||||
plen = alg->parameter->value.sequence->length;
|
||||
kekalg = d2i_X509_ALGOR(NULL, &p, plen);
|
||||
if (kekalg == NULL)
|
||||
goto err;
|
||||
kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
||||
if (kekctx == NULL)
|
||||
goto err;
|
||||
name = OBJ_nid2sn(OBJ_obj2nid(kekalg->algorithm));
|
||||
kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery);
|
||||
if (kekcipher == NULL || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
|
||||
goto err;
|
||||
if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
|
||||
goto err;
|
||||
if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
|
||||
goto err;
|
||||
|
||||
keylen = EVP_CIPHER_CTX_key_length(kekctx);
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
|
||||
goto err;
|
||||
|
||||
plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen);
|
||||
|
||||
if (plen <= 0)
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0)
|
||||
goto err;
|
||||
der = NULL;
|
||||
|
||||
rv = 1;
|
||||
err:
|
||||
EVP_CIPHER_free(kekcipher);
|
||||
X509_ALGOR_free(kekalg);
|
||||
OPENSSL_free(der);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ecdh_cms_decrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx;
|
||||
|
||||
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
if (pctx == NULL)
|
||||
return 0;
|
||||
/* See if we need to set peer key */
|
||||
if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
|
||||
X509_ALGOR *alg;
|
||||
ASN1_BIT_STRING *pubkey;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
|
||||
NULL, NULL, NULL))
|
||||
return 0;
|
||||
if (!alg || !pubkey)
|
||||
return 0;
|
||||
if (!ecdh_cms_set_peerkey(pctx, alg, pubkey)) {
|
||||
CMSerr(0, CMS_R_PEER_KEY_ERROR);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Set ECDH derivation parameters and initialise unwrap context */
|
||||
if (!ecdh_cms_set_shared_info(pctx, ri)) {
|
||||
CMSerr(0, CMS_R_SHARED_INFO_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecdh_cms_encrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx;
|
||||
EVP_PKEY *pkey;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
int keylen;
|
||||
X509_ALGOR *talg, *wrap_alg = NULL;
|
||||
const ASN1_OBJECT *aoid;
|
||||
ASN1_BIT_STRING *pubkey;
|
||||
ASN1_STRING *wrap_str;
|
||||
ASN1_OCTET_STRING *ukm;
|
||||
unsigned char *penc = NULL;
|
||||
size_t penclen;
|
||||
int rv = 0;
|
||||
int ecdh_nid, kdf_type, kdf_nid, wrap_nid;
|
||||
const EVP_MD *kdf_md;
|
||||
|
||||
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
if (pctx == NULL)
|
||||
return 0;
|
||||
/* Get ephemeral key */
|
||||
pkey = EVP_PKEY_CTX_get0_pkey(pctx);
|
||||
if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
|
||||
NULL, NULL, NULL))
|
||||
goto err;
|
||||
X509_ALGOR_get0(&aoid, NULL, NULL, talg);
|
||||
/* Is everything uninitialised? */
|
||||
if (aoid == OBJ_nid2obj(NID_undef)) {
|
||||
/* Set the key */
|
||||
|
||||
/* TODO(3.0): Terrible name. Needs a non TLS specific name */
|
||||
penclen = EVP_PKEY_get1_tls_encodedpoint(pkey, &penc);
|
||||
ASN1_STRING_set0(pubkey, penc, penclen);
|
||||
pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
|
||||
pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
|
||||
|
||||
penc = NULL;
|
||||
X509_ALGOR_set0(talg, OBJ_nid2obj(NID_X9_62_id_ecPublicKey),
|
||||
V_ASN1_UNDEF, NULL);
|
||||
}
|
||||
|
||||
/* See if custom parameters set */
|
||||
kdf_type = EVP_PKEY_CTX_get_ecdh_kdf_type(pctx);
|
||||
if (kdf_type <= 0)
|
||||
goto err;
|
||||
if (!EVP_PKEY_CTX_get_ecdh_kdf_md(pctx, &kdf_md))
|
||||
goto err;
|
||||
ecdh_nid = EVP_PKEY_CTX_get_ecdh_cofactor_mode(pctx);
|
||||
if (ecdh_nid < 0)
|
||||
goto err;
|
||||
else if (ecdh_nid == 0)
|
||||
ecdh_nid = NID_dh_std_kdf;
|
||||
else if (ecdh_nid == 1)
|
||||
ecdh_nid = NID_dh_cofactor_kdf;
|
||||
|
||||
if (kdf_type == EVP_PKEY_ECDH_KDF_NONE) {
|
||||
kdf_type = EVP_PKEY_ECDH_KDF_X9_63;
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, kdf_type) <= 0)
|
||||
goto err;
|
||||
} else
|
||||
/* Unknown KDF */
|
||||
goto err;
|
||||
if (kdf_md == NULL) {
|
||||
/* Fixme later for better MD */
|
||||
kdf_md = EVP_sha1();
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
|
||||
goto err;
|
||||
|
||||
/* Lookup NID for KDF+cofactor+digest */
|
||||
|
||||
if (!OBJ_find_sigid_by_algs(&kdf_nid, EVP_MD_type(kdf_md), ecdh_nid))
|
||||
goto err;
|
||||
/* Get wrap NID */
|
||||
ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
||||
wrap_nid = EVP_CIPHER_CTX_type(ctx);
|
||||
keylen = EVP_CIPHER_CTX_key_length(ctx);
|
||||
|
||||
/* Package wrap algorithm in an AlgorithmIdentifier */
|
||||
|
||||
wrap_alg = X509_ALGOR_new();
|
||||
if (wrap_alg == NULL)
|
||||
goto err;
|
||||
wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
|
||||
wrap_alg->parameter = ASN1_TYPE_new();
|
||||
if (wrap_alg->parameter == NULL)
|
||||
goto err;
|
||||
if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
|
||||
goto err;
|
||||
if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
|
||||
ASN1_TYPE_free(wrap_alg->parameter);
|
||||
wrap_alg->parameter = NULL;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
|
||||
goto err;
|
||||
|
||||
penclen = CMS_SharedInfo_encode(&penc, wrap_alg, ukm, keylen);
|
||||
|
||||
if (!penclen)
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, penc, penclen) <= 0)
|
||||
goto err;
|
||||
penc = NULL;
|
||||
|
||||
/*
|
||||
* Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
|
||||
* of another AlgorithmIdentifier.
|
||||
*/
|
||||
penclen = i2d_X509_ALGOR(wrap_alg, &penc);
|
||||
if (!penc || !penclen)
|
||||
goto err;
|
||||
wrap_str = ASN1_STRING_new();
|
||||
if (wrap_str == NULL)
|
||||
goto err;
|
||||
ASN1_STRING_set0(wrap_str, penc, penclen);
|
||||
penc = NULL;
|
||||
X509_ALGOR_set0(talg, OBJ_nid2obj(kdf_nid), V_ASN1_SEQUENCE, wrap_str);
|
||||
|
||||
rv = 1;
|
||||
|
||||
err:
|
||||
OPENSSL_free(penc);
|
||||
X509_ALGOR_free(wrap_alg);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int cms_ecdh_envelope(CMS_RecipientInfo *ri, int decrypt)
|
||||
{
|
||||
if (decrypt == 1)
|
||||
return ecdh_cms_decrypt(ri);
|
||||
else if (decrypt == 0)
|
||||
return ecdh_cms_encrypt(ri);
|
||||
|
||||
CMSerr(0, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
|
||||
return 0;
|
||||
}
|
@ -115,6 +115,15 @@ int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
|
||||
return 0;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (EVP_PKEY_is_a(pkey, "DHX"))
|
||||
return cms_dh_envelope(ri, cmd);
|
||||
else if (EVP_PKEY_is_a(pkey, "EC"))
|
||||
return cms_ecdh_envelope(ri, cmd);
|
||||
else if (EVP_PKEY_is_a(pkey, "RSA"))
|
||||
return cms_rsa_envelope(ri, cmd);
|
||||
|
||||
/* Something else? We'll give engines etc a chance to handle this */
|
||||
if (pkey->ameth == NULL || pkey->ameth->pkey_ctrl == NULL)
|
||||
return 1;
|
||||
i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_ENVELOPE, cmd, ri);
|
||||
|
@ -47,6 +47,7 @@ static const ERR_STRING_DATA CMS_str_reasons[] = {
|
||||
"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_DECODE_ERROR), "decode error"},
|
||||
{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"},
|
||||
@ -64,6 +65,11 @@ static const ERR_STRING_DATA CMS_str_reasons[] = {
|
||||
{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_INVALID_LABEL), "invalid label"},
|
||||
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_INVALID_OAEP_PARAMETERS),
|
||||
"invalid oaep parameters"},
|
||||
{ERR_PACK(ERR_LIB_CMS, 0, CMS_R_KDF_PARAMETER_ERROR),
|
||||
"kdf parameter error"},
|
||||
{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"},
|
||||
@ -102,11 +108,13 @@ static const ERR_STRING_DATA CMS_str_reasons[] = {
|
||||
{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_PEER_KEY_ERROR), "peer key error"},
|
||||
{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_SHARED_INFO_ERROR), "shared info 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"},
|
||||
@ -131,10 +139,14 @@ static const ERR_STRING_DATA CMS_str_reasons[] = {
|
||||
"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_ENCRYPTION_TYPE),
|
||||
"unsupported encryption 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_LABEL_SOURCE),
|
||||
"unsupported label source"},
|
||||
{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),
|
||||
|
@ -471,6 +471,10 @@ void cms_SignerInfos_set_cmsctx(CMS_ContentInfo *cms);
|
||||
/* ESS routines */
|
||||
int ess_check_signing_certs(CMS_SignerInfo *si, STACK_OF(X509) *chain);
|
||||
|
||||
int cms_dh_envelope(CMS_RecipientInfo *ri, int decrypt);
|
||||
int cms_ecdh_envelope(CMS_RecipientInfo *ri, int decrypt);
|
||||
int cms_rsa_envelope(CMS_RecipientInfo *ri, int decrypt);
|
||||
|
||||
DECLARE_ASN1_ITEM(CMS_CertificateChoices)
|
||||
DECLARE_ASN1_ITEM(CMS_DigestedData)
|
||||
DECLARE_ASN1_ITEM(CMS_EncryptedData)
|
||||
|
182
crypto/cms/cms_rsa.c
Normal file
182
crypto/cms/cms_rsa.c
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (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>
|
||||
#include "crypto/asn1.h"
|
||||
#include "cms_local.h"
|
||||
|
||||
|
||||
static RSA_OAEP_PARAMS *rsa_oaep_decode(const X509_ALGOR *alg)
|
||||
{
|
||||
RSA_OAEP_PARAMS *oaep;
|
||||
|
||||
oaep = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(RSA_OAEP_PARAMS),
|
||||
alg->parameter);
|
||||
|
||||
if (oaep == NULL)
|
||||
return NULL;
|
||||
|
||||
if (oaep->maskGenFunc != NULL) {
|
||||
oaep->maskHash = x509_algor_mgf1_decode(oaep->maskGenFunc);
|
||||
if (oaep->maskHash == NULL) {
|
||||
RSA_OAEP_PARAMS_free(oaep);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return oaep;
|
||||
}
|
||||
|
||||
static int rsa_cms_decrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pkctx;
|
||||
X509_ALGOR *cmsalg;
|
||||
int nid;
|
||||
int rv = -1;
|
||||
unsigned char *label = NULL;
|
||||
int labellen = 0;
|
||||
const EVP_MD *mgf1md = NULL, *md = NULL;
|
||||
RSA_OAEP_PARAMS *oaep;
|
||||
|
||||
pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
if (pkctx == NULL)
|
||||
return 0;
|
||||
if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg))
|
||||
return -1;
|
||||
nid = OBJ_obj2nid(cmsalg->algorithm);
|
||||
if (nid == NID_rsaEncryption)
|
||||
return 1;
|
||||
if (nid != NID_rsaesOaep) {
|
||||
CMSerr(0, CMS_R_UNSUPPORTED_ENCRYPTION_TYPE);
|
||||
return -1;
|
||||
}
|
||||
/* Decode OAEP parameters */
|
||||
oaep = rsa_oaep_decode(cmsalg);
|
||||
|
||||
if (oaep == NULL) {
|
||||
CMSerr(0, CMS_R_INVALID_OAEP_PARAMETERS);
|
||||
goto err;
|
||||
}
|
||||
|
||||
mgf1md = x509_algor_get_md(oaep->maskHash);
|
||||
if (mgf1md == NULL)
|
||||
goto err;
|
||||
md = x509_algor_get_md(oaep->hashFunc);
|
||||
if (md == NULL)
|
||||
goto err;
|
||||
|
||||
if (oaep->pSourceFunc != NULL) {
|
||||
X509_ALGOR *plab = oaep->pSourceFunc;
|
||||
|
||||
if (OBJ_obj2nid(plab->algorithm) != NID_pSpecified) {
|
||||
CMSerr(0, CMS_R_UNSUPPORTED_LABEL_SOURCE);
|
||||
goto err;
|
||||
}
|
||||
if (plab->parameter->type != V_ASN1_OCTET_STRING) {
|
||||
CMSerr(0, CMS_R_INVALID_LABEL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
label = plab->parameter->value.octet_string->data;
|
||||
/* Stop label being freed when OAEP parameters are freed */
|
||||
plab->parameter->value.octet_string->data = NULL;
|
||||
labellen = plab->parameter->value.octet_string->length;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, md) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0)
|
||||
goto err;
|
||||
if (label != NULL
|
||||
&& EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, label, labellen) <= 0)
|
||||
goto err;
|
||||
/* Carry on */
|
||||
rv = 1;
|
||||
|
||||
err:
|
||||
RSA_OAEP_PARAMS_free(oaep);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int rsa_cms_encrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
const EVP_MD *md, *mgf1md;
|
||||
RSA_OAEP_PARAMS *oaep = NULL;
|
||||
ASN1_STRING *os = NULL;
|
||||
X509_ALGOR *alg;
|
||||
EVP_PKEY_CTX *pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
int pad_mode = RSA_PKCS1_PADDING, rv = 0, labellen;
|
||||
unsigned char *label;
|
||||
|
||||
if (CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg) <= 0)
|
||||
return 0;
|
||||
if (pkctx) {
|
||||
if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
|
||||
return 0;
|
||||
}
|
||||
if (pad_mode == RSA_PKCS1_PADDING) {
|
||||
X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
/* Not supported */
|
||||
if (pad_mode != RSA_PKCS1_OAEP_PADDING)
|
||||
return 0;
|
||||
if (EVP_PKEY_CTX_get_rsa_oaep_md(pkctx, &md) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0)
|
||||
goto err;
|
||||
labellen = EVP_PKEY_CTX_get0_rsa_oaep_label(pkctx, &label);
|
||||
if (labellen < 0)
|
||||
goto err;
|
||||
oaep = RSA_OAEP_PARAMS_new();
|
||||
if (oaep == NULL)
|
||||
goto err;
|
||||
if (!x509_algor_new_from_md(&oaep->hashFunc, md))
|
||||
goto err;
|
||||
if (!x509_algor_md_to_mgf1(&oaep->maskGenFunc, mgf1md))
|
||||
goto err;
|
||||
if (labellen > 0) {
|
||||
ASN1_OCTET_STRING *los;
|
||||
oaep->pSourceFunc = X509_ALGOR_new();
|
||||
if (oaep->pSourceFunc == NULL)
|
||||
goto err;
|
||||
los = ASN1_OCTET_STRING_new();
|
||||
if (los == NULL)
|
||||
goto err;
|
||||
if (!ASN1_OCTET_STRING_set(los, label, labellen)) {
|
||||
ASN1_OCTET_STRING_free(los);
|
||||
goto err;
|
||||
}
|
||||
X509_ALGOR_set0(oaep->pSourceFunc, OBJ_nid2obj(NID_pSpecified),
|
||||
V_ASN1_OCTET_STRING, los);
|
||||
}
|
||||
/* create string with pss parameter encoding. */
|
||||
if (!ASN1_item_pack(oaep, ASN1_ITEM_rptr(RSA_OAEP_PARAMS), &os))
|
||||
goto err;
|
||||
X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaesOaep), V_ASN1_SEQUENCE, os);
|
||||
os = NULL;
|
||||
rv = 1;
|
||||
err:
|
||||
RSA_OAEP_PARAMS_free(oaep);
|
||||
ASN1_STRING_free(os);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int cms_rsa_envelope(CMS_RecipientInfo *ri, int decrypt)
|
||||
{
|
||||
if (decrypt == 1)
|
||||
return rsa_cms_decrypt(ri);
|
||||
else if (decrypt == 0)
|
||||
return rsa_cms_encrypt(ri);
|
||||
|
||||
CMSerr(0, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
|
||||
return 0;
|
||||
}
|
@ -14,18 +14,18 @@
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include "dh_local.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/cms.h>
|
||||
#include "internal/ffc.h"
|
||||
#include "internal/cryptlib.h"
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/dh.h"
|
||||
#include "crypto/evp.h"
|
||||
#include <openssl/cms.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/param_build.h>
|
||||
#include "internal/ffc.h"
|
||||
#include "dh_local.h"
|
||||
|
||||
/*
|
||||
* i2d/d2i like DH parameter functions which use the appropriate routine for
|
||||
@ -434,11 +434,6 @@ int DHparams_print(BIO *bp, const DH *x)
|
||||
return do_dh_print(bp, x, 4, 0);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_CMS
|
||||
static int dh_cms_decrypt(CMS_RecipientInfo *ri);
|
||||
static int dh_cms_encrypt(CMS_RecipientInfo *ri);
|
||||
#endif
|
||||
|
||||
static int dh_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
|
||||
{
|
||||
switch (op) {
|
||||
@ -455,14 +450,6 @@ static int dhx_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
|
||||
{
|
||||
switch (op) {
|
||||
#ifndef OPENSSL_NO_CMS
|
||||
|
||||
case ASN1_PKEY_CTRL_CMS_ENVELOPE:
|
||||
if (arg1 == 1)
|
||||
return dh_cms_decrypt(arg2);
|
||||
else if (arg1 == 0)
|
||||
return dh_cms_encrypt(arg2);
|
||||
return -2;
|
||||
|
||||
case ASN1_PKEY_CTRL_CMS_RI_TYPE:
|
||||
*(int *)arg2 = CMS_RECIPINFO_AGREE;
|
||||
return 1;
|
||||
@ -675,308 +662,3 @@ const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = {
|
||||
dh_pkey_export_to,
|
||||
dhx_pkey_import_from,
|
||||
};
|
||||
|
||||
#ifndef OPENSSL_NO_CMS
|
||||
|
||||
static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
|
||||
X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
|
||||
{
|
||||
const ASN1_OBJECT *aoid;
|
||||
int atype;
|
||||
const void *aval;
|
||||
ASN1_INTEGER *public_key = NULL;
|
||||
int rv = 0;
|
||||
EVP_PKEY *pkpeer = NULL, *pk = NULL;
|
||||
DH *dhpeer = NULL;
|
||||
const unsigned char *p;
|
||||
int plen;
|
||||
|
||||
X509_ALGOR_get0(&aoid, &atype, &aval, alg);
|
||||
if (OBJ_obj2nid(aoid) != NID_dhpublicnumber)
|
||||
goto err;
|
||||
/* Only absent parameters allowed in RFC XXXX */
|
||||
if (atype != V_ASN1_UNDEF && atype == V_ASN1_NULL)
|
||||
goto err;
|
||||
|
||||
pk = EVP_PKEY_CTX_get0_pkey(pctx);
|
||||
if (pk == NULL)
|
||||
goto err;
|
||||
if (pk->type != EVP_PKEY_DHX)
|
||||
goto err;
|
||||
/* Get parameters from parent key */
|
||||
dhpeer = DHparams_dup(pk->pkey.dh);
|
||||
/* We have parameters now set public key */
|
||||
plen = ASN1_STRING_length(pubkey);
|
||||
p = ASN1_STRING_get0_data(pubkey);
|
||||
if (p == NULL || plen == 0)
|
||||
goto err;
|
||||
|
||||
if ((public_key = d2i_ASN1_INTEGER(NULL, &p, plen)) == NULL) {
|
||||
DHerr(DH_F_DH_CMS_SET_PEERKEY, DH_R_DECODE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* We have parameters now set public key */
|
||||
if ((dhpeer->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) {
|
||||
DHerr(DH_F_DH_CMS_SET_PEERKEY, DH_R_BN_DECODE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
pkpeer = EVP_PKEY_new();
|
||||
if (pkpeer == NULL)
|
||||
goto err;
|
||||
EVP_PKEY_assign(pkpeer, pk->ameth->pkey_id, dhpeer);
|
||||
dhpeer = NULL;
|
||||
if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
|
||||
rv = 1;
|
||||
err:
|
||||
ASN1_INTEGER_free(public_key);
|
||||
EVP_PKEY_free(pkpeer);
|
||||
DH_free(dhpeer);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
X509_ALGOR *alg, *kekalg = NULL;
|
||||
ASN1_OCTET_STRING *ukm;
|
||||
const unsigned char *p;
|
||||
unsigned char *dukm = NULL;
|
||||
size_t dukmlen = 0;
|
||||
int keylen, plen;
|
||||
const EVP_CIPHER *kekcipher;
|
||||
EVP_CIPHER_CTX *kekctx;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* For DH we only have one OID permissible. If ever any more get defined
|
||||
* we will need something cleverer.
|
||||
*/
|
||||
if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) {
|
||||
DHerr(DH_F_DH_CMS_SET_SHARED_INFO, DH_R_KDF_PARAMETER_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0)
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0)
|
||||
goto err;
|
||||
|
||||
if (alg->parameter->type != V_ASN1_SEQUENCE)
|
||||
goto err;
|
||||
|
||||
p = alg->parameter->value.sequence->data;
|
||||
plen = alg->parameter->value.sequence->length;
|
||||
kekalg = d2i_X509_ALGOR(NULL, &p, plen);
|
||||
if (!kekalg)
|
||||
goto err;
|
||||
kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
||||
if (!kekctx)
|
||||
goto err;
|
||||
kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
|
||||
if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
|
||||
goto err;
|
||||
if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
|
||||
goto err;
|
||||
if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
|
||||
goto err;
|
||||
|
||||
keylen = EVP_CIPHER_CTX_key_length(kekctx);
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
|
||||
goto err;
|
||||
/* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */
|
||||
if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx,
|
||||
OBJ_nid2obj(EVP_CIPHER_type(kekcipher)))
|
||||
<= 0)
|
||||
goto err;
|
||||
|
||||
if (ukm) {
|
||||
dukmlen = ASN1_STRING_length(ukm);
|
||||
dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
|
||||
if (!dukm)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
|
||||
goto err;
|
||||
dukm = NULL;
|
||||
|
||||
rv = 1;
|
||||
err:
|
||||
X509_ALGOR_free(kekalg);
|
||||
OPENSSL_free(dukm);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int dh_cms_decrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx;
|
||||
|
||||
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
|
||||
if (pctx == NULL)
|
||||
return 0;
|
||||
/* See if we need to set peer key */
|
||||
if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
|
||||
X509_ALGOR *alg;
|
||||
ASN1_BIT_STRING *pubkey;
|
||||
if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
|
||||
NULL, NULL, NULL))
|
||||
return 0;
|
||||
if (!alg || !pubkey)
|
||||
return 0;
|
||||
if (!dh_cms_set_peerkey(pctx, alg, pubkey)) {
|
||||
DHerr(DH_F_DH_CMS_DECRYPT, DH_R_PEER_KEY_ERROR);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Set DH derivation parameters and initialise unwrap context */
|
||||
if (!dh_cms_set_shared_info(pctx, ri)) {
|
||||
DHerr(DH_F_DH_CMS_DECRYPT, DH_R_SHARED_INFO_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dh_cms_encrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx;
|
||||
EVP_PKEY *pkey;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
int keylen;
|
||||
X509_ALGOR *talg, *wrap_alg = NULL;
|
||||
const ASN1_OBJECT *aoid;
|
||||
ASN1_BIT_STRING *pubkey;
|
||||
ASN1_STRING *wrap_str;
|
||||
ASN1_OCTET_STRING *ukm;
|
||||
unsigned char *penc = NULL, *dukm = NULL;
|
||||
int penclen;
|
||||
size_t dukmlen = 0;
|
||||
int rv = 0;
|
||||
int kdf_type, wrap_nid;
|
||||
const EVP_MD *kdf_md;
|
||||
|
||||
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
if (pctx == NULL)
|
||||
return 0;
|
||||
/* Get ephemeral key */
|
||||
pkey = EVP_PKEY_CTX_get0_pkey(pctx);
|
||||
if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
|
||||
NULL, NULL, NULL))
|
||||
goto err;
|
||||
X509_ALGOR_get0(&aoid, NULL, NULL, talg);
|
||||
/* Is everything uninitialised? */
|
||||
if (aoid == OBJ_nid2obj(NID_undef)) {
|
||||
ASN1_INTEGER *pubk = BN_to_ASN1_INTEGER(pkey->pkey.dh->pub_key, NULL);
|
||||
|
||||
if (pubk == NULL)
|
||||
goto err;
|
||||
/* Set the key */
|
||||
|
||||
penclen = i2d_ASN1_INTEGER(pubk, &penc);
|
||||
ASN1_INTEGER_free(pubk);
|
||||
if (penclen <= 0)
|
||||
goto err;
|
||||
ASN1_STRING_set0(pubkey, penc, penclen);
|
||||
pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
|
||||
pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
|
||||
|
||||
penc = NULL;
|
||||
X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber),
|
||||
V_ASN1_UNDEF, NULL);
|
||||
}
|
||||
|
||||
/* See if custom parameters set */
|
||||
kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx);
|
||||
if (kdf_type <= 0)
|
||||
goto err;
|
||||
if (!EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md))
|
||||
goto err;
|
||||
|
||||
if (kdf_type == EVP_PKEY_DH_KDF_NONE) {
|
||||
kdf_type = EVP_PKEY_DH_KDF_X9_42;
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0)
|
||||
goto err;
|
||||
} else if (kdf_type != EVP_PKEY_DH_KDF_X9_42)
|
||||
/* Unknown KDF */
|
||||
goto err;
|
||||
if (kdf_md == NULL) {
|
||||
/* Only SHA1 supported */
|
||||
kdf_md = EVP_sha1();
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0)
|
||||
goto err;
|
||||
} else if (EVP_MD_type(kdf_md) != NID_sha1)
|
||||
/* Unsupported digest */
|
||||
goto err;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
|
||||
goto err;
|
||||
|
||||
/* Get wrap NID */
|
||||
ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
||||
wrap_nid = EVP_CIPHER_CTX_type(ctx);
|
||||
if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0)
|
||||
goto err;
|
||||
keylen = EVP_CIPHER_CTX_key_length(ctx);
|
||||
|
||||
/* Package wrap algorithm in an AlgorithmIdentifier */
|
||||
|
||||
wrap_alg = X509_ALGOR_new();
|
||||
if (wrap_alg == NULL)
|
||||
goto err;
|
||||
wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
|
||||
wrap_alg->parameter = ASN1_TYPE_new();
|
||||
if (wrap_alg->parameter == NULL)
|
||||
goto err;
|
||||
if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
|
||||
goto err;
|
||||
if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
|
||||
ASN1_TYPE_free(wrap_alg->parameter);
|
||||
wrap_alg->parameter = NULL;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
|
||||
goto err;
|
||||
|
||||
if (ukm) {
|
||||
dukmlen = ASN1_STRING_length(ukm);
|
||||
dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
|
||||
if (!dukm)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
|
||||
goto err;
|
||||
dukm = NULL;
|
||||
|
||||
/*
|
||||
* Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
|
||||
* of another AlgorithmIdentifier.
|
||||
*/
|
||||
penc = NULL;
|
||||
penclen = i2d_X509_ALGOR(wrap_alg, &penc);
|
||||
if (penc == NULL || penclen == 0)
|
||||
goto err;
|
||||
wrap_str = ASN1_STRING_new();
|
||||
if (wrap_str == NULL)
|
||||
goto err;
|
||||
ASN1_STRING_set0(wrap_str, penc, penclen);
|
||||
penc = NULL;
|
||||
X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH),
|
||||
V_ASN1_SEQUENCE, wrap_str);
|
||||
|
||||
rv = 1;
|
||||
|
||||
err:
|
||||
OPENSSL_free(penc);
|
||||
X509_ALGOR_free(wrap_alg);
|
||||
OPENSSL_free(dukm);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -27,11 +27,6 @@
|
||||
#include "openssl/param_build.h"
|
||||
#include "ec_local.h"
|
||||
|
||||
#ifndef OPENSSL_NO_CMS
|
||||
static int ecdh_cms_decrypt(CMS_RecipientInfo *ri);
|
||||
static int ecdh_cms_encrypt(CMS_RecipientInfo *ri);
|
||||
#endif
|
||||
|
||||
static int eckey_param2type(int *pptype, void **ppval, const EC_KEY *ec_key)
|
||||
{
|
||||
const EC_GROUP *group;
|
||||
@ -511,13 +506,6 @@ static int ec_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
|
||||
}
|
||||
return 1;
|
||||
|
||||
case ASN1_PKEY_CTRL_CMS_ENVELOPE:
|
||||
if (arg1 == 1)
|
||||
return ecdh_cms_decrypt(arg2);
|
||||
else if (arg1 == 0)
|
||||
return ecdh_cms_encrypt(arg2);
|
||||
return -2;
|
||||
|
||||
case ASN1_PKEY_CTRL_CMS_RI_TYPE:
|
||||
*(int *)arg2 = CMS_RECIPINFO_AGREE;
|
||||
return 1;
|
||||
@ -828,327 +816,3 @@ int ECParameters_print(BIO *bp, const EC_KEY *x)
|
||||
{
|
||||
return do_EC_KEY_print(bp, x, 4, EC_KEY_PRINT_PARAM);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_CMS
|
||||
|
||||
static int ecdh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
|
||||
X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
|
||||
{
|
||||
const ASN1_OBJECT *aoid;
|
||||
int atype;
|
||||
const void *aval;
|
||||
int rv = 0;
|
||||
EVP_PKEY *pkpeer = NULL;
|
||||
EC_KEY *ecpeer = NULL;
|
||||
const unsigned char *p;
|
||||
int plen;
|
||||
|
||||
X509_ALGOR_get0(&aoid, &atype, &aval, alg);
|
||||
if (OBJ_obj2nid(aoid) != NID_X9_62_id_ecPublicKey)
|
||||
goto err;
|
||||
/* If absent parameters get group from main key */
|
||||
if (atype == V_ASN1_UNDEF || atype == V_ASN1_NULL) {
|
||||
const EC_GROUP *grp;
|
||||
EVP_PKEY *pk;
|
||||
pk = EVP_PKEY_CTX_get0_pkey(pctx);
|
||||
if (pk == NULL)
|
||||
goto err;
|
||||
grp = EC_KEY_get0_group(pk->pkey.ec);
|
||||
ecpeer = EC_KEY_new();
|
||||
if (ecpeer == NULL)
|
||||
goto err;
|
||||
if (!EC_KEY_set_group(ecpeer, grp))
|
||||
goto err;
|
||||
} else {
|
||||
ecpeer = eckey_type2param(atype, aval, pctx->libctx, pctx->propquery);
|
||||
if (!ecpeer)
|
||||
goto err;
|
||||
}
|
||||
/* We have parameters now set public key */
|
||||
plen = ASN1_STRING_length(pubkey);
|
||||
p = ASN1_STRING_get0_data(pubkey);
|
||||
if (p == NULL || plen == 0)
|
||||
goto err;
|
||||
if (!o2i_ECPublicKey(&ecpeer, &p, plen))
|
||||
goto err;
|
||||
pkpeer = EVP_PKEY_new();
|
||||
if (pkpeer == NULL)
|
||||
goto err;
|
||||
EVP_PKEY_set1_EC_KEY(pkpeer, ecpeer);
|
||||
if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
|
||||
rv = 1;
|
||||
err:
|
||||
EC_KEY_free(ecpeer);
|
||||
EVP_PKEY_free(pkpeer);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Set KDF parameters based on KDF NID */
|
||||
static int ecdh_cms_set_kdf_param(EVP_PKEY_CTX *pctx, int eckdf_nid)
|
||||
{
|
||||
int kdf_nid, kdfmd_nid, cofactor;
|
||||
const EVP_MD *kdf_md;
|
||||
if (eckdf_nid == NID_undef)
|
||||
return 0;
|
||||
|
||||
/* Lookup KDF type, cofactor mode and digest */
|
||||
if (!OBJ_find_sigid_algs(eckdf_nid, &kdfmd_nid, &kdf_nid))
|
||||
return 0;
|
||||
|
||||
if (kdf_nid == NID_dh_std_kdf)
|
||||
cofactor = 0;
|
||||
else if (kdf_nid == NID_dh_cofactor_kdf)
|
||||
cofactor = 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (EVP_PKEY_CTX_set_ecdh_cofactor_mode(pctx, cofactor) <= 0)
|
||||
return 0;
|
||||
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, EVP_PKEY_ECDH_KDF_X9_63) <= 0)
|
||||
return 0;
|
||||
|
||||
kdf_md = EVP_get_digestbynid(kdfmd_nid);
|
||||
if (!kdf_md)
|
||||
return 0;
|
||||
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
X509_ALGOR *alg, *kekalg = NULL;
|
||||
ASN1_OCTET_STRING *ukm;
|
||||
const unsigned char *p;
|
||||
unsigned char *der = NULL;
|
||||
int plen, keylen;
|
||||
EVP_CIPHER *kekcipher = NULL;
|
||||
EVP_CIPHER_CTX *kekctx;
|
||||
const char *name;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
|
||||
return 0;
|
||||
|
||||
if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) {
|
||||
ECerr(EC_F_ECDH_CMS_SET_SHARED_INFO, EC_R_KDF_PARAMETER_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (alg->parameter->type != V_ASN1_SEQUENCE)
|
||||
return 0;
|
||||
|
||||
p = alg->parameter->value.sequence->data;
|
||||
plen = alg->parameter->value.sequence->length;
|
||||
kekalg = d2i_X509_ALGOR(NULL, &p, plen);
|
||||
if (kekalg == NULL)
|
||||
goto err;
|
||||
kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
||||
if (kekctx == NULL)
|
||||
goto err;
|
||||
name = OBJ_nid2sn(OBJ_obj2nid(kekalg->algorithm));
|
||||
kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery);
|
||||
if (kekcipher == NULL || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
|
||||
goto err;
|
||||
if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
|
||||
goto err;
|
||||
if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
|
||||
goto err;
|
||||
|
||||
keylen = EVP_CIPHER_CTX_key_length(kekctx);
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
|
||||
goto err;
|
||||
|
||||
plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen);
|
||||
|
||||
if (plen <= 0)
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0)
|
||||
goto err;
|
||||
der = NULL;
|
||||
|
||||
rv = 1;
|
||||
err:
|
||||
EVP_CIPHER_free(kekcipher);
|
||||
X509_ALGOR_free(kekalg);
|
||||
OPENSSL_free(der);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ecdh_cms_decrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx;
|
||||
|
||||
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
if (pctx == NULL)
|
||||
return 0;
|
||||
/* See if we need to set peer key */
|
||||
if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
|
||||
X509_ALGOR *alg;
|
||||
ASN1_BIT_STRING *pubkey;
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
|
||||
NULL, NULL, NULL))
|
||||
return 0;
|
||||
if (!alg || !pubkey)
|
||||
return 0;
|
||||
if (!ecdh_cms_set_peerkey(pctx, alg, pubkey)) {
|
||||
ECerr(EC_F_ECDH_CMS_DECRYPT, EC_R_PEER_KEY_ERROR);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Set ECDH derivation parameters and initialise unwrap context */
|
||||
if (!ecdh_cms_set_shared_info(pctx, ri)) {
|
||||
ECerr(EC_F_ECDH_CMS_DECRYPT, EC_R_SHARED_INFO_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecdh_cms_encrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pctx;
|
||||
EVP_PKEY *pkey;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
int keylen;
|
||||
X509_ALGOR *talg, *wrap_alg = NULL;
|
||||
const ASN1_OBJECT *aoid;
|
||||
ASN1_BIT_STRING *pubkey;
|
||||
ASN1_STRING *wrap_str;
|
||||
ASN1_OCTET_STRING *ukm;
|
||||
unsigned char *penc = NULL;
|
||||
int penclen;
|
||||
int rv = 0;
|
||||
int ecdh_nid, kdf_type, kdf_nid, wrap_nid;
|
||||
const EVP_MD *kdf_md;
|
||||
|
||||
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
if (pctx == NULL)
|
||||
return 0;
|
||||
/* Get ephemeral key */
|
||||
pkey = EVP_PKEY_CTX_get0_pkey(pctx);
|
||||
if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
|
||||
NULL, NULL, NULL))
|
||||
goto err;
|
||||
X509_ALGOR_get0(&aoid, NULL, NULL, talg);
|
||||
/* Is everything uninitialised? */
|
||||
if (aoid == OBJ_nid2obj(NID_undef)) {
|
||||
|
||||
EC_KEY *eckey = pkey->pkey.ec;
|
||||
/* Set the key */
|
||||
unsigned char *p;
|
||||
|
||||
penclen = i2o_ECPublicKey(eckey, NULL);
|
||||
if (penclen <= 0)
|
||||
goto err;
|
||||
penc = OPENSSL_malloc(penclen);
|
||||
if (penc == NULL)
|
||||
goto err;
|
||||
p = penc;
|
||||
penclen = i2o_ECPublicKey(eckey, &p);
|
||||
if (penclen <= 0)
|
||||
goto err;
|
||||
ASN1_STRING_set0(pubkey, penc, penclen);
|
||||
pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
|
||||
pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
|
||||
|
||||
penc = NULL;
|
||||
X509_ALGOR_set0(talg, OBJ_nid2obj(NID_X9_62_id_ecPublicKey),
|
||||
V_ASN1_UNDEF, NULL);
|
||||
}
|
||||
|
||||
/* See if custom parameters set */
|
||||
kdf_type = EVP_PKEY_CTX_get_ecdh_kdf_type(pctx);
|
||||
if (kdf_type <= 0)
|
||||
goto err;
|
||||
if (!EVP_PKEY_CTX_get_ecdh_kdf_md(pctx, &kdf_md))
|
||||
goto err;
|
||||
ecdh_nid = EVP_PKEY_CTX_get_ecdh_cofactor_mode(pctx);
|
||||
if (ecdh_nid < 0)
|
||||
goto err;
|
||||
else if (ecdh_nid == 0)
|
||||
ecdh_nid = NID_dh_std_kdf;
|
||||
else if (ecdh_nid == 1)
|
||||
ecdh_nid = NID_dh_cofactor_kdf;
|
||||
|
||||
if (kdf_type == EVP_PKEY_ECDH_KDF_NONE) {
|
||||
kdf_type = EVP_PKEY_ECDH_KDF_X9_63;
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, kdf_type) <= 0)
|
||||
goto err;
|
||||
} else
|
||||
/* Unknown KDF */
|
||||
goto err;
|
||||
if (kdf_md == NULL) {
|
||||
/* Fixme later for better MD */
|
||||
kdf_md = EVP_sha1();
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
|
||||
goto err;
|
||||
|
||||
/* Lookup NID for KDF+cofactor+digest */
|
||||
|
||||
if (!OBJ_find_sigid_by_algs(&kdf_nid, EVP_MD_type(kdf_md), ecdh_nid))
|
||||
goto err;
|
||||
/* Get wrap NID */
|
||||
ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
|
||||
wrap_nid = EVP_CIPHER_CTX_type(ctx);
|
||||
keylen = EVP_CIPHER_CTX_key_length(ctx);
|
||||
|
||||
/* Package wrap algorithm in an AlgorithmIdentifier */
|
||||
|
||||
wrap_alg = X509_ALGOR_new();
|
||||
if (wrap_alg == NULL)
|
||||
goto err;
|
||||
wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
|
||||
wrap_alg->parameter = ASN1_TYPE_new();
|
||||
if (wrap_alg->parameter == NULL)
|
||||
goto err;
|
||||
if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
|
||||
goto err;
|
||||
if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
|
||||
ASN1_TYPE_free(wrap_alg->parameter);
|
||||
wrap_alg->parameter = NULL;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0)
|
||||
goto err;
|
||||
|
||||
penclen = CMS_SharedInfo_encode(&penc, wrap_alg, ukm, keylen);
|
||||
|
||||
if (!penclen)
|
||||
goto err;
|
||||
|
||||
if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, penc, penclen) <= 0)
|
||||
goto err;
|
||||
penc = NULL;
|
||||
|
||||
/*
|
||||
* Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
|
||||
* of another AlgorithmIdentifier.
|
||||
*/
|
||||
penclen = i2d_X509_ALGOR(wrap_alg, &penc);
|
||||
if (!penc || !penclen)
|
||||
goto err;
|
||||
wrap_str = ASN1_STRING_new();
|
||||
if (wrap_str == NULL)
|
||||
goto err;
|
||||
ASN1_STRING_set0(wrap_str, penc, penclen);
|
||||
penc = NULL;
|
||||
X509_ALGOR_set0(talg, OBJ_nid2obj(kdf_nid), V_ASN1_SEQUENCE, wrap_str);
|
||||
|
||||
rv = 1;
|
||||
|
||||
err:
|
||||
OPENSSL_free(penc);
|
||||
X509_ALGOR_free(wrap_alg);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1996,6 +1996,7 @@ ASN1_R_TYPE_NOT_CONSTRUCTED:156:type not constructed
|
||||
ASN1_R_TYPE_NOT_PRIMITIVE:195:type not primitive
|
||||
ASN1_R_UNEXPECTED_EOC:159:unexpected eoc
|
||||
ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH:215:universalstring is wrong length
|
||||
ASN1_R_UNKNOWN_DIGEST:229:unknown digest
|
||||
ASN1_R_UNKNOWN_FORMAT:160:unknown format
|
||||
ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM:161:unknown message digest algorithm
|
||||
ASN1_R_UNKNOWN_OBJECT_TYPE:162:unknown object type
|
||||
@ -2181,6 +2182,7 @@ CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA:108:content type not signed data
|
||||
CMS_R_CONTENT_VERIFY_ERROR:109:content verify error
|
||||
CMS_R_CTRL_ERROR:110:ctrl error
|
||||
CMS_R_CTRL_FAILURE:111:ctrl failure
|
||||
CMS_R_DECODE_ERROR:187:decode error
|
||||
CMS_R_DECRYPT_ERROR:112:decrypt error
|
||||
CMS_R_ERROR_GETTING_PUBLIC_KEY:113:error getting public key
|
||||
CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE:114:\
|
||||
@ -2192,6 +2194,9 @@ CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR:183:ess signing certid mismatch error
|
||||
CMS_R_INVALID_ENCRYPTED_KEY_LENGTH:117:invalid encrypted key length
|
||||
CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER:176:invalid key encryption parameter
|
||||
CMS_R_INVALID_KEY_LENGTH:118:invalid key length
|
||||
CMS_R_INVALID_LABEL:190:invalid label
|
||||
CMS_R_INVALID_OAEP_PARAMETERS:191:invalid oaep parameters
|
||||
CMS_R_KDF_PARAMETER_ERROR:186:kdf parameter error
|
||||
CMS_R_MD_BIO_INIT_ERROR:119:md bio init error
|
||||
CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH:120:\
|
||||
messagedigest attribute wrong length
|
||||
@ -2223,10 +2228,12 @@ CMS_R_NO_PRIVATE_KEY:133:no private key
|
||||
CMS_R_NO_PUBLIC_KEY:134:no public key
|
||||
CMS_R_NO_RECEIPT_REQUEST:168:no receipt request
|
||||
CMS_R_NO_SIGNERS:135:no signers
|
||||
CMS_R_PEER_KEY_ERROR:188:peer key error
|
||||
CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE:136:\
|
||||
private key does not match certificate
|
||||
CMS_R_RECEIPT_DECODE_ERROR:169:receipt decode error
|
||||
CMS_R_RECIPIENT_ERROR:137:recipient error
|
||||
CMS_R_SHARED_INFO_ERROR:189:shared info error
|
||||
CMS_R_SIGNER_CERTIFICATE_NOT_FOUND:138:signer certificate not found
|
||||
CMS_R_SIGNFINAL_ERROR:139:signfinal error
|
||||
CMS_R_SMIME_TEXT_ERROR:140:smime text error
|
||||
@ -2242,9 +2249,11 @@ CMS_R_UNKNOWN_DIGEST_ALGORITHM:149:unknown digest algorithm
|
||||
CMS_R_UNKNOWN_ID:150:unknown id
|
||||
CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM:151:unsupported compression algorithm
|
||||
CMS_R_UNSUPPORTED_CONTENT_TYPE:152:unsupported content type
|
||||
CMS_R_UNSUPPORTED_ENCRYPTION_TYPE:192:unsupported encryption type
|
||||
CMS_R_UNSUPPORTED_KEK_ALGORITHM:153:unsupported kek algorithm
|
||||
CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM:179:\
|
||||
unsupported key encryption algorithm
|
||||
CMS_R_UNSUPPORTED_LABEL_SOURCE:193:unsupported label source
|
||||
CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE:155:unsupported recipientinfo type
|
||||
CMS_R_UNSUPPORTED_RECIPIENT_TYPE:154:unsupported recipient type
|
||||
CMS_R_UNSUPPORTED_TYPE:156:unsupported type
|
||||
|
@ -1762,6 +1762,16 @@ int evp_pkey_ctx_use_cached_data(EVP_PKEY_CTX *ctx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
OPENSSL_CTX *evp_pkey_ctx_get0_libctx(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return ctx->libctx;
|
||||
}
|
||||
|
||||
const char *evp_pkey_ctx_get0_propq(EVP_PKEY_CTX *ctx)
|
||||
{
|
||||
return ctx->propquery;
|
||||
}
|
||||
|
||||
/* Utility functions to send a string of hex string to a ctrl */
|
||||
|
||||
int EVP_PKEY_CTX_str2ctrl(EVP_PKEY_CTX *ctx, int cmd, const char *str)
|
||||
|
@ -29,8 +29,6 @@
|
||||
#ifndef OPENSSL_NO_CMS
|
||||
static int rsa_cms_sign(CMS_SignerInfo *si);
|
||||
static int rsa_cms_verify(CMS_SignerInfo *si);
|
||||
static int rsa_cms_decrypt(CMS_RecipientInfo *ri);
|
||||
static int rsa_cms_encrypt(CMS_RecipientInfo *ri);
|
||||
#endif
|
||||
|
||||
static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg);
|
||||
@ -256,14 +254,6 @@ static void int_rsa_free(EVP_PKEY *pkey)
|
||||
RSA_free(pkey->pkey.rsa);
|
||||
}
|
||||
|
||||
static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg)
|
||||
{
|
||||
if (OBJ_obj2nid(alg->algorithm) != NID_mgf1)
|
||||
return NULL;
|
||||
return ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),
|
||||
alg->parameter);
|
||||
}
|
||||
|
||||
static int rsa_pss_param_print(BIO *bp, int pss_key, RSA_PSS_PARAMS *pss,
|
||||
int indent)
|
||||
{
|
||||
@ -315,7 +305,7 @@ static int rsa_pss_param_print(BIO *bp, int pss_key, RSA_PSS_PARAMS *pss,
|
||||
goto err;
|
||||
if (BIO_puts(bp, " with ") <= 0)
|
||||
goto err;
|
||||
maskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
|
||||
maskHash = x509_algor_mgf1_decode(pss->maskGenAlgorithm);
|
||||
if (maskHash != NULL) {
|
||||
if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0)
|
||||
goto err;
|
||||
@ -471,7 +461,7 @@ static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg)
|
||||
return NULL;
|
||||
|
||||
if (pss->maskGenAlgorithm != NULL) {
|
||||
pss->maskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
|
||||
pss->maskHash = x509_algor_mgf1_decode(pss->maskGenAlgorithm);
|
||||
if (pss->maskHash == NULL) {
|
||||
RSA_PSS_PARAMS_free(pss);
|
||||
return NULL;
|
||||
@ -528,15 +518,6 @@ static int rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
|
||||
return rsa_cms_verify(arg2);
|
||||
break;
|
||||
|
||||
case ASN1_PKEY_CTRL_CMS_ENVELOPE:
|
||||
if (pkey_is_pss(pkey))
|
||||
return -2;
|
||||
if (arg1 == 0)
|
||||
return rsa_cms_encrypt(arg2);
|
||||
else if (arg1 == 1)
|
||||
return rsa_cms_decrypt(arg2);
|
||||
break;
|
||||
|
||||
case ASN1_PKEY_CTRL_CMS_RI_TYPE:
|
||||
if (pkey_is_pss(pkey))
|
||||
return -2;
|
||||
@ -570,58 +551,6 @@ static int rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
|
||||
|
||||
}
|
||||
|
||||
/* allocate and set algorithm ID from EVP_MD, default SHA1 */
|
||||
static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md)
|
||||
{
|
||||
if (md == NULL || EVP_MD_type(md) == NID_sha1)
|
||||
return 1;
|
||||
*palg = X509_ALGOR_new();
|
||||
if (*palg == NULL)
|
||||
return 0;
|
||||
X509_ALGOR_set_md(*palg, md);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Allocate and set MGF1 algorithm ID from EVP_MD */
|
||||
static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md)
|
||||
{
|
||||
X509_ALGOR *algtmp = NULL;
|
||||
ASN1_STRING *stmp = NULL;
|
||||
|
||||
*palg = NULL;
|
||||
if (mgf1md == NULL || EVP_MD_type(mgf1md) == NID_sha1)
|
||||
return 1;
|
||||
/* need to embed algorithm ID inside another */
|
||||
if (!rsa_md_to_algor(&algtmp, mgf1md))
|
||||
goto err;
|
||||
if (ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp) == NULL)
|
||||
goto err;
|
||||
*palg = X509_ALGOR_new();
|
||||
if (*palg == NULL)
|
||||
goto err;
|
||||
X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp);
|
||||
stmp = NULL;
|
||||
err:
|
||||
ASN1_STRING_free(stmp);
|
||||
X509_ALGOR_free(algtmp);
|
||||
if (*palg)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* convert algorithm ID to EVP_MD, default SHA1 */
|
||||
static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg)
|
||||
{
|
||||
const EVP_MD *md;
|
||||
|
||||
if (!alg)
|
||||
return EVP_sha1();
|
||||
md = EVP_get_digestbyobj(alg->algorithm);
|
||||
if (md == NULL)
|
||||
RSAerr(RSA_F_RSA_ALGOR_TO_MD, RSA_R_UNKNOWN_DIGEST);
|
||||
return md;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert EVP_PKEY_CTX in PSS mode into corresponding algorithm parameter,
|
||||
* suitable for setting an AlgorithmIdentifier.
|
||||
@ -667,13 +596,13 @@ RSA_PSS_PARAMS *rsa_pss_params_create(const EVP_MD *sigmd,
|
||||
if (!ASN1_INTEGER_set(pss->saltLength, saltlen))
|
||||
goto err;
|
||||
}
|
||||
if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd))
|
||||
if (!x509_algor_new_from_md(&pss->hashAlgorithm, sigmd))
|
||||
goto err;
|
||||
if (mgf1md == NULL)
|
||||
mgf1md = sigmd;
|
||||
if (!rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md))
|
||||
if (!x509_algor_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md))
|
||||
goto err;
|
||||
if (!rsa_md_to_algor(&pss->maskHash, mgf1md))
|
||||
if (!x509_algor_new_from_md(&pss->maskHash, mgf1md))
|
||||
goto err;
|
||||
return pss;
|
||||
err:
|
||||
@ -781,10 +710,10 @@ static int rsa_pss_get_param_unverified(const RSA_PSS_PARAMS *pss,
|
||||
|
||||
if (pss == NULL)
|
||||
return 0;
|
||||
*pmd = rsa_algor_to_md(pss->hashAlgorithm);
|
||||
*pmd = x509_algor_get_md(pss->hashAlgorithm);
|
||||
if (*pmd == NULL)
|
||||
return 0;
|
||||
*pmgf1md = rsa_algor_to_md(pss->maskHash);
|
||||
*pmgf1md = x509_algor_get_md(pss->maskHash);
|
||||
if (*pmgf1md == NULL)
|
||||
return 0;
|
||||
if (pss->saltLength)
|
||||
@ -1013,165 +942,6 @@ static int rsa_sig_info_set(X509_SIG_INFO *siginf, const X509_ALGOR *sigalg,
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_CMS
|
||||
static RSA_OAEP_PARAMS *rsa_oaep_decode(const X509_ALGOR *alg)
|
||||
{
|
||||
RSA_OAEP_PARAMS *oaep;
|
||||
|
||||
oaep = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(RSA_OAEP_PARAMS),
|
||||
alg->parameter);
|
||||
|
||||
if (oaep == NULL)
|
||||
return NULL;
|
||||
|
||||
if (oaep->maskGenFunc != NULL) {
|
||||
oaep->maskHash = rsa_mgf1_decode(oaep->maskGenFunc);
|
||||
if (oaep->maskHash == NULL) {
|
||||
RSA_OAEP_PARAMS_free(oaep);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return oaep;
|
||||
}
|
||||
|
||||
static int rsa_cms_decrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
EVP_PKEY_CTX *pkctx;
|
||||
X509_ALGOR *cmsalg;
|
||||
int nid;
|
||||
int rv = -1;
|
||||
unsigned char *label = NULL;
|
||||
int labellen = 0;
|
||||
const EVP_MD *mgf1md = NULL, *md = NULL;
|
||||
RSA_OAEP_PARAMS *oaep;
|
||||
|
||||
pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
if (pkctx == NULL)
|
||||
return 0;
|
||||
if (!CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &cmsalg))
|
||||
return -1;
|
||||
nid = OBJ_obj2nid(cmsalg->algorithm);
|
||||
if (nid == NID_rsaEncryption)
|
||||
return 1;
|
||||
if (nid != NID_rsaesOaep) {
|
||||
RSAerr(RSA_F_RSA_CMS_DECRYPT, RSA_R_UNSUPPORTED_ENCRYPTION_TYPE);
|
||||
return -1;
|
||||
}
|
||||
/* Decode OAEP parameters */
|
||||
oaep = rsa_oaep_decode(cmsalg);
|
||||
|
||||
if (oaep == NULL) {
|
||||
RSAerr(RSA_F_RSA_CMS_DECRYPT, RSA_R_INVALID_OAEP_PARAMETERS);
|
||||
goto err;
|
||||
}
|
||||
|
||||
mgf1md = rsa_algor_to_md(oaep->maskHash);
|
||||
if (mgf1md == NULL)
|
||||
goto err;
|
||||
md = rsa_algor_to_md(oaep->hashFunc);
|
||||
if (md == NULL)
|
||||
goto err;
|
||||
|
||||
if (oaep->pSourceFunc != NULL) {
|
||||
X509_ALGOR *plab = oaep->pSourceFunc;
|
||||
|
||||
if (OBJ_obj2nid(plab->algorithm) != NID_pSpecified) {
|
||||
RSAerr(RSA_F_RSA_CMS_DECRYPT, RSA_R_UNSUPPORTED_LABEL_SOURCE);
|
||||
goto err;
|
||||
}
|
||||
if (plab->parameter->type != V_ASN1_OCTET_STRING) {
|
||||
RSAerr(RSA_F_RSA_CMS_DECRYPT, RSA_R_INVALID_LABEL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
label = plab->parameter->value.octet_string->data;
|
||||
/* Stop label being freed when OAEP parameters are freed */
|
||||
plab->parameter->value.octet_string->data = NULL;
|
||||
labellen = plab->parameter->value.octet_string->length;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, md) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0)
|
||||
goto err;
|
||||
if (label != NULL
|
||||
&& EVP_PKEY_CTX_set0_rsa_oaep_label(pkctx, label, labellen) <= 0)
|
||||
goto err;
|
||||
/* Carry on */
|
||||
rv = 1;
|
||||
|
||||
err:
|
||||
RSA_OAEP_PARAMS_free(oaep);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int rsa_cms_encrypt(CMS_RecipientInfo *ri)
|
||||
{
|
||||
const EVP_MD *md, *mgf1md;
|
||||
RSA_OAEP_PARAMS *oaep = NULL;
|
||||
ASN1_STRING *os = NULL;
|
||||
X509_ALGOR *alg;
|
||||
EVP_PKEY_CTX *pkctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
|
||||
int pad_mode = RSA_PKCS1_PADDING, rv = 0, labellen;
|
||||
unsigned char *label;
|
||||
|
||||
if (CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg) <= 0)
|
||||
return 0;
|
||||
if (pkctx) {
|
||||
if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0)
|
||||
return 0;
|
||||
}
|
||||
if (pad_mode == RSA_PKCS1_PADDING) {
|
||||
X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
/* Not supported */
|
||||
if (pad_mode != RSA_PKCS1_OAEP_PADDING)
|
||||
return 0;
|
||||
if (EVP_PKEY_CTX_get_rsa_oaep_md(pkctx, &md) <= 0)
|
||||
goto err;
|
||||
if (EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0)
|
||||
goto err;
|
||||
labellen = EVP_PKEY_CTX_get0_rsa_oaep_label(pkctx, &label);
|
||||
if (labellen < 0)
|
||||
goto err;
|
||||
oaep = RSA_OAEP_PARAMS_new();
|
||||
if (oaep == NULL)
|
||||
goto err;
|
||||
if (!rsa_md_to_algor(&oaep->hashFunc, md))
|
||||
goto err;
|
||||
if (!rsa_md_to_mgf1(&oaep->maskGenFunc, mgf1md))
|
||||
goto err;
|
||||
if (labellen > 0) {
|
||||
ASN1_OCTET_STRING *los;
|
||||
oaep->pSourceFunc = X509_ALGOR_new();
|
||||
if (oaep->pSourceFunc == NULL)
|
||||
goto err;
|
||||
los = ASN1_OCTET_STRING_new();
|
||||
if (los == NULL)
|
||||
goto err;
|
||||
if (!ASN1_OCTET_STRING_set(los, label, labellen)) {
|
||||
ASN1_OCTET_STRING_free(los);
|
||||
goto err;
|
||||
}
|
||||
X509_ALGOR_set0(oaep->pSourceFunc, OBJ_nid2obj(NID_pSpecified),
|
||||
V_ASN1_OCTET_STRING, los);
|
||||
}
|
||||
/* create string with pss parameter encoding. */
|
||||
if (!ASN1_item_pack(oaep, ASN1_ITEM_rptr(RSA_OAEP_PARAMS), &os))
|
||||
goto err;
|
||||
X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaesOaep), V_ASN1_SEQUENCE, os);
|
||||
os = NULL;
|
||||
rv = 1;
|
||||
err:
|
||||
RSA_OAEP_PARAMS_free(oaep);
|
||||
ASN1_STRING_free(os);
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rsa_pkey_check(const EVP_PKEY *pkey)
|
||||
{
|
||||
return RSA_check_key_ex(pkey->pkey.rsa, NULL);
|
||||
|
@ -133,3 +133,8 @@ int asn1_type_set_octetstring_int(ASN1_TYPE *a, long num,
|
||||
unsigned char *data, int len);
|
||||
int asn1_type_get_octetstring_int(const ASN1_TYPE *a, long *num,
|
||||
unsigned char *data, int max_len);
|
||||
|
||||
int x509_algor_new_from_md(X509_ALGOR **palg, const EVP_MD *md);
|
||||
const EVP_MD *x509_algor_get_md(X509_ALGOR *alg);
|
||||
X509_ALGOR *x509_algor_mgf1_decode(X509_ALGOR *alg);
|
||||
int x509_algor_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md);
|
@ -835,6 +835,8 @@ int evp_pkey_ctx_get1_id_len_prov(EVP_PKEY_CTX *ctx, size_t *id_len);
|
||||
|
||||
int evp_pkey_ctx_use_cached_data(EVP_PKEY_CTX *ctx);
|
||||
#endif /* !defined(FIPS_MODULE) */
|
||||
OPENSSL_CTX *evp_pkey_ctx_get0_libctx(EVP_PKEY_CTX *ctx);
|
||||
const char *evp_pkey_ctx_get0_propq(EVP_PKEY_CTX *ctx);
|
||||
void evp_method_store_flush(OPENSSL_CTX *libctx);
|
||||
int evp_set_default_properties_int(OPENSSL_CTX *libctx, const char *propq,
|
||||
int loadconfig);
|
||||
|
@ -244,6 +244,7 @@ int ERR_load_ASN1_strings(void);
|
||||
# define ASN1_R_TYPE_NOT_PRIMITIVE 195
|
||||
# define ASN1_R_UNEXPECTED_EOC 159
|
||||
# define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 215
|
||||
# define ASN1_R_UNKNOWN_DIGEST 229
|
||||
# define ASN1_R_UNKNOWN_FORMAT 160
|
||||
# define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 161
|
||||
# define ASN1_R_UNKNOWN_OBJECT_TYPE 162
|
||||
|
@ -146,6 +146,7 @@ int ERR_load_CMS_strings(void);
|
||||
# define CMS_R_CONTENT_VERIFY_ERROR 109
|
||||
# define CMS_R_CTRL_ERROR 110
|
||||
# define CMS_R_CTRL_FAILURE 111
|
||||
# define CMS_R_DECODE_ERROR 187
|
||||
# define CMS_R_DECRYPT_ERROR 112
|
||||
# define CMS_R_ERROR_GETTING_PUBLIC_KEY 113
|
||||
# define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 114
|
||||
@ -156,6 +157,9 @@ int ERR_load_CMS_strings(void);
|
||||
# define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 117
|
||||
# define CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER 176
|
||||
# define CMS_R_INVALID_KEY_LENGTH 118
|
||||
# define CMS_R_INVALID_LABEL 190
|
||||
# define CMS_R_INVALID_OAEP_PARAMETERS 191
|
||||
# define CMS_R_KDF_PARAMETER_ERROR 186
|
||||
# define CMS_R_MD_BIO_INIT_ERROR 119
|
||||
# define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 120
|
||||
# define CMS_R_MESSAGEDIGEST_WRONG_LENGTH 121
|
||||
@ -186,9 +190,11 @@ int ERR_load_CMS_strings(void);
|
||||
# define CMS_R_NO_PUBLIC_KEY 134
|
||||
# define CMS_R_NO_RECEIPT_REQUEST 168
|
||||
# define CMS_R_NO_SIGNERS 135
|
||||
# define CMS_R_PEER_KEY_ERROR 188
|
||||
# define CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 136
|
||||
# define CMS_R_RECEIPT_DECODE_ERROR 169
|
||||
# define CMS_R_RECIPIENT_ERROR 137
|
||||
# define CMS_R_SHARED_INFO_ERROR 189
|
||||
# define CMS_R_SIGNER_CERTIFICATE_NOT_FOUND 138
|
||||
# define CMS_R_SIGNFINAL_ERROR 139
|
||||
# define CMS_R_SMIME_TEXT_ERROR 140
|
||||
@ -204,8 +210,10 @@ int ERR_load_CMS_strings(void);
|
||||
# define CMS_R_UNKNOWN_ID 150
|
||||
# define CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM 151
|
||||
# define CMS_R_UNSUPPORTED_CONTENT_TYPE 152
|
||||
# define CMS_R_UNSUPPORTED_ENCRYPTION_TYPE 192
|
||||
# define CMS_R_UNSUPPORTED_KEK_ALGORITHM 153
|
||||
# define CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM 179
|
||||
# define CMS_R_UNSUPPORTED_LABEL_SOURCE 193
|
||||
# define CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE 155
|
||||
# define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 154
|
||||
# define CMS_R_UNSUPPORTED_TYPE 156
|
||||
|
Loading…
Reference in New Issue
Block a user