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