]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/cms/cms_dh.c
Move CMS signing code out of the algorithms and into CMS
[thirdparty/openssl.git] / crypto / cms / cms_dh.c
CommitLineData
0b3a4ef2
MC
1/*
2 * Copyright 2006-2020 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
9ab7fe48 10#include <assert.h>
0b3a4ef2 11#include <openssl/cms.h>
9ab7fe48 12#include <openssl/dh.h>
0b3a4ef2
MC
13#include <openssl/err.h>
14#include <openssl/core_names.h>
15#include "cms_local.h"
16
17static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx,
18 X509_ALGOR *alg, ASN1_BIT_STRING *pubkey)
19{
20 const ASN1_OBJECT *aoid;
21 int atype;
22 const void *aval;
23 ASN1_INTEGER *public_key = NULL;
24 int rv = 0;
25 EVP_PKEY *pkpeer = NULL, *pk = NULL;
26 const unsigned char *p;
27 int plen;
28
29 X509_ALGOR_get0(&aoid, &atype, &aval, alg);
30 if (OBJ_obj2nid(aoid) != NID_dhpublicnumber)
31 goto err;
32 /* Only absent parameters allowed in RFC XXXX */
33 if (atype != V_ASN1_UNDEF && atype == V_ASN1_NULL)
34 goto err;
35
36 pk = EVP_PKEY_CTX_get0_pkey(pctx);
9ab7fe48 37 if (pk == NULL || !EVP_PKEY_is_a(pk, "DHX"))
0b3a4ef2
MC
38 goto err;
39
40 /* Get public key */
41 plen = ASN1_STRING_length(pubkey);
42 p = ASN1_STRING_get0_data(pubkey);
43 if (p == NULL || plen == 0)
44 goto err;
45
46 pkpeer = EVP_PKEY_new();
47 if (pkpeer == NULL
48 || !EVP_PKEY_copy_parameters(pkpeer, pk)
49 /*
50 * TODO(3.0): This is badly named!! Can we make this more
51 * generic and not TLS specific?
52 */
53 || !EVP_PKEY_set1_tls_encodedpoint(pkpeer, p, plen))
54 goto err;
55
56 if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0)
57 rv = 1;
58 err:
59 ASN1_INTEGER_free(public_key);
60 EVP_PKEY_free(pkpeer);
61 return rv;
62}
63
64static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
65{
66 int rv = 0;
67 X509_ALGOR *alg, *kekalg = NULL;
68 ASN1_OCTET_STRING *ukm;
69 const unsigned char *p;
70 unsigned char *dukm = NULL;
71 size_t dukmlen = 0;
72 int keylen, plen;
73 const EVP_CIPHER *kekcipher;
74 EVP_CIPHER_CTX *kekctx;
75
76 if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
77 goto err;
78
79 /*
80 * For DH we only have one OID permissible. If ever any more get defined
81 * we will need something cleverer.
82 */
83 if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) {
84 CMSerr(0, CMS_R_KDF_PARAMETER_ERROR);
85 goto err;
86 }
87
9ab7fe48
MC
88 if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0
89 || EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0)
0b3a4ef2
MC
90 goto err;
91
92 if (alg->parameter->type != V_ASN1_SEQUENCE)
93 goto err;
94
95 p = alg->parameter->value.sequence->data;
96 plen = alg->parameter->value.sequence->length;
97 kekalg = d2i_X509_ALGOR(NULL, &p, plen);
98 if (kekalg == NULL)
99 goto err;
100 kekctx = CMS_RecipientInfo_kari_get0_ctx(ri);
101 if (kekctx == NULL)
102 goto err;
103 kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
104 if (kekcipher == NULL || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
105 goto err;
106 if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL))
107 goto err;
108 if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0)
109 goto err;
110
111 keylen = EVP_CIPHER_CTX_key_length(kekctx);
112 if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
113 goto err;
114 /* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */
115 if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx,
116 OBJ_nid2obj(EVP_CIPHER_type(kekcipher)))
117 <= 0)
118 goto err;
119
120 if (ukm != NULL) {
121 dukmlen = ASN1_STRING_length(ukm);
122 dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
123 if (dukm == NULL)
124 goto err;
125 }
126
127 if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
128 goto err;
129 dukm = NULL;
130
131 rv = 1;
132 err:
133 X509_ALGOR_free(kekalg);
134 OPENSSL_free(dukm);
135 return rv;
136}
137
138static int dh_cms_decrypt(CMS_RecipientInfo *ri)
139{
9ab7fe48 140 EVP_PKEY_CTX *pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
0b3a4ef2
MC
141
142 if (pctx == NULL)
143 return 0;
144 /* See if we need to set peer key */
145 if (!EVP_PKEY_CTX_get0_peerkey(pctx)) {
146 X509_ALGOR *alg;
147 ASN1_BIT_STRING *pubkey;
148
149 if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey,
150 NULL, NULL, NULL))
151 return 0;
152 if (alg == NULL || pubkey == NULL)
153 return 0;
154 if (!dh_cms_set_peerkey(pctx, alg, pubkey)) {
155 DHerr(DH_F_DH_CMS_DECRYPT, DH_R_PEER_KEY_ERROR);
156 return 0;
157 }
158 }
159 /* Set DH derivation parameters and initialise unwrap context */
160 if (!dh_cms_set_shared_info(pctx, ri)) {
161 DHerr(DH_F_DH_CMS_DECRYPT, DH_R_SHARED_INFO_ERROR);
162 return 0;
163 }
164 return 1;
165}
166
167static int dh_cms_encrypt(CMS_RecipientInfo *ri)
168{
169 EVP_PKEY_CTX *pctx;
170 EVP_PKEY *pkey;
171 EVP_CIPHER_CTX *ctx;
172 int keylen;
173 X509_ALGOR *talg, *wrap_alg = NULL;
174 const ASN1_OBJECT *aoid;
175 ASN1_BIT_STRING *pubkey;
176 ASN1_STRING *wrap_str;
177 ASN1_OCTET_STRING *ukm;
178 unsigned char *penc = NULL, *dukm = NULL;
179 int penclen;
180 size_t dukmlen = 0;
181 int rv = 0;
182 int kdf_type, wrap_nid;
183 const EVP_MD *kdf_md;
184
185 pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
186 if (pctx == NULL)
187 return 0;
188 /* Get ephemeral key */
189 pkey = EVP_PKEY_CTX_get0_pkey(pctx);
190 if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey,
191 NULL, NULL, NULL))
192 goto err;
9ab7fe48 193
0b3a4ef2 194 /* Is everything uninitialised? */
9ab7fe48 195 X509_ALGOR_get0(&aoid, NULL, NULL, talg);
0b3a4ef2
MC
196 if (aoid == OBJ_nid2obj(NID_undef)) {
197 BIGNUM *bn_pub_key = NULL;
198 ASN1_INTEGER *pubk;
199
200 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &bn_pub_key))
201 goto err;
202
203 pubk = BN_to_ASN1_INTEGER(bn_pub_key, NULL);
204 BN_free(bn_pub_key);
205 if (pubk == NULL)
206 goto err;
0b3a4ef2 207
9ab7fe48 208 /* Set the key */
0b3a4ef2
MC
209 penclen = i2d_ASN1_INTEGER(pubk, &penc);
210 ASN1_INTEGER_free(pubk);
211 if (penclen <= 0)
212 goto err;
213 ASN1_STRING_set0(pubkey, penc, penclen);
214 pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
215 pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
216
217 penc = NULL;
218 X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber),
219 V_ASN1_UNDEF, NULL);
220 }
221
222 /* See if custom parameters set */
223 kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx);
9ab7fe48 224 if (kdf_type <= 0 || !EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md))
0b3a4ef2
MC
225 goto err;
226
227 if (kdf_type == EVP_PKEY_DH_KDF_NONE) {
228 kdf_type = EVP_PKEY_DH_KDF_X9_42;
229 if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0)
230 goto err;
231 } else if (kdf_type != EVP_PKEY_DH_KDF_X9_42)
232 /* Unknown KDF */
233 goto err;
234 if (kdf_md == NULL) {
235 /* Only SHA1 supported */
236 kdf_md = EVP_sha1();
237 if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0)
238 goto err;
239 } else if (EVP_MD_type(kdf_md) != NID_sha1)
240 /* Unsupported digest */
241 goto err;
242
243 if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm))
244 goto err;
245
246 /* Get wrap NID */
247 ctx = CMS_RecipientInfo_kari_get0_ctx(ri);
248 wrap_nid = EVP_CIPHER_CTX_type(ctx);
249 if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0)
250 goto err;
251 keylen = EVP_CIPHER_CTX_key_length(ctx);
252
253 /* Package wrap algorithm in an AlgorithmIdentifier */
254
255 wrap_alg = X509_ALGOR_new();
256 if (wrap_alg == NULL)
257 goto err;
258 wrap_alg->algorithm = OBJ_nid2obj(wrap_nid);
259 wrap_alg->parameter = ASN1_TYPE_new();
260 if (wrap_alg->parameter == NULL)
261 goto err;
262 if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0)
263 goto err;
264 if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) {
265 ASN1_TYPE_free(wrap_alg->parameter);
266 wrap_alg->parameter = NULL;
267 }
268
269 if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0)
270 goto err;
271
272 if (ukm != NULL) {
273 dukmlen = ASN1_STRING_length(ukm);
274 dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen);
275 if (dukm == NULL)
276 goto err;
277 }
278
279 if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0)
280 goto err;
281 dukm = NULL;
282
283 /*
284 * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter
285 * of another AlgorithmIdentifier.
286 */
287 penc = NULL;
288 penclen = i2d_X509_ALGOR(wrap_alg, &penc);
289 if (penc == NULL || penclen == 0)
290 goto err;
291 wrap_str = ASN1_STRING_new();
292 if (wrap_str == NULL)
293 goto err;
294 ASN1_STRING_set0(wrap_str, penc, penclen);
295 penc = NULL;
296 X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH),
297 V_ASN1_SEQUENCE, wrap_str);
298
299 rv = 1;
300
301 err:
302 OPENSSL_free(penc);
303 X509_ALGOR_free(wrap_alg);
304 OPENSSL_free(dukm);
305 return rv;
306}
307
308int cms_dh_envelope(CMS_RecipientInfo *ri, int decrypt)
309{
9ab7fe48
MC
310 assert(decrypt == 0 || decrypt == 1);
311
0b3a4ef2
MC
312 if (decrypt == 1)
313 return dh_cms_decrypt(ri);
9ab7fe48
MC
314
315 if (decrypt == 0)
0b3a4ef2
MC
316 return dh_cms_encrypt(ri);
317
318 CMSerr(0, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
319 return 0;
9ab7fe48 320}