summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/cms/cms_enc.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_enc.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_enc.c')
-rw-r--r--src/lib/libcrypto/cms/cms_enc.c213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/lib/libcrypto/cms/cms_enc.c b/src/lib/libcrypto/cms/cms_enc.c
new file mode 100644
index 0000000000..a1719830e8
--- /dev/null
+++ b/src/lib/libcrypto/cms/cms_enc.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright 2008-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 "cms_lcl.h"
18
19/* CMS EncryptedData Utilities */
20
21/* Return BIO based on EncryptedContentInfo and key */
22
23BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec)
24{
25 BIO *b;
26 EVP_CIPHER_CTX *ctx;
27 const EVP_CIPHER *ciph;
28 X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
29 unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
30 unsigned char *tkey = NULL;
31 size_t tkeylen = 0;
32
33 int ok = 0;
34
35 int enc, keep_key = 0;
36
37 enc = ec->cipher ? 1 : 0;
38
39 b = BIO_new(BIO_f_cipher());
40 if (b == NULL) {
41 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
42 return NULL;
43 }
44
45 BIO_get_cipher_ctx(b, &ctx);
46
47 if (enc) {
48 ciph = ec->cipher;
49 /*
50 * If not keeping key set cipher to NULL so subsequent calls decrypt.
51 */
52 if (ec->key)
53 ec->cipher = NULL;
54 } else {
55 ciph = EVP_get_cipherbyobj(calg->algorithm);
56
57 if (!ciph) {
58 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_UNKNOWN_CIPHER);
59 goto err;
60 }
61 }
62
63 if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) {
64 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
65 CMS_R_CIPHER_INITIALISATION_ERROR);
66 goto err;
67 }
68
69 if (enc) {
70 int ivlen;
71 calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
72 /* Generate a random IV if we need one */
73 ivlen = EVP_CIPHER_CTX_iv_length(ctx);
74 if (ivlen > 0) {
75 if (RAND_bytes(iv, ivlen) <= 0)
76 goto err;
77 piv = iv;
78 }
79 } else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) {
80 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
81 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
82 goto err;
83 }
84 tkeylen = EVP_CIPHER_CTX_key_length(ctx);
85 /* Generate random session key */
86 if (!enc || !ec->key) {
87 tkey = OPENSSL_malloc(tkeylen);
88 if (tkey == NULL) {
89 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
90 goto err;
91 }
92 if (EVP_CIPHER_CTX_rand_key(ctx, tkey) <= 0)
93 goto err;
94 }
95
96 if (!ec->key) {
97 ec->key = tkey;
98 ec->keylen = tkeylen;
99 tkey = NULL;
100 if (enc)
101 keep_key = 1;
102 else
103 ERR_clear_error();
104
105 }
106
107 if (ec->keylen != tkeylen) {
108 /* If necessary set key length */
109 if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) {
110 /*
111 * Only reveal failure if debugging so we don't leak information
112 * which may be useful in MMA.
113 */
114 if (enc || ec->debug) {
115 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
116 CMS_R_INVALID_KEY_LENGTH);
117 goto err;
118 } else {
119 /* Use random key */
120 OPENSSL_clear_free(ec->key, ec->keylen);
121 ec->key = tkey;
122 ec->keylen = tkeylen;
123 tkey = NULL;
124 ERR_clear_error();
125 }
126 }
127 }
128
129 if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) {
130 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
131 CMS_R_CIPHER_INITIALISATION_ERROR);
132 goto err;
133 }
134 if (enc) {
135 calg->parameter = ASN1_TYPE_new();
136 if (calg->parameter == NULL) {
137 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
138 goto err;
139 }
140 if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) {
141 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
142 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
143 goto err;
144 }
145 /* If parameter type not set omit parameter */
146 if (calg->parameter->type == V_ASN1_UNDEF) {
147 ASN1_TYPE_free(calg->parameter);
148 calg->parameter = NULL;
149 }
150 }
151 ok = 1;
152
153 err:
154 if (!keep_key || !ok) {
155 OPENSSL_clear_free(ec->key, ec->keylen);
156 ec->key = NULL;
157 }
158 OPENSSL_clear_free(tkey, tkeylen);
159 if (ok)
160 return b;
161 BIO_free(b);
162 return NULL;
163}
164
165int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec,
166 const EVP_CIPHER *cipher,
167 const unsigned char *key, size_t keylen)
168{
169 ec->cipher = cipher;
170 if (key) {
171 if ((ec->key = OPENSSL_malloc(keylen)) == NULL) {
172 CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT, ERR_R_MALLOC_FAILURE);
173 return 0;
174 }
175 memcpy(ec->key, key, keylen);
176 }
177 ec->keylen = keylen;
178 if (cipher)
179 ec->contentType = OBJ_nid2obj(NID_pkcs7_data);
180 return 1;
181}
182
183int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph,
184 const unsigned char *key, size_t keylen)
185{
186 CMS_EncryptedContentInfo *ec;
187 if (!key || !keylen) {
188 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NO_KEY);
189 return 0;
190 }
191 if (ciph) {
192 cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData);
193 if (!cms->d.encryptedData) {
194 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, ERR_R_MALLOC_FAILURE);
195 return 0;
196 }
197 cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted);
198 cms->d.encryptedData->version = 0;
199 } else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) {
200 CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, CMS_R_NOT_ENCRYPTED_DATA);
201 return 0;
202 }
203 ec = cms->d.encryptedData->encryptedContentInfo;
204 return cms_EncryptedContent_init(ec, ciph, key, keylen);
205}
206
207BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms)
208{
209 CMS_EncryptedData *enc = cms->d.encryptedData;
210 if (enc->encryptedContentInfo->cipher && enc->unprotectedAttrs)
211 enc->version = 2;
212 return cms_EncryptedContent_init_bio(enc->encryptedContentInfo);
213}