1 | /*
|
---|
2 | * Copyright 2007-2022 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 | }
|
---|