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