1 /* 2 * Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <assert.h> 11 #include <openssl/cms.h> 12 #include <openssl/dh.h> 13 #include <openssl/err.h> 14 #include <openssl/core_names.h> 15 #include "internal/sizes.h" 16 #include "crypto/evp.h" 17 #include "cms_local.h" 18 19 static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx, 20 X509_ALGOR *alg, ASN1_BIT_STRING *pubkey) 21 { 22 const ASN1_OBJECT *aoid; 23 int atype; 24 const void *aval; 25 ASN1_INTEGER *public_key = NULL; 26 int rv = 0; 27 EVP_PKEY *pkpeer = NULL, *pk = NULL; 28 BIGNUM *bnpub = NULL; 29 const unsigned char *p; 30 unsigned char *buf = NULL; 31 int plen; 32 33 X509_ALGOR_get0(&aoid, &atype, &aval, alg); 34 if (OBJ_obj2nid(aoid) != NID_dhpublicnumber) 35 goto err; 36 /* Only absent parameters allowed in RFC XXXX */ 37 if (atype != V_ASN1_UNDEF && atype == V_ASN1_NULL) 38 goto err; 39 40 pk = EVP_PKEY_CTX_get0_pkey(pctx); 41 if (pk == NULL || !EVP_PKEY_is_a(pk, "DHX")) 42 goto err; 43 44 /* Get public key */ 45 plen = ASN1_STRING_length(pubkey); 46 p = ASN1_STRING_get0_data(pubkey); 47 if (p == NULL || plen == 0) 48 goto err; 49 50 if ((public_key = d2i_ASN1_INTEGER(NULL, &p, plen)) == NULL) 51 goto err; 52 /* 53 * Pad to full p parameter size as that is checked by 54 * EVP_PKEY_set1_encoded_public_key() 55 */ 56 plen = EVP_PKEY_get_size(pk); 57 if ((bnpub = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) 58 goto err; 59 if ((buf = OPENSSL_malloc(plen)) == NULL) 60 goto err; 61 if (BN_bn2binpad(bnpub, buf, plen) < 0) 62 goto err; 63 64 pkpeer = EVP_PKEY_new(); 65 if (pkpeer == NULL 66 || !EVP_PKEY_copy_parameters(pkpeer, pk) 67 || !EVP_PKEY_set1_encoded_public_key(pkpeer, buf, plen)) 68 goto err; 69 70 if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0) 71 rv = 1; 72 err: 73 ASN1_INTEGER_free(public_key); 74 BN_free(bnpub); 75 OPENSSL_free(buf); 76 EVP_PKEY_free(pkpeer); 77 return rv; 78 } 79 80 static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) 81 { 82 int rv = 0; 83 X509_ALGOR *alg, *kekalg = NULL; 84 ASN1_OCTET_STRING *ukm; 85 const unsigned char *p; 86 unsigned char *dukm = NULL; 87 size_t dukmlen = 0; 88 int keylen, plen; 89 EVP_CIPHER *kekcipher = NULL; 90 EVP_CIPHER_CTX *kekctx; 91 char name[OSSL_MAX_NAME_SIZE]; 92 93 if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) 94 goto err; 95 96 /* 97 * For DH we only have one OID permissible. If ever any more get defined 98 * we will need something cleverer. 99 */ 100 if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) { 101 ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR); 102 goto err; 103 } 104 105 if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0 106 || EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0) 107 goto err; 108 109 if (alg->parameter->type != V_ASN1_SEQUENCE) 110 goto err; 111 112 p = alg->parameter->value.sequence->data; 113 plen = alg->parameter->value.sequence->length; 114 kekalg = d2i_X509_ALGOR(NULL, &p, plen); 115 if (kekalg == NULL) 116 goto err; 117 kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); 118 if (kekctx == NULL) 119 goto err; 120 121 if (OBJ_obj2txt(name, sizeof(name), kekalg->algorithm, 0) <= 0) 122 goto err; 123 124 kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery); 125 if (kekcipher == NULL 126 || EVP_CIPHER_get_mode(kekcipher) != EVP_CIPH_WRAP_MODE) 127 goto err; 128 if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) 129 goto err; 130 if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) 131 goto err; 132 133 keylen = EVP_CIPHER_CTX_get_key_length(kekctx); 134 if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) 135 goto err; 136 /* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */ 137 if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, 138 OBJ_nid2obj(EVP_CIPHER_get_type(kekcipher))) 139 <= 0) 140 goto err; 141 142 if (ukm != NULL) { 143 dukmlen = ASN1_STRING_length(ukm); 144 dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen); 145 if (dukm == NULL) 146 goto err; 147 } 148 149 if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) 150 goto err; 151 dukm = NULL; 152 153 rv = 1; 154 err: 155 X509_ALGOR_free(kekalg); 156 EVP_CIPHER_free(kekcipher); 157 OPENSSL_free(dukm); 158 return rv; 159 } 160 161 static int dh_cms_decrypt(CMS_RecipientInfo *ri) 162 { 163 EVP_PKEY_CTX *pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); 164 165 if (pctx == NULL) 166 return 0; 167 /* See if we need to set peer key */ 168 if (!EVP_PKEY_CTX_get0_peerkey(pctx)) { 169 X509_ALGOR *alg; 170 ASN1_BIT_STRING *pubkey; 171 172 if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey, 173 NULL, NULL, NULL)) 174 return 0; 175 if (alg == NULL || pubkey == NULL) 176 return 0; 177 if (!dh_cms_set_peerkey(pctx, alg, pubkey)) { 178 ERR_raise(ERR_LIB_CMS, CMS_R_PEER_KEY_ERROR); 179 return 0; 180 } 181 } 182 /* Set DH derivation parameters and initialise unwrap context */ 183 if (!dh_cms_set_shared_info(pctx, ri)) { 184 ERR_raise(ERR_LIB_CMS, CMS_R_SHARED_INFO_ERROR); 185 return 0; 186 } 187 return 1; 188 } 189 190 static int dh_cms_encrypt(CMS_RecipientInfo *ri) 191 { 192 EVP_PKEY_CTX *pctx; 193 EVP_PKEY *pkey; 194 EVP_CIPHER_CTX *ctx; 195 int keylen; 196 X509_ALGOR *talg, *wrap_alg = NULL; 197 const ASN1_OBJECT *aoid; 198 ASN1_BIT_STRING *pubkey; 199 ASN1_STRING *wrap_str; 200 ASN1_OCTET_STRING *ukm; 201 unsigned char *penc = NULL, *dukm = NULL; 202 int penclen; 203 size_t dukmlen = 0; 204 int rv = 0; 205 int kdf_type, wrap_nid; 206 const EVP_MD *kdf_md; 207 208 pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); 209 if (pctx == NULL) 210 return 0; 211 /* Get ephemeral key */ 212 pkey = EVP_PKEY_CTX_get0_pkey(pctx); 213 if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey, 214 NULL, NULL, NULL)) 215 goto err; 216 217 /* Is everything uninitialised? */ 218 X509_ALGOR_get0(&aoid, NULL, NULL, talg); 219 if (aoid == OBJ_nid2obj(NID_undef)) { 220 BIGNUM *bn_pub_key = NULL; 221 ASN1_INTEGER *pubk; 222 223 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &bn_pub_key)) 224 goto err; 225 226 pubk = BN_to_ASN1_INTEGER(bn_pub_key, NULL); 227 BN_free(bn_pub_key); 228 if (pubk == NULL) 229 goto err; 230 231 /* Set the key */ 232 penclen = i2d_ASN1_INTEGER(pubk, &penc); 233 ASN1_INTEGER_free(pubk); 234 if (penclen <= 0) 235 goto err; 236 ASN1_STRING_set0(pubkey, penc, penclen); 237 pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); 238 pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT; 239 240 penc = NULL; 241 X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber), 242 V_ASN1_UNDEF, NULL); 243 } 244 245 /* See if custom parameters set */ 246 kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx); 247 if (kdf_type <= 0 || EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md) <= 0) 248 goto err; 249 250 if (kdf_type == EVP_PKEY_DH_KDF_NONE) { 251 kdf_type = EVP_PKEY_DH_KDF_X9_42; 252 if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0) 253 goto err; 254 } else if (kdf_type != EVP_PKEY_DH_KDF_X9_42) 255 /* Unknown KDF */ 256 goto err; 257 if (kdf_md == NULL) { 258 /* Only SHA1 supported */ 259 kdf_md = EVP_sha1(); 260 if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0) 261 goto err; 262 } else if (EVP_MD_get_type(kdf_md) != NID_sha1) 263 /* Unsupported digest */ 264 goto err; 265 266 if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm)) 267 goto err; 268 269 /* Get wrap NID */ 270 ctx = CMS_RecipientInfo_kari_get0_ctx(ri); 271 wrap_nid = EVP_CIPHER_CTX_get_type(ctx); 272 if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0) 273 goto err; 274 keylen = EVP_CIPHER_CTX_get_key_length(ctx); 275 276 /* Package wrap algorithm in an AlgorithmIdentifier */ 277 278 wrap_alg = X509_ALGOR_new(); 279 if (wrap_alg == NULL) 280 goto err; 281 wrap_alg->algorithm = OBJ_nid2obj(wrap_nid); 282 wrap_alg->parameter = ASN1_TYPE_new(); 283 if (wrap_alg->parameter == NULL) 284 goto err; 285 if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0) 286 goto err; 287 if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) { 288 ASN1_TYPE_free(wrap_alg->parameter); 289 wrap_alg->parameter = NULL; 290 } 291 292 if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) 293 goto err; 294 295 if (ukm != NULL) { 296 dukmlen = ASN1_STRING_length(ukm); 297 dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen); 298 if (dukm == NULL) 299 goto err; 300 } 301 302 if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) 303 goto err; 304 dukm = NULL; 305 306 /* 307 * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter 308 * of another AlgorithmIdentifier. 309 */ 310 penc = NULL; 311 penclen = i2d_X509_ALGOR(wrap_alg, &penc); 312 if (penclen <= 0) 313 goto err; 314 wrap_str = ASN1_STRING_new(); 315 if (wrap_str == NULL) 316 goto err; 317 ASN1_STRING_set0(wrap_str, penc, penclen); 318 penc = NULL; 319 rv = X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH), 320 V_ASN1_SEQUENCE, wrap_str); 321 if (!rv) 322 ASN1_STRING_free(wrap_str); 323 324 err: 325 OPENSSL_free(penc); 326 X509_ALGOR_free(wrap_alg); 327 OPENSSL_free(dukm); 328 return rv; 329 } 330 331 int ossl_cms_dh_envelope(CMS_RecipientInfo *ri, int decrypt) 332 { 333 assert(decrypt == 0 || decrypt == 1); 334 335 if (decrypt == 1) 336 return dh_cms_decrypt(ri); 337 338 if (decrypt == 0) 339 return dh_cms_encrypt(ri); 340 341 ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); 342 return 0; 343 } 344