]>
Commit | Line | Data |
---|---|---|
3dbc5156 | 1 | /* |
fecb3aae | 2 | * Copyright 2007-2022 The OpenSSL Project Authors. All Rights Reserved. |
3dbc5156 DDO |
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" | |
9944df11 | 13 | #include "crypto/asn1.h" |
3dbc5156 DDO |
14 | |
15 | /* explicit #includes not strictly needed since implied by the above: */ | |
16 | #include <openssl/asn1t.h> | |
17 | #include <openssl/cmp.h> | |
18 | #include <openssl/crmf.h> | |
19 | #include <openssl/err.h> | |
20 | #include <openssl/x509.h> | |
21 | ||
22 | /* | |
6d1f50b5 | 23 | * This function is also used by the internal verify_PBMAC() in cmp_vfy.c. |
3dbc5156 | 24 | * |
6d1f50b5 DDO |
25 | * Calculate protection for given PKImessage according to |
26 | * the algorithm and parameters in the message header's protectionAlg | |
27 | * using the credentials, library context, and property criteria in the ctx. | |
3dbc5156 | 28 | * |
6d1f50b5 | 29 | * returns ASN1_BIT_STRING representing the protection on success, else NULL |
3dbc5156 | 30 | */ |
6d1f50b5 DDO |
31 | ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx, |
32 | const OSSL_CMP_MSG *msg) | |
3dbc5156 DDO |
33 | { |
34 | ASN1_BIT_STRING *prot = NULL; | |
642f60d8 | 35 | OSSL_CMP_PROTECTEDPART prot_part; |
3dbc5156 | 36 | const ASN1_OBJECT *algorOID = NULL; |
3dbc5156 DDO |
37 | const void *ppval = NULL; |
38 | int pptype = 0; | |
3dbc5156 | 39 | |
6d1f50b5 | 40 | if (!ossl_assert(ctx != NULL && msg != NULL)) |
3dbc5156 DDO |
41 | return NULL; |
42 | ||
43 | /* construct data to be signed */ | |
44 | prot_part.header = msg->header; | |
45 | prot_part.body = msg->body; | |
46 | ||
3dbc5156 | 47 | if (msg->header->protectionAlg == NULL) { |
9311d0c4 | 48 | ERR_raise(ERR_LIB_CMP, CMP_R_UNKNOWN_ALGORITHM_ID); |
6d1f50b5 | 49 | return NULL; |
3dbc5156 DDO |
50 | } |
51 | X509_ALGOR_get0(&algorOID, &pptype, &ppval, msg->header->protectionAlg); | |
52 | ||
6d1f50b5 DDO |
53 | if (OBJ_obj2nid(algorOID) == NID_id_PasswordBasedMAC) { |
54 | int len; | |
55 | size_t prot_part_der_len; | |
56 | unsigned char *prot_part_der = NULL; | |
57 | size_t sig_len; | |
58 | unsigned char *protection = NULL; | |
59 | OSSL_CRMF_PBMPARAMETER *pbm = NULL; | |
60 | ASN1_STRING *pbm_str = NULL; | |
61 | const unsigned char *pbm_str_uc = NULL; | |
62 | ||
63 | if (ctx->secretValue == NULL) { | |
9311d0c4 | 64 | ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PBM_SECRET); |
6d1f50b5 DDO |
65 | return NULL; |
66 | } | |
3dbc5156 | 67 | if (ppval == NULL) { |
9311d0c4 | 68 | ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION); |
6d1f50b5 | 69 | return NULL; |
3dbc5156 | 70 | } |
6d1f50b5 DDO |
71 | |
72 | len = i2d_OSSL_CMP_PROTECTEDPART(&prot_part, &prot_part_der); | |
73 | if (len < 0 || prot_part_der == NULL) { | |
9311d0c4 | 74 | ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION); |
3dbc5156 DDO |
75 | goto end; |
76 | } | |
6d1f50b5 DDO |
77 | prot_part_der_len = (size_t)len; |
78 | ||
3dbc5156 DDO |
79 | pbm_str = (ASN1_STRING *)ppval; |
80 | pbm_str_uc = pbm_str->data; | |
81 | pbm = d2i_OSSL_CRMF_PBMPARAMETER(NULL, &pbm_str_uc, pbm_str->length); | |
82 | if (pbm == NULL) { | |
9311d0c4 | 83 | ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_ALGORITHM_OID); |
3dbc5156 DDO |
84 | goto end; |
85 | } | |
86 | ||
6d1f50b5 DDO |
87 | if (!OSSL_CRMF_pbm_new(ctx->libctx, ctx->propq, |
88 | pbm, prot_part_der, prot_part_der_len, | |
89 | ctx->secretValue->data, ctx->secretValue->length, | |
3dbc5156 DDO |
90 | &protection, &sig_len)) |
91 | goto end; | |
3dbc5156 | 92 | |
6d1f50b5 | 93 | if ((prot = ASN1_BIT_STRING_new()) == NULL) |
74c929d0 | 94 | goto end; |
6d1f50b5 | 95 | /* OpenSSL defaults all bit strings to be encoded as ASN.1 NamedBitList */ |
7c310e87 | 96 | ossl_asn1_string_set_bits_left(prot, 0); |
6d1f50b5 DDO |
97 | if (!ASN1_BIT_STRING_set(prot, protection, sig_len)) { |
98 | ASN1_BIT_STRING_free(prot); | |
99 | prot = NULL; | |
3dbc5156 | 100 | } |
6d1f50b5 DDO |
101 | end: |
102 | OSSL_CRMF_PBMPARAMETER_free(pbm); | |
103 | OPENSSL_free(protection); | |
104 | OPENSSL_free(prot_part_der); | |
105 | return prot; | |
3dbc5156 | 106 | } else { |
6d1f50b5 DDO |
107 | int md_nid; |
108 | const EVP_MD *md = NULL; | |
3dbc5156 | 109 | |
6d1f50b5 | 110 | if (ctx->pkey == NULL) { |
9311d0c4 RL |
111 | ERR_raise(ERR_LIB_CMP, |
112 | CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION); | |
6d1f50b5 DDO |
113 | return NULL; |
114 | } | |
115 | if (!OBJ_find_sigid_algs(OBJ_obj2nid(algorOID), &md_nid, NULL) | |
116 | || (md = EVP_get_digestbynid(md_nid)) == NULL) { | |
9311d0c4 | 117 | ERR_raise(ERR_LIB_CMP, CMP_R_UNKNOWN_ALGORITHM_ID); |
6d1f50b5 DDO |
118 | return NULL; |
119 | } | |
120 | ||
121 | if ((prot = ASN1_BIT_STRING_new()) == NULL) | |
122 | return NULL; | |
d8652be0 MC |
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)) | |
6d1f50b5 | 126 | return prot; |
3dbc5156 | 127 | ASN1_BIT_STRING_free(prot); |
6d1f50b5 | 128 | return NULL; |
3dbc5156 | 129 | } |
3dbc5156 DDO |
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 | ||
a0745e2b | 137 | /* Add first ctx->cert and its chain if using signature-based protection */ |
61994781 DDO |
138 | if (!ctx->unprotectedSend && ctx->secretValue == NULL |
139 | && ctx->cert != NULL && ctx->pkey != NULL) { | |
daf1300b | 140 | int prepend = X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP |
a0745e2b | 141 | | X509_ADD_FLAG_PREPEND | X509_ADD_FLAG_NO_SS; |
1a5ae1da | 142 | |
a0745e2b DDO |
143 | /* if not yet done try to build chain using available untrusted certs */ |
144 | if (ctx->chain == NULL) { | |
1a5ae1da DDO |
145 | ossl_cmp_debug(ctx, |
146 | "trying to build chain for own CMP signer cert"); | |
1c0eede9 DDO |
147 | ctx->chain = X509_build_chain(ctx->cert, ctx->untrusted, NULL, 0, |
148 | ctx->libctx, ctx->propq); | |
a0745e2b DDO |
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"); | |
1a5ae1da | 157 | } |
a0745e2b DDO |
158 | } |
159 | if (ctx->chain != NULL) { | |
daf1300b | 160 | if (!ossl_x509_add_certs_new(&msg->extraCerts, ctx->chain, prepend)) |
a0745e2b DDO |
161 | return 0; |
162 | } else { | |
163 | /* make sure that at least our own signer cert is included first */ | |
c1be4d61 | 164 | if (!ossl_x509_add_cert_new(&msg->extraCerts, ctx->cert, prepend)) |
a0745e2b | 165 | return 0; |
daf1300b | 166 | ossl_cmp_debug(ctx, "fallback: adding just own CMP signer cert"); |
3dbc5156 DDO |
167 | } |
168 | } | |
169 | ||
170 | /* add any additional certificates from ctx->extraCertsOut */ | |
daf1300b DDO |
171 | if (!ossl_x509_add_certs_new(&msg->extraCerts, ctx->extraCertsOut, |
172 | X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP)) | |
3dbc5156 DDO |
173 | return 0; |
174 | ||
543a802f | 175 | /* in case extraCerts are empty list avoid empty ASN.1 sequence */ |
3dbc5156 DDO |
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 | |
3dbc5156 | 186 | */ |
9944df11 | 187 | static X509_ALGOR *pbmac_algor(const OSSL_CMP_CTX *ctx) |
3dbc5156 | 188 | { |
3dbc5156 DDO |
189 | OSSL_CRMF_PBMPARAMETER *pbm = NULL; |
190 | unsigned char *pbm_der = NULL; | |
191 | int pbm_der_len; | |
192 | ASN1_STRING *pbm_str = NULL; | |
9944df11 | 193 | X509_ALGOR *alg = NULL; |
3dbc5156 DDO |
194 | |
195 | if (!ossl_assert(ctx != NULL)) | |
9944df11 | 196 | return NULL; |
3dbc5156 | 197 | |
97e00da9 | 198 | pbm = OSSL_CRMF_pbmp_new(ctx->libctx, ctx->pbm_slen, |
ed576acd | 199 | EVP_MD_get_type(ctx->pbm_owf), ctx->pbm_itercnt, |
6d1f50b5 | 200 | ctx->pbm_mac); |
3dbc5156 | 201 | pbm_str = ASN1_STRING_new(); |
6d1f50b5 | 202 | if (pbm == NULL || pbm_str == NULL) |
3dbc5156 | 203 | goto err; |
3dbc5156 DDO |
204 | if ((pbm_der_len = i2d_OSSL_CRMF_PBMPARAMETER(pbm, &pbm_der)) < 0) |
205 | goto err; | |
3dbc5156 DDO |
206 | if (!ASN1_STRING_set(pbm_str, pbm_der, pbm_der_len)) |
207 | goto err; | |
9944df11 DDO |
208 | alg = ossl_X509_ALGOR_from_nid(NID_id_PasswordBasedMAC, |
209 | V_ASN1_SEQUENCE, pbm_str); | |
3dbc5156 | 210 | err: |
9944df11 DDO |
211 | if (alg == NULL) |
212 | ASN1_STRING_free(pbm_str); | |
3dbc5156 DDO |
213 | OPENSSL_free(pbm_der); |
214 | OSSL_CRMF_PBMPARAMETER_free(pbm); | |
9944df11 | 215 | return alg; |
6d1f50b5 DDO |
216 | } |
217 | ||
9944df11 | 218 | static X509_ALGOR *sig_algor(const OSSL_CMP_CTX *ctx) |
6d1f50b5 DDO |
219 | { |
220 | int nid = 0; | |
6d1f50b5 | 221 | |
ed576acd TM |
222 | if (!OBJ_find_sigid_by_algs(&nid, EVP_MD_get_type(ctx->digest), |
223 | EVP_PKEY_get_id(ctx->pkey))) { | |
9311d0c4 | 224 | ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_KEY_TYPE); |
6d1f50b5 DDO |
225 | return 0; |
226 | } | |
9944df11 | 227 | return ossl_X509_ALGOR_from_nid(nid, V_ASN1_UNDEF, NULL); |
6d1f50b5 DDO |
228 | } |
229 | ||
230 | static int set_senderKID(const OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg, | |
231 | const ASN1_OCTET_STRING *id) | |
232 | { | |
233 | if (id == NULL) | |
234 | id = ctx->referenceValue; /* standard for PBM, fallback for sig-based */ | |
235 | return id == NULL || ossl_cmp_hdr_set1_senderKID(msg->header, id); | |
3dbc5156 DDO |
236 | } |
237 | ||
238 | int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg) | |
239 | { | |
240 | if (!ossl_assert(ctx != NULL && msg != NULL)) | |
241 | return 0; | |
242 | ||
143be474 DDO |
243 | /* |
244 | * For the case of re-protection remove pre-existing protection. | |
143be474 DDO |
245 | */ |
246 | X509_ALGOR_free(msg->header->protectionAlg); | |
247 | msg->header->protectionAlg = NULL; | |
248 | ASN1_BIT_STRING_free(msg->protection); | |
249 | msg->protection = NULL; | |
250 | ||
543a802f DDO |
251 | if (ctx->unprotectedSend) { |
252 | if (!set_senderKID(ctx, msg, NULL)) | |
253 | goto err; | |
254 | } else if (ctx->secretValue != NULL) { | |
255 | /* use PasswordBasedMac according to 5.1.3.1 if secretValue is given */ | |
9944df11 | 256 | if ((msg->header->protectionAlg = pbmac_algor(ctx)) == NULL) |
3dbc5156 | 257 | goto err; |
6d1f50b5 | 258 | if (!set_senderKID(ctx, msg, NULL)) |
3dbc5156 | 259 | goto err; |
6d1f50b5 | 260 | |
3dbc5156 | 261 | /* |
6d1f50b5 DDO |
262 | * will add any additional certificates from ctx->extraCertsOut |
263 | * while not needed to validate the protection certificate, | |
264 | * the option to do this might be handy for certain use cases | |
3dbc5156 | 265 | */ |
6d1f50b5 DDO |
266 | } else if (ctx->cert != NULL && ctx->pkey != NULL) { |
267 | /* use MSG_SIG_ALG according to 5.1.3.3 if client cert and key given */ | |
3dbc5156 | 268 | |
143be474 | 269 | /* make sure that key and certificate match */ |
63f1883d | 270 | if (!X509_check_private_key(ctx->cert, ctx->pkey)) { |
9311d0c4 | 271 | ERR_raise(ERR_LIB_CMP, CMP_R_CERT_AND_KEY_DO_NOT_MATCH); |
143be474 DDO |
272 | goto err; |
273 | } | |
3dbc5156 | 274 | |
9944df11 | 275 | if ((msg->header->protectionAlg = sig_algor(ctx)) == NULL) |
143be474 | 276 | goto err; |
6d1f50b5 DDO |
277 | /* set senderKID to keyIdentifier of the cert according to 5.1.1 */ |
278 | if (!set_senderKID(ctx, msg, X509_get0_subject_key_id(ctx->cert))) | |
143be474 | 279 | goto err; |
143be474 DDO |
280 | |
281 | /* | |
6d1f50b5 | 282 | * will add ctx->cert followed, if possible, by its chain built |
0b86eefd | 283 | * from ctx->untrusted, and then ctx->extraCertsOut |
143be474 | 284 | */ |
143be474 | 285 | } else { |
9311d0c4 RL |
286 | ERR_raise(ERR_LIB_CMP, |
287 | CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION); | |
143be474 | 288 | goto err; |
3dbc5156 | 289 | } |
543a802f DDO |
290 | if (!ctx->unprotectedSend |
291 | && ((msg->protection = ossl_cmp_calc_protection(ctx, msg)) == NULL)) | |
143be474 DDO |
292 | goto err; |
293 | ||
294 | /* | |
543a802f | 295 | * For signature-based protection add ctx->cert followed by its chain. |
143be474 DDO |
296 | * Finally add any additional certificates from ctx->extraCertsOut; |
297 | * even if not needed to validate the protection | |
298 | * the option to do this might be handy for certain use cases. | |
299 | */ | |
300 | if (!ossl_cmp_msg_add_extraCerts(ctx, msg)) | |
301 | goto err; | |
3dbc5156 | 302 | |
cfca56df DDO |
303 | /* |
304 | * As required by RFC 4210 section 5.1.1., if the sender name is not known | |
305 | * to the client it set to NULL-DN. In this case for identification at least | |
306 | * the senderKID must be set, where we took the referenceValue as fallback. | |
307 | */ | |
543a802f DDO |
308 | if (!(ossl_cmp_general_name_is_NULL_DN(msg->header->sender) |
309 | && msg->header->senderKID == NULL)) | |
cfca56df | 310 | return 1; |
9311d0c4 | 311 | ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_SENDER_IDENTIFICATION); |
cfca56df | 312 | |
3dbc5156 | 313 | err: |
9311d0c4 | 314 | ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROTECTING_MESSAGE); |
3dbc5156 DDO |
315 | return 0; |
316 | } |