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