7ebc57d37bb212777f934c2d2b41684870c295cb
[openssl.git] / crypto / cmp / cmp_status.c
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             ERR_add_error_data(1, 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 }