2 * Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright Nokia 2007-2019
4 * Copyright Siemens AG 2015-2019
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
13 #include <openssl/cmp_util.h>
14 #include "cmp_local.h" /* just for decls of internal functions defined here */
15 #include <openssl/cmperr.h>
16 #include <openssl/err.h> /* should be implied by cmperr.h */
17 #include <openssl/x509v3.h>
20 * use trace API for CMP-specific logging, prefixed by "CMP " and severity
23 int OSSL_CMP_log_open(void) /* is designed to be idempotent */
25 #ifndef OPENSSL_NO_STDIO
26 BIO
*bio
= BIO_new_fp(stdout
, BIO_NOCLOSE
);
28 if (bio
!= NULL
&& OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_CMP
, bio
))
32 ERR_raise(ERR_LIB_CMP
, CMP_R_NO_STDIO
);
36 void OSSL_CMP_log_close(void) /* is designed to be idempotent */
38 (void)OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_CMP
, NULL
);
41 /* return >= 0 if level contains logging level, possibly preceded by "CMP " */
42 #define max_level_len 5 /* = max length of the below strings, e.g., "EMERG" */
43 static OSSL_CMP_severity
parse_level(const char *level
)
45 const char *end_level
= strchr(level
, ':');
47 char level_copy
[max_level_len
+ 1];
49 if (end_level
== NULL
)
52 if (strncmp(level
, OSSL_CMP_LOG_PREFIX
,
53 strlen(OSSL_CMP_LOG_PREFIX
)) == 0)
54 level
+= strlen(OSSL_CMP_LOG_PREFIX
);
55 len
= end_level
- level
;
56 if (len
> max_level_len
)
58 OPENSSL_strlcpy(level_copy
, level
, len
+ 1);
60 strcmp(level_copy
, "EMERG") == 0 ? OSSL_CMP_LOG_EMERG
:
61 strcmp(level_copy
, "ALERT") == 0 ? OSSL_CMP_LOG_ALERT
:
62 strcmp(level_copy
, "CRIT") == 0 ? OSSL_CMP_LOG_CRIT
:
63 strcmp(level_copy
, "ERROR") == 0 ? OSSL_CMP_LOG_ERR
:
64 strcmp(level_copy
, "WARN") == 0 ? OSSL_CMP_LOG_WARNING
:
65 strcmp(level_copy
, "NOTE") == 0 ? OSSL_CMP_LOG_NOTICE
:
66 strcmp(level_copy
, "INFO") == 0 ? OSSL_CMP_LOG_INFO
:
67 strcmp(level_copy
, "DEBUG") == 0 ? OSSL_CMP_LOG_DEBUG
:
71 const char *ossl_cmp_log_parse_metadata(const char *buf
,
72 OSSL_CMP_severity
*level
,
73 char **func
, char **file
, int *line
)
75 const char *p_func
= buf
;
76 const char *p_file
= buf
== NULL
? NULL
: strchr(buf
, ':');
77 const char *p_level
= buf
;
78 const char *msg
= buf
;
86 const char *p_line
= strchr(++p_file
, ':');
88 if ((*level
= parse_level(buf
)) < 0 && p_line
!= NULL
) {
89 /* check if buf contains location info and logging level */
90 char *p_level_tmp
= (char *)p_level
;
91 const long line_number
= strtol(++p_line
, &p_level_tmp
, 10);
93 p_level
= p_level_tmp
;
94 if (p_level
> p_line
&& *(p_level
++) == ':') {
95 if ((*level
= parse_level(p_level
)) >= 0) {
96 *func
= OPENSSL_strndup(p_func
, p_file
- 1 - p_func
);
97 *file
= OPENSSL_strndup(p_file
, p_line
- 1 - p_file
);
98 /* no real problem if OPENSSL_strndup() returns NULL */
99 *line
= (int)line_number
;
100 msg
= strchr(p_level
, ':') + 1;
110 #define UNKNOWN_FUNC "(unknown function)" /* the default for OPENSSL_FUNC */
112 * substitute fallback if component/function name is NULL or empty or contains
113 * just pseudo-information "(unknown function)" due to -pedantic and macros.h
115 static const char *improve_location_name(const char *func
, const char *fallback
)
117 if (fallback
== NULL
)
118 return func
== NULL
? UNKNOWN_FUNC
: func
;
120 return func
== NULL
|| *func
== '\0' || strcmp(func
, UNKNOWN_FUNC
) == 0
124 int OSSL_CMP_print_to_bio(BIO
*bio
, const char *component
, const char *file
,
125 int line
, OSSL_CMP_severity level
, const char *msg
)
127 const char *level_string
=
128 level
== OSSL_CMP_LOG_EMERG
? "EMERG" :
129 level
== OSSL_CMP_LOG_ALERT
? "ALERT" :
130 level
== OSSL_CMP_LOG_CRIT
? "CRIT" :
131 level
== OSSL_CMP_LOG_ERR
? "error" :
132 level
== OSSL_CMP_LOG_WARNING
? "warning" :
133 level
== OSSL_CMP_LOG_NOTICE
? "NOTE" :
134 level
== OSSL_CMP_LOG_INFO
? "info" :
135 level
== OSSL_CMP_LOG_DEBUG
? "DEBUG" : "(unknown level)";
138 if (BIO_printf(bio
, "%s:%s:%d:", improve_location_name(component
, "CMP"),
142 return BIO_printf(bio
, OSSL_CMP_LOG_PREFIX
"%s: %s\n",
143 level_string
, msg
) >= 0;
146 #define ERR_PRINT_BUF_SIZE 4096
147 /* this is similar to ERR_print_errors_cb, but uses the CMP-specific cb type */
148 void OSSL_CMP_print_errors_cb(OSSL_CMP_log_cb_t log_fn
)
151 char msg
[ERR_PRINT_BUF_SIZE
];
152 const char *file
= NULL
, *func
= NULL
, *data
= NULL
;
155 while ((err
= ERR_get_error_all(&file
, &line
, &func
, &data
, &flags
)) != 0) {
156 const char *component
=
157 improve_location_name(func
, ERR_lib_error_string(err
));
158 unsigned long reason
= ERR_GET_REASON(err
);
159 const char *rs
= NULL
;
162 #ifndef OPENSSL_NO_ERR
163 if (ERR_SYSTEM_ERROR(err
)) {
164 if (openssl_strerror_r(reason
, rsbuf
, sizeof(rsbuf
)))
167 rs
= ERR_reason_error_string(err
);
171 BIO_snprintf(rsbuf
, sizeof(rsbuf
), "reason(%lu)", reason
);
174 if (data
!= NULL
&& (flags
& ERR_TXT_STRING
) != 0)
175 BIO_snprintf(msg
, sizeof(msg
), "%s:%s", rs
, data
);
177 BIO_snprintf(msg
, sizeof(msg
), "%s", rs
);
179 if (log_fn
== NULL
) {
180 #ifndef OPENSSL_NO_STDIO
181 BIO
*bio
= BIO_new_fp(stderr
, BIO_NOCLOSE
);
184 OSSL_CMP_print_to_bio(bio
, component
, file
, line
,
185 OSSL_CMP_LOG_ERR
, msg
);
189 /* ERR_raise(ERR_LIB_CMP, CMP_R_NO_STDIO) makes no sense during error printing */
192 if (log_fn(component
, file
, line
, OSSL_CMP_LOG_ERR
, msg
) <= 0)
193 break; /* abort outputting the error report */
198 int ossl_cmp_X509_STORE_add1_certs(X509_STORE
*store
, STACK_OF(X509
) *certs
,
199 int only_self_signed
)
204 ERR_raise(ERR_LIB_CMP
, CMP_R_NULL_ARGUMENT
);
209 for (i
= 0; i
< sk_X509_num(certs
); i
++) {
210 X509
*cert
= sk_X509_value(certs
, i
);
212 if (!only_self_signed
|| X509_self_signed(cert
, 0) == 1)
213 if (!X509_STORE_add_cert(store
, cert
)) /* ups cert ref counter */
220 * Builds a certificate chain starting from <cert>
221 * using the optional list of intermediate CA certificates <certs>.
222 * If <store> is NULL builds the chain as far down as possible, ignoring errors.
223 * Else the chain must reach a trust anchor contained in <store>.
225 * Returns NULL on error, else a pointer to a stack of (up_ref'ed) certificates
226 * starting with given EE certificate and followed by all available intermediate
227 * certificates down towards any trust anchor but without including the latter.
229 * NOTE: If a non-NULL stack is returned the caller is responsible for freeing.
230 * NOTE: In case there is more than one possibility for the chain,
231 * OpenSSL seems to take the first one; check X509_verify_cert() for details.
233 /* TODO this should be of more general interest and thus be exported. */
235 *ossl_cmp_build_cert_chain(OSSL_LIB_CTX
*libctx
, const char *propq
,
237 STACK_OF(X509
) *certs
, X509
*cert
)
239 STACK_OF(X509
) *chain
= NULL
, *result
= NULL
;
240 X509_STORE
*ts
= store
== NULL
? X509_STORE_new() : store
;
241 X509_STORE_CTX
*csc
= NULL
;
243 if (ts
== NULL
|| cert
== NULL
) {
244 ERR_raise(ERR_LIB_CMP
, CMP_R_NULL_ARGUMENT
);
248 if ((csc
= X509_STORE_CTX_new_ex(libctx
, propq
)) == NULL
)
250 if (store
== NULL
&& certs
!= NULL
251 && !ossl_cmp_X509_STORE_add1_certs(ts
, certs
, 0))
253 if (!X509_STORE_CTX_init(csc
, ts
, cert
,
254 store
== NULL
? NULL
: certs
))
256 /* disable any cert status/revocation checking etc. */
257 X509_VERIFY_PARAM_clear_flags(X509_STORE_CTX_get0_param(csc
),
258 ~(X509_V_FLAG_USE_CHECK_TIME
259 | X509_V_FLAG_NO_CHECK_TIME
));
261 if (X509_verify_cert(csc
) <= 0 && store
!= NULL
)
263 chain
= X509_STORE_CTX_get0_chain(csc
);
265 /* result list to store the up_ref'ed not self-signed certificates */
266 if (!ossl_x509_add_certs_new(&result
, chain
,
267 X509_ADD_FLAG_UP_REF
| X509_ADD_FLAG_NO_DUP
268 | X509_ADD_FLAG_NO_SS
)) {
269 sk_X509_free(result
);
276 X509_STORE_CTX_free(csc
);
280 int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING
) *sk
,
283 ASN1_UTF8STRING
*utf8string
;
285 if (!ossl_assert(sk
!= NULL
&& text
!= NULL
))
287 if ((utf8string
= ASN1_UTF8STRING_new()) == NULL
)
289 if (!ASN1_STRING_set(utf8string
, text
, -1))
291 if (!sk_ASN1_UTF8STRING_push(sk
, utf8string
))
296 ASN1_UTF8STRING_free(utf8string
);
300 int ossl_cmp_asn1_octet_string_set1(ASN1_OCTET_STRING
**tgt
,
301 const ASN1_OCTET_STRING
*src
)
303 ASN1_OCTET_STRING
*new;
305 ERR_raise(ERR_LIB_CMP
, CMP_R_NULL_ARGUMENT
);
308 if (*tgt
== src
) /* self-assignment */
312 if ((new = ASN1_OCTET_STRING_dup(src
)) == NULL
)
318 ASN1_OCTET_STRING_free(*tgt
);
323 int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING
**tgt
,
324 const unsigned char *bytes
, int len
)
326 ASN1_OCTET_STRING
*new = NULL
;
329 ERR_raise(ERR_LIB_CMP
, CMP_R_NULL_ARGUMENT
);
333 if ((new = ASN1_OCTET_STRING_new()) == NULL
334 || !(ASN1_OCTET_STRING_set(new, bytes
, len
))) {
335 ASN1_OCTET_STRING_free(new);
340 ASN1_OCTET_STRING_free(*tgt
);