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