xref: /netbsd-src/external/mpl/bind/dist/lib/dns/openssl_link.c (revision b2c35e17b976cf7ccd7250c86c6f5e95090ed636)
1 /*	$NetBSD: openssl_link.c,v 1.10 2024/02/21 22:52:07 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0 AND ISC
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*
17  * Copyright (C) Network Associates, Inc.
18  *
19  * Permission to use, copy, modify, and/or distribute this software for any
20  * purpose with or without fee is hereby granted, provided that the above
21  * copyright notice and this permission notice appear in all copies.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
24  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
26  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
29  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  */
31 
32 #include <isc/mem.h>
33 #include <isc/mutex.h>
34 #include <isc/mutexblock.h>
35 #include <isc/result.h>
36 #include <isc/string.h>
37 #include <isc/thread.h>
38 #include <isc/tls.h>
39 #include <isc/util.h>
40 
41 #include <dns/log.h>
42 
43 #include "dst_internal.h"
44 #include "dst_openssl.h"
45 
46 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000
47 #include <openssl/engine.h>
48 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */
49 
50 #include "openssl_shim.h"
51 
52 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000
53 static ENGINE *e = NULL;
54 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */
55 
56 static void
57 enable_fips_mode(void) {
58 #ifdef HAVE_FIPS_MODE
59 	if (FIPS_mode() != 0) {
60 		/*
61 		 * FIPS mode is already enabled.
62 		 */
63 		return;
64 	}
65 
66 	if (FIPS_mode_set(1) == 0) {
67 		dst__openssl_toresult2("FIPS_mode_set", DST_R_OPENSSLFAILURE);
68 		exit(1);
69 	}
70 #endif /* HAVE_FIPS_MODE */
71 }
72 
73 isc_result_t
74 dst__openssl_init(const char *engine) {
75 	isc_result_t result = ISC_R_SUCCESS;
76 
77 	enable_fips_mode();
78 
79 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000
80 	if (engine != NULL && *engine == '\0') {
81 		engine = NULL;
82 	}
83 
84 	if (engine != NULL) {
85 		e = ENGINE_by_id(engine);
86 		if (e == NULL) {
87 			result = DST_R_NOENGINE;
88 			goto cleanup_rm;
89 		}
90 		if (!ENGINE_init(e)) {
91 			result = DST_R_NOENGINE;
92 			goto cleanup_rm;
93 		}
94 		/* This will init the engine. */
95 		if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
96 			result = DST_R_NOENGINE;
97 			goto cleanup_init;
98 		}
99 	}
100 
101 	return (ISC_R_SUCCESS);
102 cleanup_init:
103 	ENGINE_finish(e);
104 cleanup_rm:
105 	if (e != NULL) {
106 		ENGINE_free(e);
107 	}
108 	e = NULL;
109 	ERR_clear_error();
110 #else
111 	UNUSED(engine);
112 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */
113 	return (result);
114 }
115 
116 void
117 dst__openssl_destroy(void) {
118 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000
119 	if (e != NULL) {
120 		ENGINE_finish(e);
121 		ENGINE_free(e);
122 	}
123 	e = NULL;
124 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */
125 }
126 
127 static isc_result_t
128 toresult(isc_result_t fallback) {
129 	isc_result_t result = fallback;
130 	unsigned long err = ERR_peek_error();
131 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
132 	int lib = ERR_GET_LIB(err);
133 #endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */
134 	int reason = ERR_GET_REASON(err);
135 
136 	switch (reason) {
137 	/*
138 	 * ERR_* errors are globally unique; others
139 	 * are unique per sublibrary
140 	 */
141 	case ERR_R_MALLOC_FAILURE:
142 		result = ISC_R_NOMEMORY;
143 		break;
144 	default:
145 #if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
146 		if (lib == ERR_R_ECDSA_LIB &&
147 		    reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
148 		{
149 			result = ISC_R_NOENTROPY;
150 			break;
151 		}
152 #endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */
153 		break;
154 	}
155 
156 	return (result);
157 }
158 
159 isc_result_t
160 dst__openssl_toresult(isc_result_t fallback) {
161 	isc_result_t result;
162 
163 	result = toresult(fallback);
164 
165 	ERR_clear_error();
166 	return (result);
167 }
168 
169 isc_result_t
170 dst__openssl_toresult2(const char *funcname, isc_result_t fallback) {
171 	return (dst__openssl_toresult3(DNS_LOGCATEGORY_GENERAL, funcname,
172 				       fallback));
173 }
174 
175 isc_result_t
176 dst__openssl_toresult3(isc_logcategory_t *category, const char *funcname,
177 		       isc_result_t fallback) {
178 	isc_result_t result;
179 	unsigned long err;
180 	const char *file, *func, *data;
181 	int line, flags;
182 	char buf[256];
183 
184 	result = toresult(fallback);
185 
186 	isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
187 		      "%s failed (%s)", funcname, isc_result_totext(result));
188 
189 	if (result == ISC_R_NOMEMORY) {
190 		goto done;
191 	}
192 
193 	for (;;) {
194 		err = ERR_get_error_all(&file, &line, &func, &data, &flags);
195 		if (err == 0U) {
196 			goto done;
197 		}
198 		ERR_error_string_n(err, buf, sizeof(buf));
199 		isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO,
200 			      ISC_LOG_INFO, "%s:%s:%d:%s", buf, file, line,
201 			      ((flags & ERR_TXT_STRING) != 0) ? data : "");
202 	}
203 
204 done:
205 	ERR_clear_error();
206 	return (result);
207 }
208 
209 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000
210 ENGINE *
211 dst__openssl_getengine(const char *engine) {
212 	if (engine == NULL) {
213 		return (NULL);
214 	}
215 	if (e == NULL) {
216 		return (NULL);
217 	}
218 	if (strcmp(engine, ENGINE_get_id(e)) == 0) {
219 		return (e);
220 	}
221 	return (NULL);
222 }
223 #endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */
224 
225 /*! \file */
226