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