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