1 | /*
|
---|
2 | * Copyright 2007-2022 The OpenSSL Project Authors. All Rights Reserved.
|
---|
3 | * Copyright Nokia 2007-2019
|
---|
4 | * Copyright Siemens AG 2015-2019
|
---|
5 | *
|
---|
6 | * Licensed under the Apache License 2.0 (the "License"). You may not use
|
---|
7 | * this file except in compliance with the License. You can obtain a copy
|
---|
8 | * in the file LICENSE in the source distribution or at
|
---|
9 | * https://www.openssl.org/source/license.html
|
---|
10 | */
|
---|
11 |
|
---|
12 | #include "cmp_local.h"
|
---|
13 |
|
---|
14 | /* explicit #includes not strictly needed since implied by the above: */
|
---|
15 | #include <openssl/asn1t.h>
|
---|
16 | #include <openssl/cmp.h>
|
---|
17 | #include <openssl/crmf.h>
|
---|
18 | #include <openssl/err.h>
|
---|
19 | #include <openssl/x509.h>
|
---|
20 |
|
---|
21 | /*
|
---|
22 | * This function is also used by the internal verify_PBMAC() in cmp_vfy.c.
|
---|
23 | *
|
---|
24 | * Calculate protection for given PKImessage according to
|
---|
25 | * the algorithm and parameters in the message header's protectionAlg
|
---|
26 | * using the credentials, library context, and property criteria in the ctx.
|
---|
27 | *
|
---|
28 | * returns ASN1_BIT_STRING representing the protection on success, else NULL
|
---|
29 | */
|
---|
30 | ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx,
|
---|
31 | const OSSL_CMP_MSG *msg)
|
---|
32 | {
|
---|
33 | ASN1_BIT_STRING *prot = NULL;
|
---|
34 | OSSL_CMP_PROTECTEDPART prot_part;
|
---|
35 | const ASN1_OBJECT *algorOID = NULL;
|
---|
36 | const void *ppval = NULL;
|
---|
37 | int pptype = 0;
|
---|
38 |
|
---|
39 | if (!ossl_assert(ctx != NULL && msg != NULL))
|
---|
40 | return NULL;
|
---|
41 |
|
---|
42 | /* construct data to be signed */
|
---|
43 | prot_part.header = msg->header;
|
---|
44 | prot_part.body = msg->body;
|
---|
45 |
|
---|
46 | if (msg->header->protectionAlg == NULL) {
|
---|
47 | ERR_raise(ERR_LIB_CMP, CMP_R_UNKNOWN_ALGORITHM_ID);
|
---|
48 | return NULL;
|
---|
49 | }
|
---|
50 | X509_ALGOR_get0(&algorOID, &pptype, &ppval, msg->header->protectionAlg);
|
---|
51 |
|
---|
52 | if (OBJ_obj2nid(algorOID) == NID_id_PasswordBasedMAC) {
|
---|
53 | int len;
|
---|
54 | size_t prot_part_der_len;
|
---|
55 | unsigned char *prot_part_der = NULL;
|
---|
56 | size_t sig_len;
|
---|
57 | unsigned char *protection = NULL;
|
---|
58 | OSSL_CRMF_PBMPARAMETER *pbm = NULL;
|
---|
59 | ASN1_STRING *pbm_str = NULL;
|
---|
60 | const unsigned char *pbm_str_uc = NULL;
|
---|
61 |
|
---|
62 | if (ctx->secretValue == NULL) {
|
---|
63 | ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PBM_SECRET);
|
---|
64 | return NULL;
|
---|
65 | }
|
---|
66 | if (ppval == NULL) {
|
---|
67 | ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION);
|
---|
68 | return NULL;
|
---|
69 | }
|
---|
70 |
|
---|
71 | len = i2d_OSSL_CMP_PROTECTEDPART(&prot_part, &prot_part_der);
|
---|
72 | if (len < 0 || prot_part_der == NULL) {
|
---|
73 | ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION);
|
---|
74 | goto end;
|
---|
75 | }
|
---|
76 | prot_part_der_len = (size_t)len;
|
---|
77 |
|
---|
78 | pbm_str = (ASN1_STRING *)ppval;
|
---|
79 | pbm_str_uc = pbm_str->data;
|
---|
80 | pbm = d2i_OSSL_CRMF_PBMPARAMETER(NULL, &pbm_str_uc, pbm_str->length);
|
---|
81 | if (pbm == NULL) {
|
---|
82 | ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_ALGORITHM_OID);
|
---|
83 | goto end;
|
---|
84 | }
|
---|
85 |
|
---|
86 | if (!OSSL_CRMF_pbm_new(ctx->libctx, ctx->propq,
|
---|
87 | pbm, prot_part_der, prot_part_der_len,
|
---|
88 | ctx->secretValue->data, ctx->secretValue->length,
|
---|
89 | &protection, &sig_len))
|
---|
90 | goto end;
|
---|
91 |
|
---|
92 | if ((prot = ASN1_BIT_STRING_new()) == NULL)
|
---|
93 | goto end;
|
---|
94 | /* OpenSSL defaults all bit strings to be encoded as ASN.1 NamedBitList */
|
---|
95 | prot->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
|
---|
96 | prot->flags |= ASN1_STRING_FLAG_BITS_LEFT;
|
---|
97 | if (!ASN1_BIT_STRING_set(prot, protection, sig_len)) {
|
---|
98 | ASN1_BIT_STRING_free(prot);
|
---|
99 | prot = NULL;
|
---|
100 | }
|
---|
101 | end:
|
---|
102 | OSSL_CRMF_PBMPARAMETER_free(pbm);
|
---|
103 | OPENSSL_free(protection);
|
---|
104 | OPENSSL_free(prot_part_der);
|
---|
105 | return prot;
|
---|
106 | } else {
|
---|
107 | int md_nid;
|
---|
108 | const EVP_MD *md = NULL;
|
---|
109 |
|
---|
110 | if (ctx->pkey == NULL) {
|
---|
111 | ERR_raise(ERR_LIB_CMP,
|
---|
112 | CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
|
---|
113 | return NULL;
|
---|
114 | }
|
---|
115 | if (!OBJ_find_sigid_algs(OBJ_obj2nid(algorOID), &md_nid, NULL)
|
---|
116 | || (md = EVP_get_digestbynid(md_nid)) == NULL) {
|
---|
117 | ERR_raise(ERR_LIB_CMP, CMP_R_UNKNOWN_ALGORITHM_ID);
|
---|
118 | return NULL;
|
---|
119 | }
|
---|
120 |
|
---|
121 | if ((prot = ASN1_BIT_STRING_new()) == NULL)
|
---|
122 | return NULL;
|
---|
123 | if (ASN1_item_sign_ex(ASN1_ITEM_rptr(OSSL_CMP_PROTECTEDPART), NULL,
|
---|
124 | NULL, prot, &prot_part, NULL, ctx->pkey, md,
|
---|
125 | ctx->libctx, ctx->propq))
|
---|
126 | return prot;
|
---|
127 | ASN1_BIT_STRING_free(prot);
|
---|
128 | return NULL;
|
---|
129 | }
|
---|
130 | }
|
---|
131 |
|
---|
132 | int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
|
---|
133 | {
|
---|
134 | if (!ossl_assert(ctx != NULL && msg != NULL))
|
---|
135 | return 0;
|
---|
136 |
|
---|
137 | /* Add first ctx->cert and its chain if using signature-based protection */
|
---|
138 | if (!ctx->unprotectedSend && ctx->secretValue == NULL
|
---|
139 | && ctx->cert != NULL && ctx->pkey != NULL) {
|
---|
140 | int prepend = X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP
|
---|
141 | | X509_ADD_FLAG_PREPEND | X509_ADD_FLAG_NO_SS;
|
---|
142 |
|
---|
143 | /* if not yet done try to build chain using available untrusted certs */
|
---|
144 | if (ctx->chain == NULL) {
|
---|
145 | ossl_cmp_debug(ctx,
|
---|
146 | "trying to build chain for own CMP signer cert");
|
---|
147 | ctx->chain = X509_build_chain(ctx->cert, ctx->untrusted, NULL, 0,
|
---|
148 | ctx->libctx, ctx->propq);
|
---|
149 | if (ctx->chain != NULL) {
|
---|
150 | ossl_cmp_debug(ctx,
|
---|
151 | "success building chain for own CMP signer cert");
|
---|
152 | } else {
|
---|
153 | /* dump errors to avoid confusion when printing further ones */
|
---|
154 | OSSL_CMP_CTX_print_errors(ctx);
|
---|
155 | ossl_cmp_warn(ctx,
|
---|
156 | "could not build chain for own CMP signer cert");
|
---|
157 | }
|
---|
158 | }
|
---|
159 | if (ctx->chain != NULL) {
|
---|
160 | if (!ossl_x509_add_certs_new(&msg->extraCerts, ctx->chain, prepend))
|
---|
161 | return 0;
|
---|
162 | } else {
|
---|
163 | /* make sure that at least our own signer cert is included first */
|
---|
164 | if (!ossl_x509_add_cert_new(&msg->extraCerts, ctx->cert, prepend))
|
---|
165 | return 0;
|
---|
166 | ossl_cmp_debug(ctx, "fallback: adding just own CMP signer cert");
|
---|
167 | }
|
---|
168 | }
|
---|
169 |
|
---|
170 | /* add any additional certificates from ctx->extraCertsOut */
|
---|
171 | if (!ossl_x509_add_certs_new(&msg->extraCerts, ctx->extraCertsOut,
|
---|
172 | X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP))
|
---|
173 | return 0;
|
---|
174 |
|
---|
175 | /* in case extraCerts are empty list avoid empty ASN.1 sequence */
|
---|
176 | if (sk_X509_num(msg->extraCerts) == 0) {
|
---|
177 | sk_X509_free(msg->extraCerts);
|
---|
178 | msg->extraCerts = NULL;
|
---|
179 | }
|
---|
180 | return 1;
|
---|
181 | }
|
---|
182 |
|
---|
183 | /*
|
---|
184 | * Create an X509_ALGOR structure for PasswordBasedMAC protection based on
|
---|
185 | * the pbm settings in the context
|
---|
186 | */
|
---|
187 | static int set_pbmac_algor(const OSSL_CMP_CTX *ctx, X509_ALGOR **alg)
|
---|
188 | {
|
---|
189 | OSSL_CRMF_PBMPARAMETER *pbm = NULL;
|
---|
190 | unsigned char *pbm_der = NULL;
|
---|
191 | int pbm_der_len;
|
---|
192 | ASN1_STRING *pbm_str = NULL;
|
---|
193 |
|
---|
194 | if (!ossl_assert(ctx != NULL))
|
---|
195 | return 0;
|
---|
196 |
|
---|
197 | pbm = OSSL_CRMF_pbmp_new(ctx->libctx, ctx->pbm_slen,
|
---|
198 | EVP_MD_get_type(ctx->pbm_owf), ctx->pbm_itercnt,
|
---|
199 | ctx->pbm_mac);
|
---|
200 | pbm_str = ASN1_STRING_new();
|
---|
201 | if (pbm == NULL || pbm_str == NULL)
|
---|
202 | goto err;
|
---|
203 |
|
---|
204 | if ((pbm_der_len = i2d_OSSL_CRMF_PBMPARAMETER(pbm, &pbm_der)) < 0)
|
---|
205 | goto err;
|
---|
206 |
|
---|
207 | if (!ASN1_STRING_set(pbm_str, pbm_der, pbm_der_len))
|
---|
208 | goto err;
|
---|
209 | if (*alg == NULL && (*alg = X509_ALGOR_new()) == NULL)
|
---|
210 | goto err;
|
---|
211 | OPENSSL_free(pbm_der);
|
---|
212 |
|
---|
213 | X509_ALGOR_set0(*alg, OBJ_nid2obj(NID_id_PasswordBasedMAC),
|
---|
214 | V_ASN1_SEQUENCE, pbm_str);
|
---|
215 | OSSL_CRMF_PBMPARAMETER_free(pbm);
|
---|
216 | return 1;
|
---|
217 |
|
---|
218 | err:
|
---|
219 | ASN1_STRING_free(pbm_str);
|
---|
220 | OPENSSL_free(pbm_der);
|
---|
221 | OSSL_CRMF_PBMPARAMETER_free(pbm);
|
---|
222 | return 0;
|
---|
223 | }
|
---|
224 |
|
---|
225 | static int set_sig_algor(const OSSL_CMP_CTX *ctx, X509_ALGOR **alg)
|
---|
226 | {
|
---|
227 | int nid = 0;
|
---|
228 | ASN1_OBJECT *algo = NULL;
|
---|
229 |
|
---|
230 | if (!OBJ_find_sigid_by_algs(&nid, EVP_MD_get_type(ctx->digest),
|
---|
231 | EVP_PKEY_get_id(ctx->pkey))) {
|
---|
232 | ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_KEY_TYPE);
|
---|
233 | return 0;
|
---|
234 | }
|
---|
235 | if ((algo = OBJ_nid2obj(nid)) == NULL)
|
---|
236 | return 0;
|
---|
237 | if (*alg == NULL && (*alg = X509_ALGOR_new()) == NULL)
|
---|
238 | return 0;
|
---|
239 |
|
---|
240 | if (X509_ALGOR_set0(*alg, algo, V_ASN1_UNDEF, NULL))
|
---|
241 | return 1;
|
---|
242 | ASN1_OBJECT_free(algo);
|
---|
243 | return 0;
|
---|
244 | }
|
---|
245 |
|
---|
246 | static int set_senderKID(const OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg,
|
---|
247 | const ASN1_OCTET_STRING *id)
|
---|
248 | {
|
---|
249 | if (id == NULL)
|
---|
250 | id = ctx->referenceValue; /* standard for PBM, fallback for sig-based */
|
---|
251 | return id == NULL || ossl_cmp_hdr_set1_senderKID(msg->header, id);
|
---|
252 | }
|
---|
253 |
|
---|
254 | int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
|
---|
255 | {
|
---|
256 | if (!ossl_assert(ctx != NULL && msg != NULL))
|
---|
257 | return 0;
|
---|
258 |
|
---|
259 | /*
|
---|
260 | * For the case of re-protection remove pre-existing protection.
|
---|
261 | */
|
---|
262 | X509_ALGOR_free(msg->header->protectionAlg);
|
---|
263 | msg->header->protectionAlg = NULL;
|
---|
264 | ASN1_BIT_STRING_free(msg->protection);
|
---|
265 | msg->protection = NULL;
|
---|
266 |
|
---|
267 | if (ctx->unprotectedSend) {
|
---|
268 | if (!set_senderKID(ctx, msg, NULL))
|
---|
269 | goto err;
|
---|
270 | } else if (ctx->secretValue != NULL) {
|
---|
271 | /* use PasswordBasedMac according to 5.1.3.1 if secretValue is given */
|
---|
272 | if (!set_pbmac_algor(ctx, &msg->header->protectionAlg))
|
---|
273 | goto err;
|
---|
274 | if (!set_senderKID(ctx, msg, NULL))
|
---|
275 | goto err;
|
---|
276 |
|
---|
277 | /*
|
---|
278 | * will add any additional certificates from ctx->extraCertsOut
|
---|
279 | * while not needed to validate the protection certificate,
|
---|
280 | * the option to do this might be handy for certain use cases
|
---|
281 | */
|
---|
282 | } else if (ctx->cert != NULL && ctx->pkey != NULL) {
|
---|
283 | /* use MSG_SIG_ALG according to 5.1.3.3 if client cert and key given */
|
---|
284 |
|
---|
285 | /* make sure that key and certificate match */
|
---|
286 | if (!X509_check_private_key(ctx->cert, ctx->pkey)) {
|
---|
287 | ERR_raise(ERR_LIB_CMP, CMP_R_CERT_AND_KEY_DO_NOT_MATCH);
|
---|
288 | goto err;
|
---|
289 | }
|
---|
290 |
|
---|
291 | if (!set_sig_algor(ctx, &msg->header->protectionAlg))
|
---|
292 | goto err;
|
---|
293 | /* set senderKID to keyIdentifier of the cert according to 5.1.1 */
|
---|
294 | if (!set_senderKID(ctx, msg, X509_get0_subject_key_id(ctx->cert)))
|
---|
295 | goto err;
|
---|
296 |
|
---|
297 | /*
|
---|
298 | * will add ctx->cert followed, if possible, by its chain built
|
---|
299 | * from ctx->untrusted, and then ctx->extraCertsOut
|
---|
300 | */
|
---|
301 | } else {
|
---|
302 | ERR_raise(ERR_LIB_CMP,
|
---|
303 | CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
|
---|
304 | goto err;
|
---|
305 | }
|
---|
306 | if (!ctx->unprotectedSend
|
---|
307 | && ((msg->protection = ossl_cmp_calc_protection(ctx, msg)) == NULL))
|
---|
308 | goto err;
|
---|
309 |
|
---|
310 | /*
|
---|
311 | * For signature-based protection add ctx->cert followed by its chain.
|
---|
312 | * Finally add any additional certificates from ctx->extraCertsOut;
|
---|
313 | * even if not needed to validate the protection
|
---|
314 | * the option to do this might be handy for certain use cases.
|
---|
315 | */
|
---|
316 | if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
|
---|
317 | goto err;
|
---|
318 |
|
---|
319 | /*
|
---|
320 | * As required by RFC 4210 section 5.1.1., if the sender name is not known
|
---|
321 | * to the client it set to NULL-DN. In this case for identification at least
|
---|
322 | * the senderKID must be set, where we took the referenceValue as fallback.
|
---|
323 | */
|
---|
324 | if (!(ossl_cmp_general_name_is_NULL_DN(msg->header->sender)
|
---|
325 | && msg->header->senderKID == NULL))
|
---|
326 | return 1;
|
---|
327 | ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_SENDER_IDENTIFICATION);
|
---|
328 |
|
---|
329 | err:
|
---|
330 | ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROTECTING_MESSAGE);
|
---|
331 | return 0;
|
---|
332 | }
|
---|