xref: /openbsd/usr.sbin/nsd/tsig-openssl.c (revision a904e103)
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
cleanup_tsig_openssl_data(void * data)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
tsig_openssl_init_algorithm(region_type * region,const char * digest,const char * name,const char * wireformat)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 #ifdef HAVE_EVP_MAC_CTX_GET_MAC_SIZE
118 	algorithm->maximum_digest_size = EVP_MAC_CTX_get_mac_size(hmac_ctx);
119 #elif !defined(HAVE_EVP_MAC_CTX_NEW)
120 	algorithm->maximum_digest_size = EVP_MD_size(hmac_algorithm);
121 #else
122 	algorithm->maximum_digest_size = EVP_MAC_size(hmac_ctx);
123 #endif
124 	if(algorithm->maximum_digest_size < 20)
125 		algorithm->maximum_digest_size = EVP_MAX_MD_SIZE;
126 #ifndef HAVE_EVP_MAC_CTX_NEW
127 	algorithm->data = hmac_algorithm;
128 #else
129 	algorithm->data = data;
130 	region_add_cleanup(region, cleanup_tsig_openssl_data, data);
131 #endif
132 	algorithm->hmac_create_context = create_context;
133 	algorithm->hmac_init_context = init_context;
134 	algorithm->hmac_update = update;
135 	algorithm->hmac_final = final;
136 	tsig_add_algorithm(algorithm);
137 
138 #ifdef HAVE_EVP_MAC_CTX_NEW
139 	EVP_MAC_CTX_free(hmac_ctx);
140 #endif
141 	return 1;
142 }
143 
144 int
tsig_openssl_init(region_type * region)145 tsig_openssl_init(region_type *region)
146 {
147 	int count = 0;
148 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
149 	OpenSSL_add_all_digests();
150 #else
151 	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
152 #endif
153 
154 	count += tsig_openssl_init_algorithm(region,
155 	    "md5", "hmac-md5","hmac-md5.sig-alg.reg.int.");
156 	count += tsig_openssl_init_algorithm(region,
157 	    "sha1", "hmac-sha1", "hmac-sha1.");
158 	count += tsig_openssl_init_algorithm(region,
159 	    "sha224", "hmac-sha224", "hmac-sha224.");
160 	count += tsig_openssl_init_algorithm(region,
161 	    "sha256", "hmac-sha256", "hmac-sha256.");
162 	count += tsig_openssl_init_algorithm(region,
163 	    "sha384", "hmac-sha384", "hmac-sha384.");
164 	count += tsig_openssl_init_algorithm(region,
165 	    "sha512", "hmac-sha512", "hmac-sha512.");
166 
167 	return count;
168 }
169 
170 static void
cleanup_context(void * data)171 cleanup_context(void *data)
172 {
173 #ifndef HAVE_EVP_MAC_CTX_NEW
174 	HMAC_CTX *context = (HMAC_CTX *) data;
175 #ifdef HAVE_HMAC_CTX_NEW
176 	HMAC_CTX_free(context);
177 #else
178 	HMAC_CTX_cleanup(context);
179 	free(context);
180 #endif
181 #else
182 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)data;
183 	EVP_MAC_CTX_free(c->hmac_ctx);
184 	c->hmac_ctx = NULL;
185 #endif
186 }
187 
188 static void *
create_context(region_type * region)189 create_context(region_type *region)
190 {
191 #ifndef HAVE_EVP_MAC_CTX_NEW
192 #ifdef HAVE_HMAC_CTX_NEW
193 	HMAC_CTX *context = HMAC_CTX_new();
194 #else
195 	HMAC_CTX *context = (HMAC_CTX *) malloc(sizeof(HMAC_CTX));
196 #endif
197 	region_add_cleanup(region, cleanup_context, context);
198 #ifdef HAVE_HMAC_CTX_RESET
199 	HMAC_CTX_reset(context);
200 #else
201 	HMAC_CTX_init(context);
202 #endif
203 #else
204 	struct tsig_openssl_context* context = region_alloc(region,
205 		sizeof(*context));
206 	memset(context, 0, sizeof(*context));
207 	region_add_cleanup(region, cleanup_context, context);
208 #endif
209 	return context;
210 }
211 
212 static void
init_context(void * context,tsig_algorithm_type * algorithm,tsig_key_type * key)213 init_context(void *context,
214 			  tsig_algorithm_type *algorithm,
215 			  tsig_key_type *key)
216 {
217 #ifndef HAVE_EVP_MAC_CTX_NEW
218 	HMAC_CTX *ctx = (HMAC_CTX *) context;
219 	const EVP_MD *md = (const EVP_MD *) algorithm->data;
220 	HMAC_Init_ex(ctx, key->data, key->size, md, NULL);
221 #else
222 	OSSL_PARAM params[3];
223 	struct tsig_openssl_data* algo_data = (struct tsig_openssl_data*)
224 		algorithm->data;
225 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
226 	if(c->hmac_ctx) {
227 		EVP_MAC_CTX_free(c->hmac_ctx);
228 	}
229 	c->hmac_ctx = EVP_MAC_CTX_new(algo_data->mac);
230 	if(!c->hmac_ctx) {
231 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_new");
232 		return;
233 	}
234 	params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
235 		(char*)algo_data->digest, 0);
236 	params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
237 		key->data, key->size);
238 	params[2] = OSSL_PARAM_construct_end();
239 #ifdef HAVE_EVP_MAC_CTX_SET_PARAMS
240 	if(EVP_MAC_CTX_set_params(c->hmac_ctx, params) <= 0) {
241 		log_msg(LOG_ERR, "could not EVP_MAC_CTX_set_params");
242 		EVP_MAC_CTX_free(c->hmac_ctx);
243 		c->hmac_ctx = NULL;
244 		return;
245 	}
246 #else
247 	if(EVP_MAC_set_ctx_params(hmac_ctx, params) <= 0) {
248 		log_msg(LOG_ERR, "could not EVP_MAC_set_ctx_params");
249 		EVP_MAC_CTX_free(c->hmac_ctx);
250 		c->hmac_ctx = NULL;
251 		return;
252 	}
253 #endif
254 	c->outsize = algorithm->maximum_digest_size;
255 #endif
256 }
257 
258 static void
update(void * context,const void * data,size_t size)259 update(void *context, const void *data, size_t size)
260 {
261 #ifndef HAVE_EVP_MAC_CTX_NEW
262 	HMAC_CTX *ctx = (HMAC_CTX *) context;
263 	HMAC_Update(ctx, (unsigned char *) data, (int) size);
264 #else
265 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
266 	if(EVP_MAC_update(c->hmac_ctx, data, size) <= 0) {
267 		log_msg(LOG_ERR, "could not EVP_MAC_update");
268 	}
269 #endif
270 }
271 
272 static void
final(void * context,uint8_t * digest,size_t * size)273 final(void *context, uint8_t *digest, size_t *size)
274 {
275 #ifndef HAVE_EVP_MAC_CTX_NEW
276 	HMAC_CTX *ctx = (HMAC_CTX *) context;
277 	unsigned len = (unsigned) *size;
278 	HMAC_Final(ctx, digest, &len);
279 	*size = (size_t) len;
280 #else
281 	struct tsig_openssl_context* c = (struct tsig_openssl_context*)context;
282 	if(EVP_MAC_final(c->hmac_ctx, digest, size, c->outsize) <= 0) {
283 		log_msg(LOG_ERR, "could not EVP_MAC_final");
284 	}
285 #endif
286 }
287 
288 void
tsig_openssl_finalize()289 tsig_openssl_finalize()
290 {
291 #ifdef HAVE_EVP_CLEANUP
292 	EVP_cleanup();
293 #endif
294 }
295 
296 #endif /* defined(HAVE_SSL) */
297