1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * Copyright Nokia 2007-2019 4e1051a39Sopenharmony_ci * Copyright Siemens AG 2015-2019 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 PKIStatusInfo handling and PKIMessage decomposition */ 13e1051a39Sopenharmony_ci 14e1051a39Sopenharmony_ci#include <string.h> 15e1051a39Sopenharmony_ci 16e1051a39Sopenharmony_ci#include "cmp_local.h" 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_ci/* explicit #includes not strictly needed since implied by the above: */ 19e1051a39Sopenharmony_ci#include <time.h> 20e1051a39Sopenharmony_ci#include <openssl/cmp.h> 21e1051a39Sopenharmony_ci#include <openssl/crmf.h> 22e1051a39Sopenharmony_ci#include <openssl/err.h> /* needed in case config no-deprecated */ 23e1051a39Sopenharmony_ci#include <openssl/engine.h> 24e1051a39Sopenharmony_ci#include <openssl/evp.h> 25e1051a39Sopenharmony_ci#include <openssl/objects.h> 26e1051a39Sopenharmony_ci#include <openssl/x509.h> 27e1051a39Sopenharmony_ci#include <openssl/asn1err.h> /* for ASN1_R_TOO_SMALL and ASN1_R_TOO_LARGE */ 28e1051a39Sopenharmony_ci 29e1051a39Sopenharmony_ci/* CMP functions related to PKIStatus */ 30e1051a39Sopenharmony_ci 31e1051a39Sopenharmony_ciint ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si) 32e1051a39Sopenharmony_ci{ 33e1051a39Sopenharmony_ci if (!ossl_assert(si != NULL && si->status != NULL)) 34e1051a39Sopenharmony_ci return -1; 35e1051a39Sopenharmony_ci return ossl_cmp_asn1_get_int(si->status); 36e1051a39Sopenharmony_ci} 37e1051a39Sopenharmony_ci 38e1051a39Sopenharmony_ciconst char *ossl_cmp_PKIStatus_to_string(int status) 39e1051a39Sopenharmony_ci{ 40e1051a39Sopenharmony_ci switch (status) { 41e1051a39Sopenharmony_ci case OSSL_CMP_PKISTATUS_accepted: 42e1051a39Sopenharmony_ci return "PKIStatus: accepted"; 43e1051a39Sopenharmony_ci case OSSL_CMP_PKISTATUS_grantedWithMods: 44e1051a39Sopenharmony_ci return "PKIStatus: granted with modifications"; 45e1051a39Sopenharmony_ci case OSSL_CMP_PKISTATUS_rejection: 46e1051a39Sopenharmony_ci return "PKIStatus: rejection"; 47e1051a39Sopenharmony_ci case OSSL_CMP_PKISTATUS_waiting: 48e1051a39Sopenharmony_ci return "PKIStatus: waiting"; 49e1051a39Sopenharmony_ci case OSSL_CMP_PKISTATUS_revocationWarning: 50e1051a39Sopenharmony_ci return "PKIStatus: revocation warning - a revocation of the cert is imminent"; 51e1051a39Sopenharmony_ci case OSSL_CMP_PKISTATUS_revocationNotification: 52e1051a39Sopenharmony_ci return "PKIStatus: revocation notification - a revocation of the cert has occurred"; 53e1051a39Sopenharmony_ci case OSSL_CMP_PKISTATUS_keyUpdateWarning: 54e1051a39Sopenharmony_ci return "PKIStatus: key update warning - update already done for the cert"; 55e1051a39Sopenharmony_ci default: 56e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_CMP, CMP_R_ERROR_PARSING_PKISTATUS, 57e1051a39Sopenharmony_ci "PKIStatus: invalid=%d", status); 58e1051a39Sopenharmony_ci return NULL; 59e1051a39Sopenharmony_ci } 60e1051a39Sopenharmony_ci} 61e1051a39Sopenharmony_ci 62e1051a39Sopenharmony_ciOSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *si) 63e1051a39Sopenharmony_ci{ 64e1051a39Sopenharmony_ci if (!ossl_assert(si != NULL)) 65e1051a39Sopenharmony_ci return NULL; 66e1051a39Sopenharmony_ci return si->statusString; 67e1051a39Sopenharmony_ci} 68e1051a39Sopenharmony_ci 69e1051a39Sopenharmony_ciint ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si) 70e1051a39Sopenharmony_ci{ 71e1051a39Sopenharmony_ci int i; 72e1051a39Sopenharmony_ci int res = 0; 73e1051a39Sopenharmony_ci 74e1051a39Sopenharmony_ci if (!ossl_assert(si != NULL)) 75e1051a39Sopenharmony_ci return -1; 76e1051a39Sopenharmony_ci if (si->failInfo != NULL) 77e1051a39Sopenharmony_ci for (i = 0; i <= OSSL_CMP_PKIFAILUREINFO_MAX; i++) 78e1051a39Sopenharmony_ci if (ASN1_BIT_STRING_get_bit(si->failInfo, i)) 79e1051a39Sopenharmony_ci res |= 1 << i; 80e1051a39Sopenharmony_ci return res; 81e1051a39Sopenharmony_ci} 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci/*- 84e1051a39Sopenharmony_ci * convert PKIFailureInfo number to human-readable string 85e1051a39Sopenharmony_ci * returns pointer to static string, or NULL on error 86e1051a39Sopenharmony_ci */ 87e1051a39Sopenharmony_cistatic const char *CMP_PKIFAILUREINFO_to_string(int number) 88e1051a39Sopenharmony_ci{ 89e1051a39Sopenharmony_ci switch (number) { 90e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badAlg: 91e1051a39Sopenharmony_ci return "badAlg"; 92e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badMessageCheck: 93e1051a39Sopenharmony_ci return "badMessageCheck"; 94e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badRequest: 95e1051a39Sopenharmony_ci return "badRequest"; 96e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badTime: 97e1051a39Sopenharmony_ci return "badTime"; 98e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badCertId: 99e1051a39Sopenharmony_ci return "badCertId"; 100e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badDataFormat: 101e1051a39Sopenharmony_ci return "badDataFormat"; 102e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_wrongAuthority: 103e1051a39Sopenharmony_ci return "wrongAuthority"; 104e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_incorrectData: 105e1051a39Sopenharmony_ci return "incorrectData"; 106e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_missingTimeStamp: 107e1051a39Sopenharmony_ci return "missingTimeStamp"; 108e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badPOP: 109e1051a39Sopenharmony_ci return "badPOP"; 110e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_certRevoked: 111e1051a39Sopenharmony_ci return "certRevoked"; 112e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_certConfirmed: 113e1051a39Sopenharmony_ci return "certConfirmed"; 114e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_wrongIntegrity: 115e1051a39Sopenharmony_ci return "wrongIntegrity"; 116e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badRecipientNonce: 117e1051a39Sopenharmony_ci return "badRecipientNonce"; 118e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_timeNotAvailable: 119e1051a39Sopenharmony_ci return "timeNotAvailable"; 120e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_unacceptedPolicy: 121e1051a39Sopenharmony_ci return "unacceptedPolicy"; 122e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_unacceptedExtension: 123e1051a39Sopenharmony_ci return "unacceptedExtension"; 124e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_addInfoNotAvailable: 125e1051a39Sopenharmony_ci return "addInfoNotAvailable"; 126e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badSenderNonce: 127e1051a39Sopenharmony_ci return "badSenderNonce"; 128e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_badCertTemplate: 129e1051a39Sopenharmony_ci return "badCertTemplate"; 130e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_signerNotTrusted: 131e1051a39Sopenharmony_ci return "signerNotTrusted"; 132e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_transactionIdInUse: 133e1051a39Sopenharmony_ci return "transactionIdInUse"; 134e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_unsupportedVersion: 135e1051a39Sopenharmony_ci return "unsupportedVersion"; 136e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_notAuthorized: 137e1051a39Sopenharmony_ci return "notAuthorized"; 138e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_systemUnavail: 139e1051a39Sopenharmony_ci return "systemUnavail"; 140e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_systemFailure: 141e1051a39Sopenharmony_ci return "systemFailure"; 142e1051a39Sopenharmony_ci case OSSL_CMP_PKIFAILUREINFO_duplicateCertReq: 143e1051a39Sopenharmony_ci return "duplicateCertReq"; 144e1051a39Sopenharmony_ci default: 145e1051a39Sopenharmony_ci return NULL; /* illegal failure number */ 146e1051a39Sopenharmony_ci } 147e1051a39Sopenharmony_ci} 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ciint ossl_cmp_pkisi_check_pkifailureinfo(const OSSL_CMP_PKISI *si, int bit_index) 150e1051a39Sopenharmony_ci{ 151e1051a39Sopenharmony_ci if (!ossl_assert(si != NULL && si->failInfo != NULL)) 152e1051a39Sopenharmony_ci return -1; 153e1051a39Sopenharmony_ci if (bit_index < 0 || bit_index > OSSL_CMP_PKIFAILUREINFO_MAX) { 154e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMP, CMP_R_INVALID_ARGS); 155e1051a39Sopenharmony_ci return -1; 156e1051a39Sopenharmony_ci } 157e1051a39Sopenharmony_ci 158e1051a39Sopenharmony_ci return ASN1_BIT_STRING_get_bit(si->failInfo, bit_index); 159e1051a39Sopenharmony_ci} 160e1051a39Sopenharmony_ci 161e1051a39Sopenharmony_ci/*- 162e1051a39Sopenharmony_ci * place human-readable error string created from PKIStatusInfo in given buffer 163e1051a39Sopenharmony_ci * returns pointer to the same buffer containing the string, or NULL on error 164e1051a39Sopenharmony_ci */ 165e1051a39Sopenharmony_cistatic 166e1051a39Sopenharmony_cichar *snprint_PKIStatusInfo_parts(int status, int fail_info, 167e1051a39Sopenharmony_ci const OSSL_CMP_PKIFREETEXT *status_strings, 168e1051a39Sopenharmony_ci char *buf, size_t bufsize) 169e1051a39Sopenharmony_ci{ 170e1051a39Sopenharmony_ci int failure; 171e1051a39Sopenharmony_ci const char *status_string, *failure_string; 172e1051a39Sopenharmony_ci ASN1_UTF8STRING *text; 173e1051a39Sopenharmony_ci int i; 174e1051a39Sopenharmony_ci int printed_chars; 175e1051a39Sopenharmony_ci int failinfo_found = 0; 176e1051a39Sopenharmony_ci int n_status_strings; 177e1051a39Sopenharmony_ci char *write_ptr = buf; 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_ci if (buf == NULL 180e1051a39Sopenharmony_ci || status < 0 181e1051a39Sopenharmony_ci || (status_string = ossl_cmp_PKIStatus_to_string(status)) == NULL) 182e1051a39Sopenharmony_ci return NULL; 183e1051a39Sopenharmony_ci 184e1051a39Sopenharmony_ci#define ADVANCE_BUFFER \ 185e1051a39Sopenharmony_ci if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \ 186e1051a39Sopenharmony_ci return NULL; \ 187e1051a39Sopenharmony_ci write_ptr += printed_chars; \ 188e1051a39Sopenharmony_ci bufsize -= printed_chars; 189e1051a39Sopenharmony_ci 190e1051a39Sopenharmony_ci printed_chars = BIO_snprintf(write_ptr, bufsize, "%s", status_string); 191e1051a39Sopenharmony_ci ADVANCE_BUFFER; 192e1051a39Sopenharmony_ci 193e1051a39Sopenharmony_ci /* 194e1051a39Sopenharmony_ci * failInfo is optional and may be empty; 195e1051a39Sopenharmony_ci * if present, print failInfo before statusString because it is more concise 196e1051a39Sopenharmony_ci */ 197e1051a39Sopenharmony_ci if (fail_info != -1 && fail_info != 0) { 198e1051a39Sopenharmony_ci printed_chars = BIO_snprintf(write_ptr, bufsize, "; PKIFailureInfo: "); 199e1051a39Sopenharmony_ci ADVANCE_BUFFER; 200e1051a39Sopenharmony_ci for (failure = 0; failure <= OSSL_CMP_PKIFAILUREINFO_MAX; failure++) { 201e1051a39Sopenharmony_ci if ((fail_info & (1 << failure)) != 0) { 202e1051a39Sopenharmony_ci failure_string = CMP_PKIFAILUREINFO_to_string(failure); 203e1051a39Sopenharmony_ci if (failure_string != NULL) { 204e1051a39Sopenharmony_ci printed_chars = BIO_snprintf(write_ptr, bufsize, "%s%s", 205e1051a39Sopenharmony_ci failinfo_found ? ", " : "", 206e1051a39Sopenharmony_ci failure_string); 207e1051a39Sopenharmony_ci ADVANCE_BUFFER; 208e1051a39Sopenharmony_ci failinfo_found = 1; 209e1051a39Sopenharmony_ci } 210e1051a39Sopenharmony_ci } 211e1051a39Sopenharmony_ci } 212e1051a39Sopenharmony_ci } 213e1051a39Sopenharmony_ci if (!failinfo_found && status != OSSL_CMP_PKISTATUS_accepted 214e1051a39Sopenharmony_ci && status != OSSL_CMP_PKISTATUS_grantedWithMods) { 215e1051a39Sopenharmony_ci printed_chars = BIO_snprintf(write_ptr, bufsize, "; <no failure info>"); 216e1051a39Sopenharmony_ci ADVANCE_BUFFER; 217e1051a39Sopenharmony_ci } 218e1051a39Sopenharmony_ci 219e1051a39Sopenharmony_ci /* statusString sequence is optional and may be empty */ 220e1051a39Sopenharmony_ci n_status_strings = sk_ASN1_UTF8STRING_num(status_strings); 221e1051a39Sopenharmony_ci if (n_status_strings > 0) { 222e1051a39Sopenharmony_ci printed_chars = BIO_snprintf(write_ptr, bufsize, "; StatusString%s: ", 223e1051a39Sopenharmony_ci n_status_strings > 1 ? "s" : ""); 224e1051a39Sopenharmony_ci ADVANCE_BUFFER; 225e1051a39Sopenharmony_ci for (i = 0; i < n_status_strings; i++) { 226e1051a39Sopenharmony_ci text = sk_ASN1_UTF8STRING_value(status_strings, i); 227e1051a39Sopenharmony_ci printed_chars = BIO_snprintf(write_ptr, bufsize, "\"%.*s\"%s", 228e1051a39Sopenharmony_ci ASN1_STRING_length(text), 229e1051a39Sopenharmony_ci ASN1_STRING_get0_data(text), 230e1051a39Sopenharmony_ci i < n_status_strings - 1 ? ", " : ""); 231e1051a39Sopenharmony_ci ADVANCE_BUFFER; 232e1051a39Sopenharmony_ci } 233e1051a39Sopenharmony_ci } 234e1051a39Sopenharmony_ci#undef ADVANCE_BUFFER 235e1051a39Sopenharmony_ci return buf; 236e1051a39Sopenharmony_ci} 237e1051a39Sopenharmony_ci 238e1051a39Sopenharmony_cichar *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo, 239e1051a39Sopenharmony_ci char *buf, size_t bufsize) 240e1051a39Sopenharmony_ci{ 241e1051a39Sopenharmony_ci int failure_info; 242e1051a39Sopenharmony_ci 243e1051a39Sopenharmony_ci if (statusInfo == NULL) { 244e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); 245e1051a39Sopenharmony_ci return NULL; 246e1051a39Sopenharmony_ci } 247e1051a39Sopenharmony_ci 248e1051a39Sopenharmony_ci failure_info = ossl_cmp_pkisi_get_pkifailureinfo(statusInfo); 249e1051a39Sopenharmony_ci 250e1051a39Sopenharmony_ci return snprint_PKIStatusInfo_parts(ASN1_INTEGER_get(statusInfo->status), 251e1051a39Sopenharmony_ci failure_info, 252e1051a39Sopenharmony_ci statusInfo->statusString, buf, bufsize); 253e1051a39Sopenharmony_ci} 254e1051a39Sopenharmony_ci 255e1051a39Sopenharmony_cichar *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf, 256e1051a39Sopenharmony_ci size_t bufsize) 257e1051a39Sopenharmony_ci{ 258e1051a39Sopenharmony_ci if (ctx == NULL) { 259e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); 260e1051a39Sopenharmony_ci return NULL; 261e1051a39Sopenharmony_ci } 262e1051a39Sopenharmony_ci 263e1051a39Sopenharmony_ci return snprint_PKIStatusInfo_parts(OSSL_CMP_CTX_get_status(ctx), 264e1051a39Sopenharmony_ci OSSL_CMP_CTX_get_failInfoCode(ctx), 265e1051a39Sopenharmony_ci OSSL_CMP_CTX_get0_statusString(ctx), 266e1051a39Sopenharmony_ci buf, bufsize); 267e1051a39Sopenharmony_ci} 268e1051a39Sopenharmony_ci 269e1051a39Sopenharmony_ci/*- 270e1051a39Sopenharmony_ci * Creates a new PKIStatusInfo structure and fills it in 271e1051a39Sopenharmony_ci * returns a pointer to the structure on success, NULL on error 272e1051a39Sopenharmony_ci * note: strongly overlaps with TS_RESP_CTX_set_status_info() 273e1051a39Sopenharmony_ci * and TS_RESP_CTX_add_failure_info() in ../ts/ts_rsp_sign.c 274e1051a39Sopenharmony_ci */ 275e1051a39Sopenharmony_ciOSSL_CMP_PKISI *OSSL_CMP_STATUSINFO_new(int status, int fail_info, 276e1051a39Sopenharmony_ci const char *text) 277e1051a39Sopenharmony_ci{ 278e1051a39Sopenharmony_ci OSSL_CMP_PKISI *si = OSSL_CMP_PKISI_new(); 279e1051a39Sopenharmony_ci ASN1_UTF8STRING *utf8_text = NULL; 280e1051a39Sopenharmony_ci int failure; 281e1051a39Sopenharmony_ci 282e1051a39Sopenharmony_ci if (si == NULL) 283e1051a39Sopenharmony_ci goto err; 284e1051a39Sopenharmony_ci if (!ASN1_INTEGER_set(si->status, status)) 285e1051a39Sopenharmony_ci goto err; 286e1051a39Sopenharmony_ci 287e1051a39Sopenharmony_ci if (text != NULL) { 288e1051a39Sopenharmony_ci if ((utf8_text = ASN1_UTF8STRING_new()) == NULL 289e1051a39Sopenharmony_ci || !ASN1_STRING_set(utf8_text, text, -1)) 290e1051a39Sopenharmony_ci goto err; 291e1051a39Sopenharmony_ci if ((si->statusString = sk_ASN1_UTF8STRING_new_null()) == NULL) 292e1051a39Sopenharmony_ci goto err; 293e1051a39Sopenharmony_ci if (!sk_ASN1_UTF8STRING_push(si->statusString, utf8_text)) 294e1051a39Sopenharmony_ci goto err; 295e1051a39Sopenharmony_ci /* Ownership is lost. */ 296e1051a39Sopenharmony_ci utf8_text = NULL; 297e1051a39Sopenharmony_ci } 298e1051a39Sopenharmony_ci 299e1051a39Sopenharmony_ci for (failure = 0; failure <= OSSL_CMP_PKIFAILUREINFO_MAX; failure++) { 300e1051a39Sopenharmony_ci if ((fail_info & (1 << failure)) != 0) { 301e1051a39Sopenharmony_ci if (si->failInfo == NULL 302e1051a39Sopenharmony_ci && (si->failInfo = ASN1_BIT_STRING_new()) == NULL) 303e1051a39Sopenharmony_ci goto err; 304e1051a39Sopenharmony_ci if (!ASN1_BIT_STRING_set_bit(si->failInfo, failure, 1)) 305e1051a39Sopenharmony_ci goto err; 306e1051a39Sopenharmony_ci } 307e1051a39Sopenharmony_ci } 308e1051a39Sopenharmony_ci return si; 309e1051a39Sopenharmony_ci 310e1051a39Sopenharmony_ci err: 311e1051a39Sopenharmony_ci OSSL_CMP_PKISI_free(si); 312e1051a39Sopenharmony_ci ASN1_UTF8STRING_free(utf8_text); 313e1051a39Sopenharmony_ci return NULL; 314e1051a39Sopenharmony_ci} 315