summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/cms/cms_pwri.c
diff options
context:
space:
mode:
authorjsing <>2019-08-10 15:55:20 +0000
committerjsing <>2019-08-10 15:55:20 +0000
commita0845ead6d459f388701fe3fe8fa27635f4885f1 (patch)
treecfa2d4e7280cbfe7b7007556c8dcab6691e87b83 /src/lib/libcrypto/cms/cms_pwri.c
parent38e170324f2dafb68786e79022ddafab241aad3d (diff)
downloadopenbsd-a0845ead6d459f388701fe3fe8fa27635f4885f1.tar.gz
openbsd-a0845ead6d459f388701fe3fe8fa27635f4885f1.tar.bz2
openbsd-a0845ead6d459f388701fe3fe8fa27635f4885f1.zip
Work towards supporting Cryptographic Message Syntax (CMS) in libcrypto.
Cryptographic Message Syntax (CMS) is a standard for cryptographically protecting messages, as defined in RFC 5652. It is derived from PKCS #7 version 1.5 and utilises various ASN.1 structures, making it complex and fairly heavyweight. Various protocols - including RPKI (RFC 6480) - have been built on top of it, which means it is necessary to support CMS, in order to support RPKI. This imports around 6,000 lines of code from OpenSSL 1.1.1, which is still under the original OpenSSL license. Further work will occur in tree. Requested by and discussed with many. ok deraadt@ tb@
Diffstat (limited to 'src/lib/libcrypto/cms/cms_pwri.c')
-rw-r--r--src/lib/libcrypto/cms/cms_pwri.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/src/lib/libcrypto/cms/cms_pwri.c b/src/lib/libcrypto/cms/cms_pwri.c
new file mode 100644
index 0000000000..26e3bdcf9e
--- /dev/null
+++ b/src/lib/libcrypto/cms/cms_pwri.c
@@ -0,0 +1,394 @@
1/*
2 * Copyright 2009-2018 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (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 "internal/cryptlib.h"
11#include <openssl/asn1t.h>
12#include <openssl/pem.h>
13#include <openssl/x509v3.h>
14#include <openssl/err.h>
15#include <openssl/cms.h>
16#include <openssl/rand.h>
17#include <openssl/aes.h>
18#include "cms_lcl.h"
19#include "internal/asn1_int.h"
20
21int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri,
22 unsigned char *pass, ossl_ssize_t passlen)
23{
24 CMS_PasswordRecipientInfo *pwri;
25 if (ri->type != CMS_RECIPINFO_PASS) {
26 CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD, CMS_R_NOT_PWRI);
27 return 0;
28 }
29
30 pwri = ri->d.pwri;
31 pwri->pass = pass;
32 if (pass && passlen < 0)
33 passlen = strlen((char *)pass);
34 pwri->passlen = passlen;
35 return 1;
36}
37
38CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
39 int iter, int wrap_nid,
40 int pbe_nid,
41 unsigned char *pass,
42 ossl_ssize_t passlen,
43 const EVP_CIPHER *kekciph)
44{
45 CMS_RecipientInfo *ri = NULL;
46 CMS_EnvelopedData *env;
47 CMS_PasswordRecipientInfo *pwri;
48 EVP_CIPHER_CTX *ctx = NULL;
49 X509_ALGOR *encalg = NULL;
50 unsigned char iv[EVP_MAX_IV_LENGTH];
51 int ivlen;
52
53 env = cms_get0_enveloped(cms);
54 if (!env)
55 return NULL;
56
57 if (wrap_nid <= 0)
58 wrap_nid = NID_id_alg_PWRI_KEK;
59
60 if (pbe_nid <= 0)
61 pbe_nid = NID_id_pbkdf2;
62
63 /* Get from enveloped data */
64 if (kekciph == NULL)
65 kekciph = env->encryptedContentInfo->cipher;
66
67 if (kekciph == NULL) {
68 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_NO_CIPHER);
69 return NULL;
70 }
71 if (wrap_nid != NID_id_alg_PWRI_KEK) {
72 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
73 CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
74 return NULL;
75 }
76
77 /* Setup algorithm identifier for cipher */
78 encalg = X509_ALGOR_new();
79 if (encalg == NULL) {
80 goto merr;
81 }
82 ctx = EVP_CIPHER_CTX_new();
83
84 if (EVP_EncryptInit_ex(ctx, kekciph, NULL, NULL, NULL) <= 0) {
85 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB);
86 goto err;
87 }
88
89 ivlen = EVP_CIPHER_CTX_iv_length(ctx);
90
91 if (ivlen > 0) {
92 if (RAND_bytes(iv, ivlen) <= 0)
93 goto err;
94 if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) <= 0) {
95 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB);
96 goto err;
97 }
98 encalg->parameter = ASN1_TYPE_new();
99 if (!encalg->parameter) {
100 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE);
101 goto err;
102 }
103 if (EVP_CIPHER_param_to_asn1(ctx, encalg->parameter) <= 0) {
104 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
105 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
106 goto err;
107 }
108 }
109
110 encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
111
112 EVP_CIPHER_CTX_free(ctx);
113 ctx = NULL;
114
115 /* Initialize recipient info */
116 ri = M_ASN1_new_of(CMS_RecipientInfo);
117 if (ri == NULL)
118 goto merr;
119
120 ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo);
121 if (ri->d.pwri == NULL)
122 goto merr;
123 ri->type = CMS_RECIPINFO_PASS;
124
125 pwri = ri->d.pwri;
126 /* Since this is overwritten, free up empty structure already there */
127 X509_ALGOR_free(pwri->keyEncryptionAlgorithm);
128 pwri->keyEncryptionAlgorithm = X509_ALGOR_new();
129 if (pwri->keyEncryptionAlgorithm == NULL)
130 goto merr;
131 pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
132 pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
133 if (pwri->keyEncryptionAlgorithm->parameter == NULL)
134 goto merr;
135
136 if (!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR),
137 &pwri->keyEncryptionAlgorithm->parameter->
138 value.sequence))
139 goto merr;
140 pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;
141
142 X509_ALGOR_free(encalg);
143 encalg = NULL;
144
145 /* Setup PBE algorithm */
146
147 pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1);
148
149 if (!pwri->keyDerivationAlgorithm)
150 goto err;
151
152 CMS_RecipientInfo_set0_password(ri, pass, passlen);
153 pwri->version = 0;
154
155 if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
156 goto merr;
157
158 return ri;
159
160 merr:
161 CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE);
162 err:
163 EVP_CIPHER_CTX_free(ctx);
164 if (ri)
165 M_ASN1_free_of(ri, CMS_RecipientInfo);
166 X509_ALGOR_free(encalg);
167 return NULL;
168
169}
170
171/*
172 * This is an implementation of the key wrapping mechanism in RFC3211, at
173 * some point this should go into EVP.
174 */
175
176static int kek_unwrap_key(unsigned char *out, size_t *outlen,
177 const unsigned char *in, size_t inlen,
178 EVP_CIPHER_CTX *ctx)
179{
180 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
181 unsigned char *tmp;
182 int outl, rv = 0;
183 if (inlen < 2 * blocklen) {
184 /* too small */
185 return 0;
186 }
187 if (inlen % blocklen) {
188 /* Invalid size */
189 return 0;
190 }
191 if ((tmp = OPENSSL_malloc(inlen)) == NULL) {
192 CMSerr(CMS_F_KEK_UNWRAP_KEY, ERR_R_MALLOC_FAILURE);
193 return 0;
194 }
195 /* setup IV by decrypting last two blocks */
196 if (!EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
197 in + inlen - 2 * blocklen, blocklen * 2)
198 /*
199 * Do a decrypt of last decrypted block to set IV to correct value
200 * output it to start of buffer so we don't corrupt decrypted block
201 * this works because buffer is at least two block lengths long.
202 */
203 || !EVP_DecryptUpdate(ctx, tmp, &outl,
204 tmp + inlen - blocklen, blocklen)
205 /* Can now decrypt first n - 1 blocks */
206 || !EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen)
207
208 /* Reset IV to original value */
209 || !EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL)
210 /* Decrypt again */
211 || !EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen))
212 goto err;
213 /* Check check bytes */
214 if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff) {
215 /* Check byte failure */
216 goto err;
217 }
218 if (inlen < (size_t)(tmp[0] - 4)) {
219 /* Invalid length value */
220 goto err;
221 }
222 *outlen = (size_t)tmp[0];
223 memcpy(out, tmp + 4, *outlen);
224 rv = 1;
225 err:
226 OPENSSL_clear_free(tmp, inlen);
227 return rv;
228
229}
230
231static int kek_wrap_key(unsigned char *out, size_t *outlen,
232 const unsigned char *in, size_t inlen,
233 EVP_CIPHER_CTX *ctx)
234{
235 size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
236 size_t olen;
237 int dummy;
238 /*
239 * First decide length of output buffer: need header and round up to
240 * multiple of block length.
241 */
242 olen = (inlen + 4 + blocklen - 1) / blocklen;
243 olen *= blocklen;
244 if (olen < 2 * blocklen) {
245 /* Key too small */
246 return 0;
247 }
248 if (inlen > 0xFF) {
249 /* Key too large */
250 return 0;
251 }
252 if (out) {
253 /* Set header */
254 out[0] = (unsigned char)inlen;
255 out[1] = in[0] ^ 0xFF;
256 out[2] = in[1] ^ 0xFF;
257 out[3] = in[2] ^ 0xFF;
258 memcpy(out + 4, in, inlen);
259 /* Add random padding to end */
260 if (olen > inlen + 4
261 && RAND_bytes(out + 4 + inlen, olen - 4 - inlen) <= 0)
262 return 0;
263 /* Encrypt twice */
264 if (!EVP_EncryptUpdate(ctx, out, &dummy, out, olen)
265 || !EVP_EncryptUpdate(ctx, out, &dummy, out, olen))
266 return 0;
267 }
268
269 *outlen = olen;
270
271 return 1;
272}
273
274/* Encrypt/Decrypt content key in PWRI recipient info */
275
276int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
277 int en_de)
278{
279 CMS_EncryptedContentInfo *ec;
280 CMS_PasswordRecipientInfo *pwri;
281 int r = 0;
282 X509_ALGOR *algtmp, *kekalg = NULL;
283 EVP_CIPHER_CTX *kekctx = NULL;
284 const EVP_CIPHER *kekcipher;
285 unsigned char *key = NULL;
286 size_t keylen;
287
288 ec = cms->d.envelopedData->encryptedContentInfo;
289
290 pwri = ri->d.pwri;
291
292 if (!pwri->pass) {
293 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_NO_PASSWORD);
294 return 0;
295 }
296 algtmp = pwri->keyEncryptionAlgorithm;
297
298 if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK) {
299 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
300 CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
301 return 0;
302 }
303
304 kekalg = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(X509_ALGOR),
305 algtmp->parameter);
306
307 if (kekalg == NULL) {
308 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
309 CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);
310 return 0;
311 }
312
313 kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
314
315 if (!kekcipher) {
316 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNKNOWN_CIPHER);
317 return 0;
318 }
319
320 kekctx = EVP_CIPHER_CTX_new();
321 if (kekctx == NULL) {
322 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_MALLOC_FAILURE);
323 return 0;
324 }
325 /* Fixup cipher based on AlgorithmIdentifier to set IV etc */
326 if (!EVP_CipherInit_ex(kekctx, kekcipher, NULL, NULL, NULL, en_de))
327 goto err;
328 EVP_CIPHER_CTX_set_padding(kekctx, 0);
329 if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) {
330 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
331 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
332 goto err;
333 }
334
335 algtmp = pwri->keyDerivationAlgorithm;
336
337 /* Finish password based key derivation to setup key in "ctx" */
338
339 if (EVP_PBE_CipherInit(algtmp->algorithm,
340 (char *)pwri->pass, pwri->passlen,
341 algtmp->parameter, kekctx, en_de) < 0) {
342 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_EVP_LIB);
343 goto err;
344 }
345
346 /* Finally wrap/unwrap the key */
347
348 if (en_de) {
349
350 if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, kekctx))
351 goto err;
352
353 key = OPENSSL_malloc(keylen);
354
355 if (key == NULL)
356 goto err;
357
358 if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, kekctx))
359 goto err;
360 pwri->encryptedKey->data = key;
361 pwri->encryptedKey->length = keylen;
362 } else {
363 key = OPENSSL_malloc(pwri->encryptedKey->length);
364
365 if (key == NULL) {
366 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_MALLOC_FAILURE);
367 goto err;
368 }
369 if (!kek_unwrap_key(key, &keylen,
370 pwri->encryptedKey->data,
371 pwri->encryptedKey->length, kekctx)) {
372 CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_UNWRAP_FAILURE);
373 goto err;
374 }
375
376 OPENSSL_clear_free(ec->key, ec->keylen);
377 ec->key = key;
378 ec->keylen = keylen;
379
380 }
381
382 r = 1;
383
384 err:
385
386 EVP_CIPHER_CTX_free(kekctx);
387
388 if (!r)
389 OPENSSL_free(key);
390 X509_ALGOR_free(kekalg);
391
392 return r;
393
394}