xref: /openbsd-src/usr.sbin/nsd/tsig-openssl.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*
2  * tsig-openssl.h -- Interface to OpenSSL for TSIG support.
3  *
4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 
12 #if defined(HAVE_SSL)
13 
14 #ifdef HAVE_OPENSSL_CORE_NAMES_H
15 #include <openssl/core_names.h>
16 #endif
17 #include "tsig-openssl.h"
18 #include "tsig.h"
19 #include "util.h"
20 
21 static void *create_context(region_type *region);
22 static void init_context(void *context,
23 			 tsig_algorithm_type *algorithm,
24 			 tsig_key_type *key);
25 static void update(void *context, const void *data, size_t size);
26 static void final(void *context, uint8_t *digest, size_t *size);
27 
28 #ifdef HAVE_EVP_MAC_CTX_NEW
29 struct tsig_openssl_data {
30 	/* the MAC for the algorithm, 'hmac' */
31 	EVP_MAC* mac;
32 	/* the digest name for creating the EVP_MAC_CTX with, 'sha256' */
33 	const char* digest;
34 };
35 
36 struct tsig_openssl_context {
37 	/* the evp mac context, if notNULL it has algo and key set. */
38 	EVP_MAC_CTX* hmac_ctx;
39 	/* the size of destination buffers */
40 	size_t outsize;
41 };
42 
43 static void
44 cleanup_tsig_openssl_data(void *data)
45 {
46 	struct tsig_openssl_data* d = (struct tsig_openssl_data*)data;
47 	EVP_MAC_free(d->mac);
48 	d->mac = NULL;
49 }
50 #endif
51 
52 static int
53 tsig_openssl_init_algorithm(region_type* region,
54 	const char* digest, const char* name, const char* wireformat)
55 {
56 	tsig_algorithm_type* algorithm;
57 #ifndef HAVE_EVP_MAC_CTX_NEW
58 	const EVP_MD *hmac_algorithm;
59 
60 	hmac_algorithm = EVP_get_digestbyname(digest);
61 	if (!hmac_algorithm) {
62 		/* skip but don't error */
63 		return 0;
64 	}
65 #else
66 	struct tsig_openssl_data* data;
67 	EVP_MAC_CTX* hmac_ctx;
68 	OSSL_PARAM params[3];
69 	data = region_alloc(region, sizeof(*data));
70 	data->digest = digest;
71 	data->mac = EVP_MAC_fetch(NULL, "hmac", NULL);
72 	if(!data->mac) {
73 		log_msg(LOG_ERR, "could not fetch MAC implementation 'hmac' with EVP_MAC_fetch");
74 		return 0;
75 	}
76 	/* this context is created to see what size the output is */
77 	hmac_ctx = EVP_MAC_CTX_new(data->mac);
78 	if(!hmac_ctx) {
79 		EVP_MAC_free(data->mac);
80 		return 0;
81 	}
82 	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
83 		(char*)digest, 0);
84 	params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
85 		"", 1);
86 	params[2] = OSSL_PARAM_construct_end();
87 #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
88 	if(EVP_MAC_CTX_set_params(hmac_ctx, params) <= 0) {
89 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params");
90 		EVP_MAC_CTX_free(hmac_ctx);
91 		EVP_MAC_free(data->mac);
92 		return 0;
93 	}
94 #else
95 	if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) {
96 		log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params");
97 		EVP_MAC_CTX_free(hmac_ctx);
98 		EVP_MAC_free(data->mac);
99 		return 0;
100 	}
101 #endif
102 #endif
103 
104 	algorithm = (tsig_algorithm_type *) region_alloc(
105 		region, sizeof(tsig_algorithm_type));
106 	algorithm->short_name = name;
107 	algorithm->wireformat_name
108 		= dname_parse(region, wireformat);
109 	if (!algorithm->wireformat_name) {
110 		log_msg(LOG_ERR, "cannot parse %s algorithm", wireformat);
111 #ifdef HAVE_EVP_MAC_CTX_NEW
112 		EVP_MAC_CTX_free(hmac_ctx);
113 		EVP_MAC_free(data->mac);
114 #endif
115 		return 0;
116 	}
117 #ifndef HAVE_EVP_MAC_CTX_NEW
118 	algorithm->maximum_digest_size = EVP_MD_size(hmac_algorithm);
119 #else
120 	algorithm->maximum_digest_size = EVP_MAC_size(hmac_ctx);
121 #endif
122 	if(algorithm->maximum_digest_size < 20)
123 		algorithm->maximum_digest_size = EVP_MAX_MD_SIZE;
124 #ifndef HAVE_EVP_MAC_CTX_NEW
125 	algorithm->data = hmac_algorithm;
126 #else
127 	algorithm->data = data;
128 	region_add_cleanup(region, cleanup_tsig_openssl_data, data);
129 #endif
130 	algorithm->hmac_create_context = create_context;
131 	algorithm->hmac_init_context = init_context;
132 	algorithm->hmac_update = update;
133 	algorithm->hmac_final = final;
134 	tsig_add_algorithm(algorithm);
135 
136 #ifdef HAVE_EVP_MAC_CTX_NEW
137 	EVP_MAC_CTX_free(hmac_ctx);
138 #endif
139 	return 1;
140 }
141 
142 int
143 tsig_openssl_init(region_type *region)
144 {
145 	int count = 0;
146 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
147 	OpenSSL_add_all_digests();
148 #else
149 	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
150 #endif
151 
152 	count += tsig_openssl_init_algorithm(region,
153 	    "md5", "hmac-md5","hmac-md5.sig-alg.reg.int.");
154 	count += tsig_openssl_init_algorithm(region,
155 	    "sha1", "hmac-sha1", "hmac-sha1.");
156 	count += tsig_openssl_init_algorithm(region,
157 	    "sha224", "hmac-sha224", "hmac-sha224.");
158 	count += tsig_openssl_init_algorithm(region,
159 	    "sha256", "hmac-sha256", "hmac-sha256.");
160 	count += tsig_openssl_init_algorithm(region,
161 	    "sha384", "hmac-sha384", "hmac-sha384.");
162 	count += tsig_openssl_init_algorithm(region,
163 	    "sha512", "hmac-sha512", "hmac-sha512.");
164 
165 	return count;
166 }
167 
168 static void
169 cleanup_context(void *data)
170 {
171 #ifndef HAVE_EVP_MAC_CTX_NEW
172 	HMAC_CTX *context = (HMAC_CTX *) data;
173 #ifdef HAVE_HMAC_CTX_NEW
174 	HMAC_CTX_free(context);
175 #else
176 	HMAC_CTX_cleanup(context);
177 	free(context);
178 #endif
179 #else
180 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)data;
181 	EVP_MAC_CTX_free(c->hmac_ctx);
182 	c->hmac_ctx = NULL;
183 #endif
184 }
185 
186 static void *
187 create_context(region_type *region)
188 {
189 #ifndef HAVE_EVP_MAC_CTX_NEW
190 #ifdef HAVE_HMAC_CTX_NEW
191 	HMAC_CTX *context = HMAC_CTX_new();
192 #else
193 	HMAC_CTX *context = (HMAC_CTX *) malloc(sizeof(HMAC_CTX));
194 #endif
195 	region_add_cleanup(region, cleanup_context, context);
196 #ifdef HAVE_HMAC_CTX_RESET
197 	HMAC_CTX_reset(context);
198 #else
199 	HMAC_CTX_init(context);
200 #endif
201 #else
202 	struct tsig_openssl_context* context = region_alloc(region,
203 		sizeof(*context));
204 	memset(context, 0, sizeof(*context));
205 	region_add_cleanup(region, cleanup_context, context);
206 #endif
207 	return context;
208 }
209 
210 static void
211 init_context(void *context,
212 			  tsig_algorithm_type *algorithm,
213 			  tsig_key_type *key)
214 {
215 #ifndef HAVE_EVP_MAC_CTX_NEW
216 	HMAC_CTX *ctx = (HMAC_CTX *) context;
217 	const EVP_MD *md = (const EVP_MD *) algorithm->data;
218 	HMAC_Init_ex(ctx, key->data, key->size, md, NULL);
219 #else
220 	OSSL_PARAM params[3];
221 	struct tsig_openssl_data* algo_data = (struct tsig_openssl_data*)
222 		algorithm->data;
223 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
224 	if(c->hmac_ctx) {
225 		EVP_MAC_CTX_free(c->hmac_ctx);
226 	}
227 	c->hmac_ctx = EVP_MAC_CTX_new(algo_data->mac);
228 	if(!c->hmac_ctx) {
229 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_new");
230 		return;
231 	}
232 	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
233 		(char*)algo_data->digest, 0);
234 	params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
235 		key->data, key->size);
236 	params[2] = OSSL_PARAM_construct_end();
237 #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
238 	if(EVP_MAC_CTX_set_params(c->hmac_ctx, params) <= 0) {
239 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params");
240 		EVP_MAC_CTX_free(c->hmac_ctx);
241 		c->hmac_ctx = NULL;
242 		return;
243 	}
244 #else
245 	if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) {
246 		log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params");
247 		EVP_MAC_CTX_free(c->hmac_ctx);
248 		c->hmac_ctx = NULL;
249 		return;
250 	}
251 #endif
252 	c->outsize = algorithm->maximum_digest_size;
253 #endif
254 }
255 
256 static void
257 update(void *context, const void *data, size_t size)
258 {
259 #ifndef HAVE_EVP_MAC_CTX_NEW
260 	HMAC_CTX *ctx = (HMAC_CTX *) context;
261 	HMAC_Update(ctx, (unsigned char *) data, (int) size);
262 #else
263 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
264 	if(EVP_MAC_update(c->hmac_ctx, data, size) <= 0) {
265 		log_msg(LOG_ERR, "could not EVP_MAC_update");
266 	}
267 #endif
268 }
269 
270 static void
271 final(void *context, uint8_t *digest, size_t *size)
272 {
273 #ifndef HAVE_EVP_MAC_CTX_NEW
274 	HMAC_CTX *ctx = (HMAC_CTX *) context;
275 	unsigned len = (unsigned) *size;
276 	HMAC_Final(ctx, digest, &len);
277 	*size = (size_t) len;
278 #else
279 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
280 	if(EVP_MAC_final(c->hmac_ctx, digest, size, c->outsize) <= 0) {
281 		log_msg(LOG_ERR, "could not EVP_MAC_final");
282 	}
283 #endif
284 }
285 
286 void
287 tsig_openssl_finalize()
288 {
289 #ifdef HAVE_EVP_CLEANUP
290 	EVP_cleanup();
291 #endif
292 }
293 
294 #endif /* defined(HAVE_SSL) */
295