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