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