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