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