1b077aed3SPierre Pronchery /*
2*a7148ab3SEnji Cooper * Copyright 2007-2024 The OpenSSL Project Authors. All Rights Reserved.
3b077aed3SPierre Pronchery * Copyright Nokia 2007-2020
4b077aed3SPierre Pronchery * Copyright Siemens AG 2015-2020
5b077aed3SPierre Pronchery *
6b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
7b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy
8b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at
9b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html
10b077aed3SPierre Pronchery */
11b077aed3SPierre Pronchery
12b077aed3SPierre Pronchery /* CMP functions for PKIMessage checking */
13b077aed3SPierre Pronchery
14b077aed3SPierre Pronchery #include "cmp_local.h"
15b077aed3SPierre Pronchery #include <openssl/cmp_util.h>
16b077aed3SPierre Pronchery
17b077aed3SPierre Pronchery /* explicit #includes not strictly needed since implied by the above: */
18b077aed3SPierre Pronchery #include <openssl/asn1t.h>
19b077aed3SPierre Pronchery #include <openssl/cmp.h>
20b077aed3SPierre Pronchery #include <openssl/crmf.h>
21b077aed3SPierre Pronchery #include <openssl/err.h>
22b077aed3SPierre Pronchery #include <openssl/x509.h>
23b077aed3SPierre Pronchery
24b077aed3SPierre Pronchery /* Verify a message protected by signature according to RFC section 5.1.3.3 */
verify_signature(const OSSL_CMP_CTX * cmp_ctx,const OSSL_CMP_MSG * msg,X509 * cert)25b077aed3SPierre Pronchery static int verify_signature(const OSSL_CMP_CTX *cmp_ctx,
26b077aed3SPierre Pronchery const OSSL_CMP_MSG *msg, X509 *cert)
27b077aed3SPierre Pronchery {
28b077aed3SPierre Pronchery OSSL_CMP_PROTECTEDPART prot_part;
29b077aed3SPierre Pronchery EVP_PKEY *pubkey = NULL;
30b077aed3SPierre Pronchery BIO *bio;
31b077aed3SPierre Pronchery int res = 0;
32b077aed3SPierre Pronchery
33b077aed3SPierre Pronchery if (!ossl_assert(cmp_ctx != NULL && msg != NULL && cert != NULL))
34b077aed3SPierre Pronchery return 0;
35b077aed3SPierre Pronchery
36b077aed3SPierre Pronchery bio = BIO_new(BIO_s_mem()); /* may be NULL */
37b077aed3SPierre Pronchery
38b077aed3SPierre Pronchery /* verify that keyUsage, if present, contains digitalSignature */
39b077aed3SPierre Pronchery if (!cmp_ctx->ignore_keyusage
40b077aed3SPierre Pronchery && (X509_get_key_usage(cert) & X509v3_KU_DIGITAL_SIGNATURE) == 0) {
41b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE);
42b077aed3SPierre Pronchery goto sig_err;
43b077aed3SPierre Pronchery }
44b077aed3SPierre Pronchery
45b077aed3SPierre Pronchery pubkey = X509_get_pubkey(cert);
46b077aed3SPierre Pronchery if (pubkey == NULL) {
47b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_FAILED_EXTRACTING_PUBKEY);
48b077aed3SPierre Pronchery goto sig_err;
49b077aed3SPierre Pronchery }
50b077aed3SPierre Pronchery
51b077aed3SPierre Pronchery prot_part.header = msg->header;
52b077aed3SPierre Pronchery prot_part.body = msg->body;
53b077aed3SPierre Pronchery
54b077aed3SPierre Pronchery if (ASN1_item_verify_ex(ASN1_ITEM_rptr(OSSL_CMP_PROTECTEDPART),
55b077aed3SPierre Pronchery msg->header->protectionAlg, msg->protection,
56b077aed3SPierre Pronchery &prot_part, NULL, pubkey, cmp_ctx->libctx,
57b077aed3SPierre Pronchery cmp_ctx->propq) > 0) {
58b077aed3SPierre Pronchery res = 1;
59b077aed3SPierre Pronchery goto end;
60b077aed3SPierre Pronchery }
61b077aed3SPierre Pronchery
62b077aed3SPierre Pronchery sig_err:
63b077aed3SPierre Pronchery res = ossl_x509_print_ex_brief(bio, cert, X509_FLAG_NO_EXTENSIONS);
64b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_SIGNATURE);
65b077aed3SPierre Pronchery if (res)
66b077aed3SPierre Pronchery ERR_add_error_mem_bio("\n", bio);
67b077aed3SPierre Pronchery res = 0;
68b077aed3SPierre Pronchery
69b077aed3SPierre Pronchery end:
70b077aed3SPierre Pronchery EVP_PKEY_free(pubkey);
71b077aed3SPierre Pronchery BIO_free(bio);
72b077aed3SPierre Pronchery
73b077aed3SPierre Pronchery return res;
74b077aed3SPierre Pronchery }
75b077aed3SPierre Pronchery
76b077aed3SPierre Pronchery /* Verify a message protected with PBMAC */
verify_PBMAC(OSSL_CMP_CTX * ctx,const OSSL_CMP_MSG * msg)77b077aed3SPierre Pronchery static int verify_PBMAC(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
78b077aed3SPierre Pronchery {
79b077aed3SPierre Pronchery ASN1_BIT_STRING *protection = NULL;
80b077aed3SPierre Pronchery int valid = 0;
81b077aed3SPierre Pronchery
82b077aed3SPierre Pronchery /* generate expected protection for the message */
83b077aed3SPierre Pronchery if ((protection = ossl_cmp_calc_protection(ctx, msg)) == NULL)
84b077aed3SPierre Pronchery return 0; /* failed to generate protection string! */
85b077aed3SPierre Pronchery
86b077aed3SPierre Pronchery valid = msg->protection != NULL && msg->protection->length >= 0
87b077aed3SPierre Pronchery && msg->protection->type == protection->type
88b077aed3SPierre Pronchery && msg->protection->length == protection->length
89b077aed3SPierre Pronchery && CRYPTO_memcmp(msg->protection->data, protection->data,
90b077aed3SPierre Pronchery protection->length) == 0;
91b077aed3SPierre Pronchery ASN1_BIT_STRING_free(protection);
92b077aed3SPierre Pronchery if (!valid)
93b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_PBM_VALUE);
94b077aed3SPierre Pronchery
95b077aed3SPierre Pronchery return valid;
96b077aed3SPierre Pronchery }
97b077aed3SPierre Pronchery
98b077aed3SPierre Pronchery /*-
99b077aed3SPierre Pronchery * Attempt to validate certificate and path using any given store with trusted
100b077aed3SPierre Pronchery * certs (possibly including CRLs and a cert verification callback function)
101b077aed3SPierre Pronchery * and non-trusted intermediate certs from the given ctx.
102b077aed3SPierre Pronchery *
103b077aed3SPierre Pronchery * Returns 1 on successful validation and 0 otherwise.
104b077aed3SPierre Pronchery */
OSSL_CMP_validate_cert_path(const OSSL_CMP_CTX * ctx,X509_STORE * trusted_store,X509 * cert)105b077aed3SPierre Pronchery int OSSL_CMP_validate_cert_path(const OSSL_CMP_CTX *ctx,
106b077aed3SPierre Pronchery X509_STORE *trusted_store, X509 *cert)
107b077aed3SPierre Pronchery {
108b077aed3SPierre Pronchery int valid = 0;
109b077aed3SPierre Pronchery X509_STORE_CTX *csc = NULL;
110b077aed3SPierre Pronchery int err;
111b077aed3SPierre Pronchery
112b077aed3SPierre Pronchery if (ctx == NULL || cert == NULL) {
113b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
114b077aed3SPierre Pronchery return 0;
115b077aed3SPierre Pronchery }
116b077aed3SPierre Pronchery
117b077aed3SPierre Pronchery if (trusted_store == NULL) {
118b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_TRUST_STORE);
119b077aed3SPierre Pronchery return 0;
120b077aed3SPierre Pronchery }
121b077aed3SPierre Pronchery
122b077aed3SPierre Pronchery if ((csc = X509_STORE_CTX_new_ex(ctx->libctx, ctx->propq)) == NULL
123b077aed3SPierre Pronchery || !X509_STORE_CTX_init(csc, trusted_store,
124b077aed3SPierre Pronchery cert, ctx->untrusted))
125b077aed3SPierre Pronchery goto err;
126b077aed3SPierre Pronchery
127b077aed3SPierre Pronchery valid = X509_verify_cert(csc) > 0;
128b077aed3SPierre Pronchery
129b077aed3SPierre Pronchery /* make sure suitable error is queued even if callback did not do */
130b077aed3SPierre Pronchery err = ERR_peek_last_error();
131b077aed3SPierre Pronchery if (!valid && ERR_GET_REASON(err) != CMP_R_POTENTIALLY_INVALID_CERTIFICATE)
132b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_POTENTIALLY_INVALID_CERTIFICATE);
133b077aed3SPierre Pronchery
134b077aed3SPierre Pronchery err:
135b077aed3SPierre Pronchery /* directly output any fresh errors, needed for check_msg_find_cert() */
136b077aed3SPierre Pronchery OSSL_CMP_CTX_print_errors(ctx);
137b077aed3SPierre Pronchery X509_STORE_CTX_free(csc);
138b077aed3SPierre Pronchery return valid;
139b077aed3SPierre Pronchery }
140b077aed3SPierre Pronchery
141b077aed3SPierre Pronchery /* Return 0 if expect_name != NULL and there is no matching actual_name */
check_name(const OSSL_CMP_CTX * ctx,int log_success,const char * actual_desc,const X509_NAME * actual_name,const char * expect_desc,const X509_NAME * expect_name)142b077aed3SPierre Pronchery static int check_name(const OSSL_CMP_CTX *ctx, int log_success,
143b077aed3SPierre Pronchery const char *actual_desc, const X509_NAME *actual_name,
144b077aed3SPierre Pronchery const char *expect_desc, const X509_NAME *expect_name)
145b077aed3SPierre Pronchery {
146b077aed3SPierre Pronchery char *str;
147b077aed3SPierre Pronchery
148b077aed3SPierre Pronchery if (expect_name == NULL)
149b077aed3SPierre Pronchery return 1; /* no expectation, thus trivially fulfilled */
150b077aed3SPierre Pronchery
151b077aed3SPierre Pronchery /* make sure that a matching name is there */
152b077aed3SPierre Pronchery if (actual_name == NULL) {
153b077aed3SPierre Pronchery ossl_cmp_log1(WARN, ctx, "missing %s", actual_desc);
154b077aed3SPierre Pronchery return 0;
155b077aed3SPierre Pronchery }
156b077aed3SPierre Pronchery str = X509_NAME_oneline(actual_name, NULL, 0);
157b077aed3SPierre Pronchery if (X509_NAME_cmp(actual_name, expect_name) == 0) {
158b077aed3SPierre Pronchery if (log_success && str != NULL)
159b077aed3SPierre Pronchery ossl_cmp_log2(INFO, ctx, " subject matches %s: %s", expect_desc,
160b077aed3SPierre Pronchery str);
161b077aed3SPierre Pronchery OPENSSL_free(str);
162b077aed3SPierre Pronchery return 1;
163b077aed3SPierre Pronchery }
164b077aed3SPierre Pronchery
165b077aed3SPierre Pronchery if (str != NULL)
166b077aed3SPierre Pronchery ossl_cmp_log2(INFO, ctx, " actual name in %s = %s", actual_desc, str);
167b077aed3SPierre Pronchery OPENSSL_free(str);
168b077aed3SPierre Pronchery if ((str = X509_NAME_oneline(expect_name, NULL, 0)) != NULL)
169b077aed3SPierre Pronchery ossl_cmp_log2(INFO, ctx, " does not match %s = %s", expect_desc, str);
170b077aed3SPierre Pronchery OPENSSL_free(str);
171b077aed3SPierre Pronchery return 0;
172b077aed3SPierre Pronchery }
173b077aed3SPierre Pronchery
174b077aed3SPierre Pronchery /* Return 0 if skid != NULL and there is no matching subject key ID in cert */
check_kid(const OSSL_CMP_CTX * ctx,const ASN1_OCTET_STRING * ckid,const ASN1_OCTET_STRING * skid)175b077aed3SPierre Pronchery static int check_kid(const OSSL_CMP_CTX *ctx,
176b077aed3SPierre Pronchery const ASN1_OCTET_STRING *ckid,
177b077aed3SPierre Pronchery const ASN1_OCTET_STRING *skid)
178b077aed3SPierre Pronchery {
179b077aed3SPierre Pronchery char *str;
180b077aed3SPierre Pronchery
181b077aed3SPierre Pronchery if (skid == NULL)
182b077aed3SPierre Pronchery return 1; /* no expectation, thus trivially fulfilled */
183b077aed3SPierre Pronchery
184b077aed3SPierre Pronchery /* make sure that the expected subject key identifier is there */
185b077aed3SPierre Pronchery if (ckid == NULL) {
186b077aed3SPierre Pronchery ossl_cmp_warn(ctx, "missing Subject Key Identifier in certificate");
187b077aed3SPierre Pronchery return 0;
188b077aed3SPierre Pronchery }
189b077aed3SPierre Pronchery str = OPENSSL_buf2hexstr(ckid->data, ckid->length);
190b077aed3SPierre Pronchery if (ASN1_OCTET_STRING_cmp(ckid, skid) == 0) {
191b077aed3SPierre Pronchery if (str != NULL)
192b077aed3SPierre Pronchery ossl_cmp_log1(INFO, ctx, " subjectKID matches senderKID: %s", str);
193b077aed3SPierre Pronchery OPENSSL_free(str);
194b077aed3SPierre Pronchery return 1;
195b077aed3SPierre Pronchery }
196b077aed3SPierre Pronchery
197b077aed3SPierre Pronchery if (str != NULL)
198b077aed3SPierre Pronchery ossl_cmp_log1(INFO, ctx, " cert Subject Key Identifier = %s", str);
199b077aed3SPierre Pronchery OPENSSL_free(str);
200b077aed3SPierre Pronchery if ((str = OPENSSL_buf2hexstr(skid->data, skid->length)) != NULL)
201b077aed3SPierre Pronchery ossl_cmp_log1(INFO, ctx, " does not match senderKID = %s", str);
202b077aed3SPierre Pronchery OPENSSL_free(str);
203b077aed3SPierre Pronchery return 0;
204b077aed3SPierre Pronchery }
205b077aed3SPierre Pronchery
already_checked(const X509 * cert,const STACK_OF (X509)* already_checked)206b077aed3SPierre Pronchery static int already_checked(const X509 *cert,
207b077aed3SPierre Pronchery const STACK_OF(X509) *already_checked)
208b077aed3SPierre Pronchery {
209b077aed3SPierre Pronchery int i;
210b077aed3SPierre Pronchery
211b077aed3SPierre Pronchery for (i = sk_X509_num(already_checked /* may be NULL */); i > 0; i--)
212b077aed3SPierre Pronchery if (X509_cmp(sk_X509_value(already_checked, i - 1), cert) == 0)
213b077aed3SPierre Pronchery return 1;
214b077aed3SPierre Pronchery return 0;
215b077aed3SPierre Pronchery }
216b077aed3SPierre Pronchery
217b077aed3SPierre Pronchery /*-
218b077aed3SPierre Pronchery * Check if the given cert is acceptable as sender cert of the given message.
219b077aed3SPierre Pronchery * The subject DN must match, the subject key ID as well if present in the msg,
220b077aed3SPierre Pronchery * and the cert must be current (checked if ctx->trusted is not NULL).
221b077aed3SPierre Pronchery * Note that cert revocation etc. is checked by OSSL_CMP_validate_cert_path().
222b077aed3SPierre Pronchery *
223b077aed3SPierre Pronchery * Returns 0 on error or not acceptable, else 1.
224b077aed3SPierre Pronchery */
cert_acceptable(const OSSL_CMP_CTX * ctx,const char * desc1,const char * desc2,X509 * cert,const STACK_OF (X509)* already_checked1,const STACK_OF (X509)* already_checked2,const OSSL_CMP_MSG * msg)225b077aed3SPierre Pronchery static int cert_acceptable(const OSSL_CMP_CTX *ctx,
226b077aed3SPierre Pronchery const char *desc1, const char *desc2, X509 *cert,
227b077aed3SPierre Pronchery const STACK_OF(X509) *already_checked1,
228b077aed3SPierre Pronchery const STACK_OF(X509) *already_checked2,
229b077aed3SPierre Pronchery const OSSL_CMP_MSG *msg)
230b077aed3SPierre Pronchery {
231b077aed3SPierre Pronchery X509_STORE *ts = ctx->trusted;
232b077aed3SPierre Pronchery int self_issued = X509_check_issued(cert, cert) == X509_V_OK;
233b077aed3SPierre Pronchery char *str;
234b077aed3SPierre Pronchery X509_VERIFY_PARAM *vpm = ts != NULL ? X509_STORE_get0_param(ts) : NULL;
235b077aed3SPierre Pronchery int time_cmp;
236b077aed3SPierre Pronchery
237b077aed3SPierre Pronchery ossl_cmp_log3(INFO, ctx, " considering %s%s %s with..",
238b077aed3SPierre Pronchery self_issued ? "self-issued ": "", desc1, desc2);
239b077aed3SPierre Pronchery if ((str = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0)) != NULL)
240b077aed3SPierre Pronchery ossl_cmp_log1(INFO, ctx, " subject = %s", str);
241b077aed3SPierre Pronchery OPENSSL_free(str);
242b077aed3SPierre Pronchery if (!self_issued) {
243b077aed3SPierre Pronchery str = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
244b077aed3SPierre Pronchery if (str != NULL)
245b077aed3SPierre Pronchery ossl_cmp_log1(INFO, ctx, " issuer = %s", str);
246b077aed3SPierre Pronchery OPENSSL_free(str);
247b077aed3SPierre Pronchery }
248b077aed3SPierre Pronchery
249b077aed3SPierre Pronchery if (already_checked(cert, already_checked1)
250b077aed3SPierre Pronchery || already_checked(cert, already_checked2)) {
251b077aed3SPierre Pronchery ossl_cmp_info(ctx, " cert has already been checked");
252b077aed3SPierre Pronchery return 0;
253b077aed3SPierre Pronchery }
254b077aed3SPierre Pronchery
255b077aed3SPierre Pronchery time_cmp = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert),
256b077aed3SPierre Pronchery X509_get0_notAfter(cert));
257b077aed3SPierre Pronchery if (time_cmp != 0) {
258b077aed3SPierre Pronchery ossl_cmp_warn(ctx, time_cmp > 0 ? "cert has expired"
259b077aed3SPierre Pronchery : "cert is not yet valid");
260b077aed3SPierre Pronchery return 0;
261b077aed3SPierre Pronchery }
262b077aed3SPierre Pronchery
263b077aed3SPierre Pronchery if (!check_name(ctx, 1,
264b077aed3SPierre Pronchery "cert subject", X509_get_subject_name(cert),
265b077aed3SPierre Pronchery "sender field", msg->header->sender->d.directoryName))
266b077aed3SPierre Pronchery return 0;
267b077aed3SPierre Pronchery
268b077aed3SPierre Pronchery if (!check_kid(ctx, X509_get0_subject_key_id(cert), msg->header->senderKID))
269b077aed3SPierre Pronchery return 0;
270b077aed3SPierre Pronchery /* prevent misleading error later in case x509v3_cache_extensions() fails */
271b077aed3SPierre Pronchery if (!ossl_x509v3_cache_extensions(cert)) {
272b077aed3SPierre Pronchery ossl_cmp_warn(ctx, "cert appears to be invalid");
273b077aed3SPierre Pronchery return 0;
274b077aed3SPierre Pronchery }
275b077aed3SPierre Pronchery if (!verify_signature(ctx, msg, cert)) {
276b077aed3SPierre Pronchery ossl_cmp_warn(ctx, "msg signature verification failed");
277b077aed3SPierre Pronchery return 0;
278b077aed3SPierre Pronchery }
279b077aed3SPierre Pronchery /* acceptable also if there is no senderKID in msg header */
280b077aed3SPierre Pronchery ossl_cmp_info(ctx, " cert seems acceptable");
281b077aed3SPierre Pronchery return 1;
282b077aed3SPierre Pronchery }
283b077aed3SPierre Pronchery
check_cert_path(const OSSL_CMP_CTX * ctx,X509_STORE * store,X509 * scrt)284b077aed3SPierre Pronchery static int check_cert_path(const OSSL_CMP_CTX *ctx, X509_STORE *store,
285b077aed3SPierre Pronchery X509 *scrt)
286b077aed3SPierre Pronchery {
287b077aed3SPierre Pronchery if (OSSL_CMP_validate_cert_path(ctx, store, scrt))
288b077aed3SPierre Pronchery return 1;
289b077aed3SPierre Pronchery
290b077aed3SPierre Pronchery ossl_cmp_warn(ctx,
291b077aed3SPierre Pronchery "msg signature validates but cert path validation failed");
292b077aed3SPierre Pronchery return 0;
293b077aed3SPierre Pronchery }
294b077aed3SPierre Pronchery
295b077aed3SPierre Pronchery /*
296b077aed3SPierre Pronchery * Exceptional handling for 3GPP TS 33.310 [3G/LTE Network Domain Security
297b077aed3SPierre Pronchery * (NDS); Authentication Framework (AF)], only to use for IP messages
298b077aed3SPierre Pronchery * and if the ctx option is explicitly set: use self-issued certificates
299b077aed3SPierre Pronchery * from extraCerts as trust anchor to validate sender cert -
300b077aed3SPierre Pronchery * provided it also can validate the newly enrolled certificate
301b077aed3SPierre Pronchery */
check_cert_path_3gpp(const OSSL_CMP_CTX * ctx,const OSSL_CMP_MSG * msg,X509 * scrt)302b077aed3SPierre Pronchery static int check_cert_path_3gpp(const OSSL_CMP_CTX *ctx,
303b077aed3SPierre Pronchery const OSSL_CMP_MSG *msg, X509 *scrt)
304b077aed3SPierre Pronchery {
305b077aed3SPierre Pronchery int valid = 0;
306b077aed3SPierre Pronchery X509_STORE *store;
307b077aed3SPierre Pronchery
308b077aed3SPierre Pronchery if (!ctx->permitTAInExtraCertsForIR)
309b077aed3SPierre Pronchery return 0;
310b077aed3SPierre Pronchery
311b077aed3SPierre Pronchery if ((store = X509_STORE_new()) == NULL
312b077aed3SPierre Pronchery || !ossl_cmp_X509_STORE_add1_certs(store, msg->extraCerts,
313b077aed3SPierre Pronchery 1 /* self-issued only */))
314b077aed3SPierre Pronchery goto err;
315b077aed3SPierre Pronchery
316b077aed3SPierre Pronchery /* store does not include CRLs */
317b077aed3SPierre Pronchery valid = OSSL_CMP_validate_cert_path(ctx, store, scrt);
318b077aed3SPierre Pronchery if (!valid) {
319b077aed3SPierre Pronchery ossl_cmp_warn(ctx,
320b077aed3SPierre Pronchery "also exceptional 3GPP mode cert path validation failed");
321b077aed3SPierre Pronchery } else {
322b077aed3SPierre Pronchery /*
323b077aed3SPierre Pronchery * verify that the newly enrolled certificate (which assumed rid ==
324b077aed3SPierre Pronchery * OSSL_CMP_CERTREQID) can also be validated with the same trusted store
325b077aed3SPierre Pronchery */
326b077aed3SPierre Pronchery OSSL_CMP_CERTRESPONSE *crep =
327b077aed3SPierre Pronchery ossl_cmp_certrepmessage_get0_certresponse(msg->body->value.ip,
328b077aed3SPierre Pronchery OSSL_CMP_CERTREQID);
329b077aed3SPierre Pronchery X509 *newcrt = ossl_cmp_certresponse_get1_cert(ctx, crep);
330b077aed3SPierre Pronchery
331b077aed3SPierre Pronchery /*
332b077aed3SPierre Pronchery * maybe better use get_cert_status() from cmp_client.c, which catches
333b077aed3SPierre Pronchery * errors
334b077aed3SPierre Pronchery */
335b077aed3SPierre Pronchery valid = OSSL_CMP_validate_cert_path(ctx, store, newcrt);
336b077aed3SPierre Pronchery X509_free(newcrt);
337b077aed3SPierre Pronchery }
338b077aed3SPierre Pronchery
339b077aed3SPierre Pronchery err:
340b077aed3SPierre Pronchery X509_STORE_free(store);
341b077aed3SPierre Pronchery return valid;
342b077aed3SPierre Pronchery }
343b077aed3SPierre Pronchery
check_msg_given_cert(const OSSL_CMP_CTX * ctx,X509 * cert,const OSSL_CMP_MSG * msg)344b077aed3SPierre Pronchery static int check_msg_given_cert(const OSSL_CMP_CTX *ctx, X509 *cert,
345b077aed3SPierre Pronchery const OSSL_CMP_MSG *msg)
346b077aed3SPierre Pronchery {
347b077aed3SPierre Pronchery return cert_acceptable(ctx, "previously validated", "sender cert",
348b077aed3SPierre Pronchery cert, NULL, NULL, msg)
349b077aed3SPierre Pronchery && (check_cert_path(ctx, ctx->trusted, cert)
350b077aed3SPierre Pronchery || check_cert_path_3gpp(ctx, msg, cert));
351b077aed3SPierre Pronchery }
352b077aed3SPierre Pronchery
353b077aed3SPierre Pronchery /*-
354b077aed3SPierre Pronchery * Try all certs in given list for verifying msg, normally or in 3GPP mode.
355b077aed3SPierre Pronchery * If already_checked1 == NULL then certs are assumed to be the msg->extraCerts.
356b077aed3SPierre Pronchery * On success cache the found cert using ossl_cmp_ctx_set0_validatedSrvCert().
357b077aed3SPierre Pronchery */
check_msg_with_certs(OSSL_CMP_CTX * ctx,const STACK_OF (X509)* certs,const char * desc,const STACK_OF (X509)* already_checked1,const STACK_OF (X509)* already_checked2,const OSSL_CMP_MSG * msg,int mode_3gpp)358b077aed3SPierre Pronchery static int check_msg_with_certs(OSSL_CMP_CTX *ctx, const STACK_OF(X509) *certs,
359b077aed3SPierre Pronchery const char *desc,
360b077aed3SPierre Pronchery const STACK_OF(X509) *already_checked1,
361b077aed3SPierre Pronchery const STACK_OF(X509) *already_checked2,
362b077aed3SPierre Pronchery const OSSL_CMP_MSG *msg, int mode_3gpp)
363b077aed3SPierre Pronchery {
364b077aed3SPierre Pronchery int in_extraCerts = already_checked1 == NULL;
365b077aed3SPierre Pronchery int n_acceptable_certs = 0;
366b077aed3SPierre Pronchery int i;
367b077aed3SPierre Pronchery
368b077aed3SPierre Pronchery if (sk_X509_num(certs) <= 0) {
369b077aed3SPierre Pronchery ossl_cmp_log1(WARN, ctx, "no %s", desc);
370b077aed3SPierre Pronchery return 0;
371b077aed3SPierre Pronchery }
372b077aed3SPierre Pronchery
373b077aed3SPierre Pronchery for (i = 0; i < sk_X509_num(certs); i++) { /* certs may be NULL */
374b077aed3SPierre Pronchery X509 *cert = sk_X509_value(certs, i);
375b077aed3SPierre Pronchery
376b077aed3SPierre Pronchery if (!ossl_assert(cert != NULL))
377b077aed3SPierre Pronchery return 0;
378b077aed3SPierre Pronchery if (!cert_acceptable(ctx, "cert from", desc, cert,
379b077aed3SPierre Pronchery already_checked1, already_checked2, msg))
380b077aed3SPierre Pronchery continue;
381b077aed3SPierre Pronchery n_acceptable_certs++;
382b077aed3SPierre Pronchery if (mode_3gpp ? check_cert_path_3gpp(ctx, msg, cert)
383b077aed3SPierre Pronchery : check_cert_path(ctx, ctx->trusted, cert)) {
384b077aed3SPierre Pronchery /* store successful sender cert for further msgs in transaction */
385b077aed3SPierre Pronchery if (!X509_up_ref(cert))
386b077aed3SPierre Pronchery return 0;
387b077aed3SPierre Pronchery if (!ossl_cmp_ctx_set0_validatedSrvCert(ctx, cert)) {
388b077aed3SPierre Pronchery X509_free(cert);
389b077aed3SPierre Pronchery return 0;
390b077aed3SPierre Pronchery }
391b077aed3SPierre Pronchery return 1;
392b077aed3SPierre Pronchery }
393b077aed3SPierre Pronchery }
394b077aed3SPierre Pronchery if (in_extraCerts && n_acceptable_certs == 0)
395b077aed3SPierre Pronchery ossl_cmp_warn(ctx, "no acceptable cert in extraCerts");
396b077aed3SPierre Pronchery return 0;
397b077aed3SPierre Pronchery }
398b077aed3SPierre Pronchery
399b077aed3SPierre Pronchery /*-
400b077aed3SPierre Pronchery * Verify msg trying first ctx->untrusted, which should include extraCerts
401b077aed3SPierre Pronchery * at its front, then trying the trusted certs in truststore (if any) of ctx.
402b077aed3SPierre Pronchery * On success cache the found cert using ossl_cmp_ctx_set0_validatedSrvCert().
403b077aed3SPierre Pronchery */
check_msg_all_certs(OSSL_CMP_CTX * ctx,const OSSL_CMP_MSG * msg,int mode_3gpp)404b077aed3SPierre Pronchery static int check_msg_all_certs(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
405b077aed3SPierre Pronchery int mode_3gpp)
406b077aed3SPierre Pronchery {
407b077aed3SPierre Pronchery int ret = 0;
408b077aed3SPierre Pronchery
409b077aed3SPierre Pronchery if (mode_3gpp
410b077aed3SPierre Pronchery && ((!ctx->permitTAInExtraCertsForIR
411b077aed3SPierre Pronchery || OSSL_CMP_MSG_get_bodytype(msg) != OSSL_CMP_PKIBODY_IP)))
412b077aed3SPierre Pronchery return 0;
413b077aed3SPierre Pronchery
414b077aed3SPierre Pronchery ossl_cmp_info(ctx,
415b077aed3SPierre Pronchery mode_3gpp ? "normal mode failed; trying now 3GPP mode trusting extraCerts"
416b077aed3SPierre Pronchery : "trying first normal mode using trust store");
417b077aed3SPierre Pronchery if (check_msg_with_certs(ctx, msg->extraCerts, "extraCerts",
418b077aed3SPierre Pronchery NULL, NULL, msg, mode_3gpp))
419b077aed3SPierre Pronchery return 1;
420b077aed3SPierre Pronchery if (check_msg_with_certs(ctx, ctx->untrusted, "untrusted certs",
421b077aed3SPierre Pronchery msg->extraCerts, NULL, msg, mode_3gpp))
422b077aed3SPierre Pronchery return 1;
423b077aed3SPierre Pronchery
424b077aed3SPierre Pronchery if (ctx->trusted == NULL) {
425b077aed3SPierre Pronchery ossl_cmp_warn(ctx, mode_3gpp ? "no self-issued extraCerts"
426b077aed3SPierre Pronchery : "no trusted store");
427b077aed3SPierre Pronchery } else {
428b077aed3SPierre Pronchery STACK_OF(X509) *trusted = X509_STORE_get1_all_certs(ctx->trusted);
429b077aed3SPierre Pronchery ret = check_msg_with_certs(ctx, trusted,
430b077aed3SPierre Pronchery mode_3gpp ? "self-issued extraCerts"
431b077aed3SPierre Pronchery : "certs in trusted store",
432b077aed3SPierre Pronchery msg->extraCerts, ctx->untrusted,
433b077aed3SPierre Pronchery msg, mode_3gpp);
434b077aed3SPierre Pronchery sk_X509_pop_free(trusted, X509_free);
435b077aed3SPierre Pronchery }
436b077aed3SPierre Pronchery return ret;
437b077aed3SPierre Pronchery }
438b077aed3SPierre Pronchery
no_log_cb(const char * func,const char * file,int line,OSSL_CMP_severity level,const char * msg)439b077aed3SPierre Pronchery static int no_log_cb(const char *func, const char *file, int line,
440b077aed3SPierre Pronchery OSSL_CMP_severity level, const char *msg)
441b077aed3SPierre Pronchery {
442b077aed3SPierre Pronchery return 1;
443b077aed3SPierre Pronchery }
444b077aed3SPierre Pronchery
445b077aed3SPierre Pronchery /*-
446b077aed3SPierre Pronchery * Verify message signature with any acceptable and valid candidate cert.
447b077aed3SPierre Pronchery * On success cache the found cert using ossl_cmp_ctx_set0_validatedSrvCert().
448b077aed3SPierre Pronchery */
check_msg_find_cert(OSSL_CMP_CTX * ctx,const OSSL_CMP_MSG * msg)449b077aed3SPierre Pronchery static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
450b077aed3SPierre Pronchery {
451b077aed3SPierre Pronchery X509 *scrt = ctx->validatedSrvCert; /* previous successful sender cert */
452b077aed3SPierre Pronchery GENERAL_NAME *sender = msg->header->sender;
453b077aed3SPierre Pronchery char *sname = NULL;
454b077aed3SPierre Pronchery char *skid_str = NULL;
455b077aed3SPierre Pronchery const ASN1_OCTET_STRING *skid = msg->header->senderKID;
456b077aed3SPierre Pronchery OSSL_CMP_log_cb_t backup_log_cb = ctx->log_cb;
457b077aed3SPierre Pronchery int res = 0;
458b077aed3SPierre Pronchery
459b077aed3SPierre Pronchery if (sender == NULL || msg->body == NULL)
460b077aed3SPierre Pronchery return 0; /* other NULL cases already have been checked */
461b077aed3SPierre Pronchery if (sender->type != GEN_DIRNAME) {
462b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED);
463b077aed3SPierre Pronchery return 0;
464b077aed3SPierre Pronchery }
465b077aed3SPierre Pronchery
466b077aed3SPierre Pronchery /* dump any hitherto errors to avoid confusion when printing further ones */
467b077aed3SPierre Pronchery OSSL_CMP_CTX_print_errors(ctx);
468b077aed3SPierre Pronchery
469b077aed3SPierre Pronchery /* enable clearing irrelevant errors in attempts to validate sender certs */
470b077aed3SPierre Pronchery (void)ERR_set_mark();
471b077aed3SPierre Pronchery ctx->log_cb = no_log_cb; /* temporarily disable logging */
472b077aed3SPierre Pronchery
473b077aed3SPierre Pronchery /*
474b077aed3SPierre Pronchery * try first cached scrt, used successfully earlier in same transaction,
475b077aed3SPierre Pronchery * for validating this and any further msgs where extraCerts may be left out
476b077aed3SPierre Pronchery */
477b077aed3SPierre Pronchery if (scrt != NULL) {
478b077aed3SPierre Pronchery if (check_msg_given_cert(ctx, scrt, msg)) {
479b077aed3SPierre Pronchery ctx->log_cb = backup_log_cb;
480b077aed3SPierre Pronchery (void)ERR_pop_to_mark();
481b077aed3SPierre Pronchery return 1;
482b077aed3SPierre Pronchery }
483b077aed3SPierre Pronchery /* cached sender cert has shown to be no more successfully usable */
484b077aed3SPierre Pronchery (void)ossl_cmp_ctx_set0_validatedSrvCert(ctx, NULL);
485b077aed3SPierre Pronchery /* re-do the above check (just) for adding diagnostic information */
486b077aed3SPierre Pronchery ossl_cmp_info(ctx,
487b077aed3SPierre Pronchery "trying to verify msg signature with previously validated cert");
488b077aed3SPierre Pronchery (void)check_msg_given_cert(ctx, scrt, msg);
489b077aed3SPierre Pronchery }
490b077aed3SPierre Pronchery
491b077aed3SPierre Pronchery res = check_msg_all_certs(ctx, msg, 0 /* using ctx->trusted */)
492b077aed3SPierre Pronchery || check_msg_all_certs(ctx, msg, 1 /* 3gpp */);
493b077aed3SPierre Pronchery ctx->log_cb = backup_log_cb;
494b077aed3SPierre Pronchery if (res) {
495b077aed3SPierre Pronchery /* discard any diagnostic information on trying to use certs */
496b077aed3SPierre Pronchery (void)ERR_pop_to_mark();
497b077aed3SPierre Pronchery goto end;
498b077aed3SPierre Pronchery }
499b077aed3SPierre Pronchery /* failed finding a sender cert that verifies the message signature */
500b077aed3SPierre Pronchery (void)ERR_clear_last_mark();
501b077aed3SPierre Pronchery
502b077aed3SPierre Pronchery sname = X509_NAME_oneline(sender->d.directoryName, NULL, 0);
503b077aed3SPierre Pronchery skid_str = skid == NULL ? NULL
504b077aed3SPierre Pronchery : OPENSSL_buf2hexstr(skid->data, skid->length);
505b077aed3SPierre Pronchery if (ctx->log_cb != NULL) {
506b077aed3SPierre Pronchery ossl_cmp_info(ctx, "trying to verify msg signature with a valid cert that..");
507b077aed3SPierre Pronchery if (sname != NULL)
508b077aed3SPierre Pronchery ossl_cmp_log1(INFO, ctx, "matches msg sender = %s", sname);
509b077aed3SPierre Pronchery if (skid_str != NULL)
510b077aed3SPierre Pronchery ossl_cmp_log1(INFO, ctx, "matches msg senderKID = %s", skid_str);
511b077aed3SPierre Pronchery else
512b077aed3SPierre Pronchery ossl_cmp_info(ctx, "while msg header does not contain senderKID");
513b077aed3SPierre Pronchery /* re-do the above checks (just) for adding diagnostic information */
514b077aed3SPierre Pronchery (void)check_msg_all_certs(ctx, msg, 0 /* using ctx->trusted */);
515b077aed3SPierre Pronchery (void)check_msg_all_certs(ctx, msg, 1 /* 3gpp */);
516b077aed3SPierre Pronchery }
517b077aed3SPierre Pronchery
518b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_NO_SUITABLE_SENDER_CERT);
519b077aed3SPierre Pronchery if (sname != NULL) {
520b077aed3SPierre Pronchery ERR_add_error_txt(NULL, "for msg sender name = ");
521b077aed3SPierre Pronchery ERR_add_error_txt(NULL, sname);
522b077aed3SPierre Pronchery }
523b077aed3SPierre Pronchery if (skid_str != NULL) {
524b077aed3SPierre Pronchery ERR_add_error_txt(" and ", "for msg senderKID = ");
525b077aed3SPierre Pronchery ERR_add_error_txt(NULL, skid_str);
526b077aed3SPierre Pronchery }
527b077aed3SPierre Pronchery
528b077aed3SPierre Pronchery end:
529b077aed3SPierre Pronchery OPENSSL_free(sname);
530b077aed3SPierre Pronchery OPENSSL_free(skid_str);
531b077aed3SPierre Pronchery return res;
532b077aed3SPierre Pronchery }
533b077aed3SPierre Pronchery
534b077aed3SPierre Pronchery /*-
535b077aed3SPierre Pronchery * Validate the protection of the given PKIMessage using either password-
536b077aed3SPierre Pronchery * based mac (PBM) or a signature algorithm. In the case of signature algorithm,
537b077aed3SPierre Pronchery * the sender certificate can have been pinned by providing it in ctx->srvCert,
538b077aed3SPierre Pronchery * else it is searched in msg->extraCerts, ctx->untrusted, in ctx->trusted
539b077aed3SPierre Pronchery * (in this order) and is path is validated against ctx->trusted.
540b077aed3SPierre Pronchery * On success cache the found cert using ossl_cmp_ctx_set0_validatedSrvCert().
541b077aed3SPierre Pronchery *
542b077aed3SPierre Pronchery * If ctx->permitTAInExtraCertsForIR is true and when validating a CMP IP msg,
543b077aed3SPierre Pronchery * the trust anchor for validating the IP msg may be taken from msg->extraCerts
544b077aed3SPierre Pronchery * if a self-issued certificate is found there that can be used to
545b077aed3SPierre Pronchery * validate the enrolled certificate returned in the IP.
546b077aed3SPierre Pronchery * This is according to the need given in 3GPP TS 33.310.
547b077aed3SPierre Pronchery *
548b077aed3SPierre Pronchery * Returns 1 on success, 0 on error or validation failed.
549b077aed3SPierre Pronchery */
OSSL_CMP_validate_msg(OSSL_CMP_CTX * ctx,const OSSL_CMP_MSG * msg)550b077aed3SPierre Pronchery int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
551b077aed3SPierre Pronchery {
552b077aed3SPierre Pronchery X509 *scrt;
553b077aed3SPierre Pronchery
554b077aed3SPierre Pronchery ossl_cmp_debug(ctx, "validating CMP message");
555b077aed3SPierre Pronchery if (ctx == NULL || msg == NULL
556b077aed3SPierre Pronchery || msg->header == NULL || msg->body == NULL) {
557b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
558b077aed3SPierre Pronchery return 0;
559b077aed3SPierre Pronchery }
560b077aed3SPierre Pronchery
561b077aed3SPierre Pronchery if (msg->header->protectionAlg == NULL /* unprotected message */
562b077aed3SPierre Pronchery || msg->protection == NULL || msg->protection->data == NULL) {
563b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PROTECTION);
564b077aed3SPierre Pronchery return 0;
565b077aed3SPierre Pronchery }
566b077aed3SPierre Pronchery
567b077aed3SPierre Pronchery switch (ossl_cmp_hdr_get_protection_nid(msg->header)) {
568b077aed3SPierre Pronchery /* 5.1.3.1. Shared Secret Information */
569b077aed3SPierre Pronchery case NID_id_PasswordBasedMAC:
570b077aed3SPierre Pronchery if (ctx->secretValue == NULL) {
571b077aed3SPierre Pronchery ossl_cmp_info(ctx, "no secret available for verifying PBM-based CMP message protection");
572b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_SECRET);
573b077aed3SPierre Pronchery return 0;
574b077aed3SPierre Pronchery }
575b077aed3SPierre Pronchery if (verify_PBMAC(ctx, msg)) {
576b077aed3SPierre Pronchery /*
577b077aed3SPierre Pronchery * RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is
578b077aed3SPierre Pronchery * "shared secret information", then any certificate transported in
579b077aed3SPierre Pronchery * the caPubs field may be directly trusted as a root CA
580b077aed3SPierre Pronchery * certificate by the initiator.'
581b077aed3SPierre Pronchery */
582b077aed3SPierre Pronchery switch (OSSL_CMP_MSG_get_bodytype(msg)) {
583b077aed3SPierre Pronchery case -1:
584b077aed3SPierre Pronchery return 0;
585b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_IP:
586b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_CP:
587b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_KUP:
588b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_CCP:
589b077aed3SPierre Pronchery if (ctx->trusted != NULL) {
590b077aed3SPierre Pronchery STACK_OF(X509) *certs = msg->body->value.ip->caPubs;
591b077aed3SPierre Pronchery /* value.ip is same for cp, kup, and ccp */
592b077aed3SPierre Pronchery
593b077aed3SPierre Pronchery if (!ossl_cmp_X509_STORE_add1_certs(ctx->trusted, certs, 0))
594b077aed3SPierre Pronchery /* adds both self-issued and not self-issued certs */
595b077aed3SPierre Pronchery return 0;
596b077aed3SPierre Pronchery }
597b077aed3SPierre Pronchery break;
598b077aed3SPierre Pronchery default:
599b077aed3SPierre Pronchery break;
600b077aed3SPierre Pronchery }
601b077aed3SPierre Pronchery ossl_cmp_debug(ctx,
602b077aed3SPierre Pronchery "sucessfully validated PBM-based CMP message protection");
603b077aed3SPierre Pronchery return 1;
604b077aed3SPierre Pronchery }
605b077aed3SPierre Pronchery ossl_cmp_warn(ctx, "verifying PBM-based CMP message protection failed");
606b077aed3SPierre Pronchery break;
607b077aed3SPierre Pronchery
608b077aed3SPierre Pronchery /*
609b077aed3SPierre Pronchery * 5.1.3.2 DH Key Pairs
610b077aed3SPierre Pronchery * Not yet supported
611b077aed3SPierre Pronchery */
612b077aed3SPierre Pronchery case NID_id_DHBasedMac:
613b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC);
614b077aed3SPierre Pronchery break;
615b077aed3SPierre Pronchery
616b077aed3SPierre Pronchery /*
617b077aed3SPierre Pronchery * 5.1.3.3. Signature
618b077aed3SPierre Pronchery */
619b077aed3SPierre Pronchery default:
620b077aed3SPierre Pronchery scrt = ctx->srvCert;
621b077aed3SPierre Pronchery if (scrt == NULL) {
622*a7148ab3SEnji Cooper if (ctx->trusted == NULL && ctx->secretValue != NULL) {
623b077aed3SPierre Pronchery ossl_cmp_info(ctx, "no trust store nor pinned server cert available for verifying signature-based CMP message protection");
624b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_TRUST_ANCHOR);
625b077aed3SPierre Pronchery return 0;
626b077aed3SPierre Pronchery }
627b077aed3SPierre Pronchery if (check_msg_find_cert(ctx, msg))
628b077aed3SPierre Pronchery return 1;
629b077aed3SPierre Pronchery } else { /* use pinned sender cert */
630b077aed3SPierre Pronchery /* use ctx->srvCert for signature check even if not acceptable */
631b077aed3SPierre Pronchery if (verify_signature(ctx, msg, scrt)) {
632b077aed3SPierre Pronchery ossl_cmp_debug(ctx,
633b077aed3SPierre Pronchery "sucessfully validated signature-based CMP message protection");
634b077aed3SPierre Pronchery
635b077aed3SPierre Pronchery return 1;
636b077aed3SPierre Pronchery }
637b077aed3SPierre Pronchery ossl_cmp_warn(ctx, "CMP message signature verification failed");
638b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG);
639b077aed3SPierre Pronchery }
640b077aed3SPierre Pronchery break;
641b077aed3SPierre Pronchery }
642b077aed3SPierre Pronchery return 0;
643b077aed3SPierre Pronchery }
644b077aed3SPierre Pronchery
645b077aed3SPierre Pronchery /*-
646b077aed3SPierre Pronchery * Check received message (i.e., response by server or request from client)
647b077aed3SPierre Pronchery * Any msg->extraCerts are prepended to ctx->untrusted.
648b077aed3SPierre Pronchery *
649b077aed3SPierre Pronchery * Ensures that:
650b077aed3SPierre Pronchery * its sender is of appropriate type (curently only X509_NAME) and
651b077aed3SPierre Pronchery * matches any expected sender or srvCert subject given in the ctx
652b077aed3SPierre Pronchery * it has a valid body type
653b077aed3SPierre Pronchery * its protection is valid (or invalid/absent, but only if a callback function
654b077aed3SPierre Pronchery * is present and yields a positive result using also the supplied argument)
655b077aed3SPierre Pronchery * its transaction ID matches the previous transaction ID stored in ctx (if any)
656b077aed3SPierre Pronchery * its recipNonce matches the previous senderNonce stored in the ctx (if any)
657b077aed3SPierre Pronchery *
658b077aed3SPierre Pronchery * If everything is fine:
659b077aed3SPierre Pronchery * learns the senderNonce from the received message,
660b077aed3SPierre Pronchery * learns the transaction ID if it is not yet in ctx,
661b077aed3SPierre Pronchery * and makes any certs in caPubs directly trusted.
662b077aed3SPierre Pronchery *
663b077aed3SPierre Pronchery * Returns 1 on success, 0 on error.
664b077aed3SPierre Pronchery */
ossl_cmp_msg_check_update(OSSL_CMP_CTX * ctx,const OSSL_CMP_MSG * msg,ossl_cmp_allow_unprotected_cb_t cb,int cb_arg)665b077aed3SPierre Pronchery int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
666b077aed3SPierre Pronchery ossl_cmp_allow_unprotected_cb_t cb, int cb_arg)
667b077aed3SPierre Pronchery {
668b077aed3SPierre Pronchery OSSL_CMP_PKIHEADER *hdr;
669b077aed3SPierre Pronchery const X509_NAME *expected_sender;
670b077aed3SPierre Pronchery
671b077aed3SPierre Pronchery if (!ossl_assert(ctx != NULL && msg != NULL && msg->header != NULL))
672b077aed3SPierre Pronchery return 0;
673b077aed3SPierre Pronchery hdr = OSSL_CMP_MSG_get0_header(msg);
674b077aed3SPierre Pronchery
675b077aed3SPierre Pronchery /* validate sender name of received msg */
676b077aed3SPierre Pronchery if (hdr->sender->type != GEN_DIRNAME) {
677b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED);
678b077aed3SPierre Pronchery return 0;
679b077aed3SPierre Pronchery }
680b077aed3SPierre Pronchery /*
681b077aed3SPierre Pronchery * Compare actual sender name of response with expected sender name.
682b077aed3SPierre Pronchery * Mitigates risk to accept misused PBM secret
683b077aed3SPierre Pronchery * or misused certificate of an unauthorized entity of a trusted hierarchy.
684b077aed3SPierre Pronchery */
685b077aed3SPierre Pronchery expected_sender = ctx->expected_sender;
686b077aed3SPierre Pronchery if (expected_sender == NULL && ctx->srvCert != NULL)
687b077aed3SPierre Pronchery expected_sender = X509_get_subject_name(ctx->srvCert);
688b077aed3SPierre Pronchery if (!check_name(ctx, 0, "sender DN field", hdr->sender->d.directoryName,
689b077aed3SPierre Pronchery "expected sender", expected_sender))
690b077aed3SPierre Pronchery return 0;
691b077aed3SPierre Pronchery /* Note: if recipient was NULL-DN it could be learned here if needed */
692b077aed3SPierre Pronchery
693b077aed3SPierre Pronchery if (sk_X509_num(msg->extraCerts) > 10)
694b077aed3SPierre Pronchery ossl_cmp_warn(ctx,
695b077aed3SPierre Pronchery "received CMP message contains more than 10 extraCerts");
696b077aed3SPierre Pronchery /*
697b077aed3SPierre Pronchery * Store any provided extraCerts in ctx for use in OSSL_CMP_validate_msg()
698b077aed3SPierre Pronchery * and for future use, such that they are available to ctx->certConf_cb and
699b077aed3SPierre Pronchery * the peer does not need to send them again in the same transaction.
700b077aed3SPierre Pronchery * Note that it does not help validating the message before storing the
701b077aed3SPierre Pronchery * extraCerts because they do not belong to the protected msg part anyway.
702b077aed3SPierre Pronchery * For efficiency, the extraCerts are prepended so they get used first.
703b077aed3SPierre Pronchery */
704b077aed3SPierre Pronchery if (!X509_add_certs(ctx->untrusted, msg->extraCerts,
705b077aed3SPierre Pronchery /* this allows self-signed certs */
706b077aed3SPierre Pronchery X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP
707b077aed3SPierre Pronchery | X509_ADD_FLAG_PREPEND))
708b077aed3SPierre Pronchery return 0;
709b077aed3SPierre Pronchery
710b077aed3SPierre Pronchery /* validate message protection */
711b077aed3SPierre Pronchery if (hdr->protectionAlg != NULL) {
712b077aed3SPierre Pronchery /* detect explicitly permitted exceptions for invalid protection */
713b077aed3SPierre Pronchery if (!OSSL_CMP_validate_msg(ctx, msg)
714b077aed3SPierre Pronchery && (cb == NULL || (*cb)(ctx, msg, 1, cb_arg) <= 0)) {
715b077aed3SPierre Pronchery #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
716b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION);
717b077aed3SPierre Pronchery return 0;
718b077aed3SPierre Pronchery #endif
719b077aed3SPierre Pronchery }
720b077aed3SPierre Pronchery } else {
721b077aed3SPierre Pronchery /* detect explicitly permitted exceptions for missing protection */
722b077aed3SPierre Pronchery if (cb == NULL || (*cb)(ctx, msg, 0, cb_arg) <= 0) {
723b077aed3SPierre Pronchery #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
724b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PROTECTION);
725b077aed3SPierre Pronchery return 0;
726b077aed3SPierre Pronchery #endif
727b077aed3SPierre Pronchery }
728b077aed3SPierre Pronchery }
729b077aed3SPierre Pronchery
730b077aed3SPierre Pronchery /* check CMP version number in header */
731b077aed3SPierre Pronchery if (ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO) {
732b077aed3SPierre Pronchery #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
733b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO);
734b077aed3SPierre Pronchery return 0;
735b077aed3SPierre Pronchery #endif
736b077aed3SPierre Pronchery }
737b077aed3SPierre Pronchery
738b077aed3SPierre Pronchery if (OSSL_CMP_MSG_get_bodytype(msg) < 0) {
739b077aed3SPierre Pronchery #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
740b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_PKIBODY_ERROR);
741b077aed3SPierre Pronchery return 0;
742b077aed3SPierre Pronchery #endif
743b077aed3SPierre Pronchery }
744b077aed3SPierre Pronchery
745b077aed3SPierre Pronchery /* compare received transactionID with the expected one in previous msg */
746b077aed3SPierre Pronchery if (ctx->transactionID != NULL
747b077aed3SPierre Pronchery && (hdr->transactionID == NULL
748b077aed3SPierre Pronchery || ASN1_OCTET_STRING_cmp(ctx->transactionID,
749b077aed3SPierre Pronchery hdr->transactionID) != 0)) {
750b077aed3SPierre Pronchery #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
751b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_TRANSACTIONID_UNMATCHED);
752b077aed3SPierre Pronchery return 0;
753b077aed3SPierre Pronchery #endif
754b077aed3SPierre Pronchery }
755b077aed3SPierre Pronchery
756b077aed3SPierre Pronchery /* compare received nonce with the one we sent */
757b077aed3SPierre Pronchery if (ctx->senderNonce != NULL
758b077aed3SPierre Pronchery && (msg->header->recipNonce == NULL
759b077aed3SPierre Pronchery || ASN1_OCTET_STRING_cmp(ctx->senderNonce,
760b077aed3SPierre Pronchery hdr->recipNonce) != 0)) {
761b077aed3SPierre Pronchery #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
762b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_RECIPNONCE_UNMATCHED);
763b077aed3SPierre Pronchery return 0;
764b077aed3SPierre Pronchery #endif
765b077aed3SPierre Pronchery }
766b077aed3SPierre Pronchery
767b077aed3SPierre Pronchery /* if not yet present, learn transactionID */
768b077aed3SPierre Pronchery if (ctx->transactionID == NULL
769b077aed3SPierre Pronchery && !OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID))
770b077aed3SPierre Pronchery return 0;
771b077aed3SPierre Pronchery
772b077aed3SPierre Pronchery /*
773b077aed3SPierre Pronchery * RFC 4210 section 5.1.1 states: the recipNonce is copied from
774b077aed3SPierre Pronchery * the senderNonce of the previous message in the transaction.
775b077aed3SPierre Pronchery * --> Store for setting in next message
776b077aed3SPierre Pronchery */
777b077aed3SPierre Pronchery if (!ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce))
778b077aed3SPierre Pronchery return 0;
779b077aed3SPierre Pronchery
780b077aed3SPierre Pronchery /*
781b077aed3SPierre Pronchery * Store any provided extraCerts in ctx for future use,
782b077aed3SPierre Pronchery * such that they are available to ctx->certConf_cb and
783b077aed3SPierre Pronchery * the peer does not need to send them again in the same transaction.
784b077aed3SPierre Pronchery * For efficiency, the extraCerts are prepended so they get used first.
785b077aed3SPierre Pronchery */
786b077aed3SPierre Pronchery if (!X509_add_certs(ctx->untrusted, msg->extraCerts,
787b077aed3SPierre Pronchery /* this allows self-signed certs */
788b077aed3SPierre Pronchery X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP
789b077aed3SPierre Pronchery | X509_ADD_FLAG_PREPEND))
790b077aed3SPierre Pronchery return 0;
791b077aed3SPierre Pronchery
792b077aed3SPierre Pronchery if (ossl_cmp_hdr_get_protection_nid(hdr) == NID_id_PasswordBasedMAC) {
793b077aed3SPierre Pronchery /*
794b077aed3SPierre Pronchery * RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is
795b077aed3SPierre Pronchery * "shared secret information", then any certificate transported in
796b077aed3SPierre Pronchery * the caPubs field may be directly trusted as a root CA
797b077aed3SPierre Pronchery * certificate by the initiator.'
798b077aed3SPierre Pronchery */
799b077aed3SPierre Pronchery switch (OSSL_CMP_MSG_get_bodytype(msg)) {
800b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_IP:
801b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_CP:
802b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_KUP:
803b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_CCP:
804b077aed3SPierre Pronchery if (ctx->trusted != NULL) {
805b077aed3SPierre Pronchery STACK_OF(X509) *certs = msg->body->value.ip->caPubs;
806b077aed3SPierre Pronchery /* value.ip is same for cp, kup, and ccp */
807b077aed3SPierre Pronchery
808b077aed3SPierre Pronchery if (!ossl_cmp_X509_STORE_add1_certs(ctx->trusted, certs, 0))
809b077aed3SPierre Pronchery /* adds both self-issued and not self-issued certs */
810b077aed3SPierre Pronchery return 0;
811b077aed3SPierre Pronchery }
812b077aed3SPierre Pronchery break;
813b077aed3SPierre Pronchery default:
814b077aed3SPierre Pronchery break;
815b077aed3SPierre Pronchery }
816b077aed3SPierre Pronchery }
817b077aed3SPierre Pronchery return 1;
818b077aed3SPierre Pronchery }
819b077aed3SPierre Pronchery
ossl_cmp_verify_popo(const OSSL_CMP_CTX * ctx,const OSSL_CMP_MSG * msg,int acceptRAVerified)820b077aed3SPierre Pronchery int ossl_cmp_verify_popo(const OSSL_CMP_CTX *ctx,
821b077aed3SPierre Pronchery const OSSL_CMP_MSG *msg, int acceptRAVerified)
822b077aed3SPierre Pronchery {
823b077aed3SPierre Pronchery if (!ossl_assert(msg != NULL && msg->body != NULL))
824b077aed3SPierre Pronchery return 0;
825b077aed3SPierre Pronchery switch (msg->body->type) {
826b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_P10CR:
827b077aed3SPierre Pronchery {
828b077aed3SPierre Pronchery X509_REQ *req = msg->body->value.p10cr;
829b077aed3SPierre Pronchery
830b077aed3SPierre Pronchery if (X509_REQ_verify_ex(req, X509_REQ_get0_pubkey(req), ctx->libctx,
831b077aed3SPierre Pronchery ctx->propq) <= 0) {
832b077aed3SPierre Pronchery #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
833b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED);
834b077aed3SPierre Pronchery return 0;
835b077aed3SPierre Pronchery #endif
836b077aed3SPierre Pronchery }
837b077aed3SPierre Pronchery }
838b077aed3SPierre Pronchery break;
839b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_IR:
840b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_CR:
841b077aed3SPierre Pronchery case OSSL_CMP_PKIBODY_KUR:
842b077aed3SPierre Pronchery if (!OSSL_CRMF_MSGS_verify_popo(msg->body->value.ir, OSSL_CMP_CERTREQID,
843b077aed3SPierre Pronchery acceptRAVerified,
844b077aed3SPierre Pronchery ctx->libctx, ctx->propq)) {
845b077aed3SPierre Pronchery #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
846b077aed3SPierre Pronchery return 0;
847b077aed3SPierre Pronchery #endif
848b077aed3SPierre Pronchery }
849b077aed3SPierre Pronchery break;
850b077aed3SPierre Pronchery default:
851b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CMP, CMP_R_PKIBODY_ERROR);
852b077aed3SPierre Pronchery return 0;
853b077aed3SPierre Pronchery }
854b077aed3SPierre Pronchery return 1;
855b077aed3SPierre Pronchery }
856