Browse Source

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)
master
Matt Caswell 2 years ago
parent
commit
0b3a4ef27a
18 changed files with 1040 additions and 898 deletions
  1. +1
    -0
      crypto/asn1/asn1_err.c
  2. +63
    -0
      crypto/asn1/x_algor.c
  3. +8
    -1
      crypto/cms/build.info
  4. +322
    -0
      crypto/cms/cms_dh.c
  5. +391
    -0
      crypto/cms/cms_ecdh.c
  6. +9
    -0
      crypto/cms/cms_env.c
  7. +12
    -0
      crypto/cms/cms_err.c
  8. +4
    -0
      crypto/cms/cms_local.h
  9. +182
    -0
      crypto/cms/cms_rsa.c
  10. +6
    -324
      crypto/dh/dh_ameth.c
  11. +0
    -336
      crypto/ec/ec_ameth.c
  12. +9
    -0
      crypto/err/openssl.txt
  13. +10
    -0
      crypto/evp/pmeth_lib.c
  14. +7
    -237
      crypto/rsa/rsa_ameth.c
  15. +5
    -0
      include/crypto/asn1.h
  16. +2
    -0
      include/crypto/evp.h
  17. +1
    -0
      include/openssl/asn1err.h
  18. +8
    -0
      include/openssl/cmserr.h

+ 1
- 0
crypto/asn1/asn1_err.c View File

@ -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"},


+ 63
- 0
crypto/asn1/x_algor.c View File

@ -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;
}

+ 8
- 1
crypto/cms/build.info View File

@ -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
- 0
crypto/cms/cms_dh.c View 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
- 0
crypto/cms/cms_ecdh.c View 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;
}

+ 9
- 0
crypto/cms/cms_env.c View File

@ -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);


+ 12
- 0
crypto/cms/cms_err.c View File

@ -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),


+ 4
- 0
crypto/cms/cms_local.h View File

@ -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
- 0
crypto/cms/cms_rsa.c View 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;
}

+ 6
- 324
crypto/dh/dh_ameth.c View File

@ -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 "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 <openssl/cms.h>
#include "internal/ffc.h"
#include "internal/cryptlib.h"
#include "crypto/asn1.h"
#include "crypto/dh.h"
#include "crypto/evp.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

+ 0
- 336
crypto/ec/ec_ameth.c View File

@ -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)