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