1/*	$NetBSD: openssl_link.c,v 1.1 2024/02/18 20:57:32 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/platform.h>
36#include <isc/string.h>
37#include <isc/thread.h>
38#include <isc/util.h>
39
40#include <dns/log.h>
41
42#include <dst/result.h>
43
44#include "dst_internal.h"
45#include "dst_openssl.h"
46
47#if !defined(OPENSSL_NO_ENGINE)
48#include <openssl/engine.h>
49#endif /* if !defined(OPENSSL_NO_ENGINE) */
50
51#if !defined(OPENSSL_NO_ENGINE)
52static ENGINE *e = NULL;
53#endif /* if !defined(OPENSSL_NO_ENGINE) */
54
55static void
56enable_fips_mode(void) {
57#ifdef HAVE_FIPS_MODE
58	if (FIPS_mode() != 0) {
59		/*
60		 * FIPS mode is already enabled.
61		 */
62		return;
63	}
64
65	if (FIPS_mode_set(1) == 0) {
66		dst__openssl_toresult2("FIPS_mode_set", DST_R_OPENSSLFAILURE);
67		exit(1);
68	}
69#endif /* HAVE_FIPS_MODE */
70}
71
72isc_result_t
73dst__openssl_init(const char *engine) {
74	isc_result_t result = ISC_R_SUCCESS;
75
76	enable_fips_mode();
77
78#if !defined(OPENSSL_NO_ENGINE)
79	if (engine != NULL && *engine == '\0') {
80		engine = NULL;
81	}
82
83	if (engine != NULL) {
84		e = ENGINE_by_id(engine);
85		if (e == NULL) {
86			result = DST_R_NOENGINE;
87			goto cleanup_rm;
88		}
89		/* This will init the engine. */
90		if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
91			result = DST_R_NOENGINE;
92			goto cleanup_rm;
93		}
94	}
95
96	return (ISC_R_SUCCESS);
97cleanup_rm:
98	if (e != NULL) {
99		ENGINE_free(e);
100	}
101	e = NULL;
102#else
103	UNUSED(engine);
104#endif /* if !defined(OPENSSL_NO_ENGINE) */
105	return (result);
106}
107
108void
109dst__openssl_destroy(void) {
110#if !defined(OPENSSL_NO_ENGINE)
111	if (e != NULL) {
112		ENGINE_free(e);
113	}
114	e = NULL;
115#endif /* if !defined(OPENSSL_NO_ENGINE) */
116}
117
118static isc_result_t
119toresult(isc_result_t fallback) {
120	isc_result_t result = fallback;
121	unsigned long err = ERR_peek_error();
122#if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
123	int lib = ERR_GET_LIB(err);
124#endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */
125	int reason = ERR_GET_REASON(err);
126
127	switch (reason) {
128	/*
129	 * ERR_* errors are globally unique; others
130	 * are unique per sublibrary
131	 */
132	case ERR_R_MALLOC_FAILURE:
133		result = ISC_R_NOMEMORY;
134		break;
135	default:
136#if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
137		if (lib == ERR_R_ECDSA_LIB &&
138		    reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
139		{
140			result = ISC_R_NOENTROPY;
141			break;
142		}
143#endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */
144		break;
145	}
146
147	return (result);
148}
149
150isc_result_t
151dst__openssl_toresult(isc_result_t fallback) {
152	isc_result_t result;
153
154	result = toresult(fallback);
155
156	ERR_clear_error();
157	return (result);
158}
159
160isc_result_t
161dst__openssl_toresult2(const char *funcname, isc_result_t fallback) {
162	return (dst__openssl_toresult3(DNS_LOGCATEGORY_GENERAL, funcname,
163				       fallback));
164}
165
166isc_result_t
167dst__openssl_toresult3(isc_logcategory_t *category, const char *funcname,
168		       isc_result_t fallback) {
169	isc_result_t result;
170	unsigned long err;
171	const char *file, *data;
172	int line, flags;
173	char buf[256];
174
175	result = toresult(fallback);
176
177	isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
178		      "%s failed (%s)", funcname, isc_result_totext(result));
179
180	if (result == ISC_R_NOMEMORY) {
181		goto done;
182	}
183
184	for (;;) {
185		err = ERR_get_error_line_data(&file, &line, &data, &flags);
186		if (err == 0U) {
187			goto done;
188		}
189		ERR_error_string_n(err, buf, sizeof(buf));
190		isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO,
191			      ISC_LOG_INFO, "%s:%s:%d:%s", buf, file, line,
192			      ((flags & ERR_TXT_STRING) != 0) ? data : "");
193	}
194
195done:
196	ERR_clear_error();
197	return (result);
198}
199
200#if !defined(OPENSSL_NO_ENGINE)
201ENGINE *
202dst__openssl_getengine(const char *engine) {
203	if (engine == NULL) {
204		return (NULL);
205	}
206	if (e == NULL) {
207		return (NULL);
208	}
209	if (strcmp(engine, ENGINE_get_id(e)) == 0) {
210		return (e);
211	}
212	return (NULL);
213}
214#endif /* if !defined(OPENSSL_NO_ENGINE) */
215
216/*! \file */
217