GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayd/ssl.c Lines: 23 145 15.9 %
Date: 2017-11-13 Branches: 8 83 9.6 %

Line Branch Exec Source
1
/*	$OpenBSD: ssl.c,v 1.34 2017/07/28 13:58:52 bluhm Exp $	*/
2
3
/*
4
 * Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
5
 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/queue.h>
22
#include <sys/uio.h>
23
24
#include <unistd.h>
25
#include <string.h>
26
#include <imsg.h>
27
28
#include <openssl/ssl.h>
29
#include <openssl/err.h>
30
#include <openssl/engine.h>
31
32
#include "relayd.h"
33
#include "boguskeys.h"
34
35
int	ssl_password_cb(char *, int, int, void *);
36
37
void
38
ssl_init(struct relayd *env)
39
{
40
	static int	 initialized = 0;
41
42
576
	if (initialized)
43
		return;
44
45
140
	SSL_library_init();
46
140
	SSL_load_error_strings();
47
48
	/* Init hardware crypto engines. */
49
140
	ENGINE_load_builtin_engines();
50
140
	ENGINE_register_all_complete();
51
52
140
	initialized = 1;
53
428
}
54
55
int
56
ssl_password_cb(char *buf, int size, int rwflag, void *u)
57
{
58
	size_t	len;
59
	if (u == NULL) {
60
		bzero(buf, size);
61
		return (0);
62
	}
63
	if ((len = strlcpy(buf, u, size)) >= (size_t)size)
64
		return (0);
65
	return (len);
66
}
67
68
char *
69
ssl_load_key(struct relayd *env, const char *name, off_t *len, char *pass)
70
{
71
	FILE		*fp;
72
	EVP_PKEY	*key = NULL;
73
	BIO		*bio = NULL;
74
	long		 size;
75
296
	char		*data, *buf = NULL;
76
77
	/* Initialize SSL library once */
78
148
	ssl_init(env);
79
80
	/*
81
	 * Read (possibly) encrypted key from file
82
	 */
83
148
	if ((fp = fopen(name, "r")) == NULL)
84
		return (NULL);
85
86
148
	key = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, pass);
87
148
	fclose(fp);
88
148
	if (key == NULL)
89
		goto fail;
90
91
	/*
92
	 * Write unencrypted key to memory buffer
93
	 */
94
148
	if ((bio = BIO_new(BIO_s_mem())) == NULL)
95
		goto fail;
96
148
	if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL))
97
		goto fail;
98
148
	if ((size = BIO_get_mem_data(bio, &data)) <= 0)
99
		goto fail;
100
148
	if ((buf = calloc(1, size)) == NULL)
101
		goto fail;
102
148
	memcpy(buf, data, size);
103
104
148
	BIO_free_all(bio);
105
148
	EVP_PKEY_free(key);
106
107
148
	*len = (off_t)size;
108
148
	return (buf);
109
110
 fail:
111
	free(buf);
112
	if (bio != NULL)
113
		BIO_free_all(bio);
114
	if (key != NULL)
115
		EVP_PKEY_free(key);
116
	return (NULL);
117
148
}
118
119
uint8_t *
120
ssl_update_certificate(const uint8_t *oldcert, size_t oldlen, EVP_PKEY *pkey,
121
    EVP_PKEY *capkey, X509 *cacert, size_t *newlen)
122
{
123
	char		 name[2][TLS_NAME_SIZE];
124
	BIO		*in, *out = NULL;
125
	BUF_MEM		*bptr = NULL;
126
	X509		*cert = NULL;
127
	uint8_t		*newcert = NULL, *foo = NULL;
128
129
	/* XXX BIO_new_mem_buf is not using const so work around this */
130
	if ((foo = malloc(oldlen)) == NULL) {
131
		log_warn("%s: malloc", __func__);
132
		return (NULL);
133
	}
134
	memcpy(foo, oldcert, oldlen);
135
136
	if ((in = BIO_new_mem_buf(foo, oldlen)) == NULL) {
137
		log_warnx("%s: BIO_new_mem_buf failed", __func__);
138
		goto done;
139
	}
140
141
	if ((cert = PEM_read_bio_X509(in, NULL,
142
	    ssl_password_cb, NULL)) == NULL) {
143
		log_warnx("%s: PEM_read_bio_X509 failed", __func__);
144
		goto done;
145
	}
146
147
	BIO_free(in);
148
	in = NULL;
149
150
	name[0][0] = name[1][0] = '\0';
151
	if (!X509_NAME_oneline(X509_get_subject_name(cert),
152
	    name[0], sizeof(name[0])) ||
153
	    !X509_NAME_oneline(X509_get_issuer_name(cert),
154
	    name[1], sizeof(name[1])))
155
		goto done;
156
157
	if ((cert = X509_dup(cert)) == NULL)
158
		goto done;
159
160
	/* Update certificate key and use our CA as the issuer */
161
	X509_set_pubkey(cert, pkey);
162
	X509_set_issuer_name(cert, X509_get_subject_name(cacert));
163
164
	/* Sign with our CA */
165
	if (!X509_sign(cert, capkey, EVP_sha256())) {
166
		log_warnx("%s: X509_sign failed", __func__);
167
		goto done;
168
	}
169
170
#if DEBUG_CERT
171
	log_debug("%s: subject %s", __func__, name[0]);
172
	log_debug("%s: issuer %s", __func__, name[1]);
173
#if DEBUG > 2
174
	X509_print_fp(stdout, cert);
175
#endif
176
#endif
177
178
	/* write cert as PEM file */
179
	out = BIO_new(BIO_s_mem());
180
	if (out == NULL) {
181
		log_warnx("%s: BIO_new failed", __func__);
182
		goto done;
183
	}
184
	if (!PEM_write_bio_X509(out, cert)) {
185
		log_warnx("%s: PEM_write_bio_X509 failed", __func__);
186
		goto done;
187
	}
188
	BIO_get_mem_ptr(out, &bptr);
189
	if ((newcert = malloc(bptr->length)) == NULL) {
190
		log_warn("%s: malloc", __func__);
191
		goto done;
192
	}
193
	memcpy(newcert, bptr->data, bptr->length);
194
	*newlen = bptr->length;
195
196
done:
197
	free(foo);
198
	if (in)
199
		BIO_free(in);
200
	if (out)
201
		BIO_free(out);
202
	if (cert)
203
		X509_free(cert);
204
	return (newcert);
205
}
206
207
int
208
ssl_load_pkey(char *buf, off_t len, X509 **x509ptr, EVP_PKEY **pkeyptr)
209
{
210
	BIO		*in;
211
	X509		*x509 = NULL;
212
	EVP_PKEY	*pkey = NULL;
213
	RSA		*rsa = NULL;
214
	char		*hash = NULL;
215
216
	if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
217
		log_warnx("%s: BIO_new_mem_buf failed", __func__);
218
		return (0);
219
	}
220
	if ((x509 = PEM_read_bio_X509(in, NULL,
221
	    ssl_password_cb, NULL)) == NULL) {
222
		log_warnx("%s: PEM_read_bio_X509 failed", __func__);
223
		goto fail;
224
	}
225
	if ((pkey = X509_get_pubkey(x509)) == NULL) {
226
		log_warnx("%s: X509_get_pubkey failed", __func__);
227
		goto fail;
228
	}
229
	if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
230
		log_warnx("%s: failed to extract RSA", __func__);
231
		goto fail;
232
	}
233
	if ((hash = malloc(TLS_CERT_HASH_SIZE)) == NULL) {
234
		log_warn("%s: allocate hash failed", __func__);
235
		goto fail;
236
	}
237
	hash_x509(x509, hash, TLS_CERT_HASH_SIZE);
238
	if (RSA_set_ex_data(rsa, 0, hash) != 1) {
239
		log_warnx("%s: failed to set hash as exdata", __func__);
240
		goto fail;
241
	}
242
243
	RSA_free(rsa); /* dereference, will be cleaned up with pkey */
244
	*pkeyptr = pkey;
245
	if (x509ptr != NULL)
246
		*x509ptr = x509;
247
	else
248
		X509_free(x509);
249
	BIO_free(in);
250
251
	return (1);
252
253
 fail:
254
	free(hash);
255
	if (rsa != NULL)
256
		RSA_free(rsa);
257
	if (pkey != NULL)
258
		EVP_PKEY_free(pkey);
259
	if (x509 != NULL)
260
		X509_free(x509);
261
	BIO_free(in);
262
263
	return (0);
264
}
265
266
/*
267
 * This function is a horrible hack but for RSA privsep to work a private key
268
 * with correct size needs to be loaded into the tls config.
269
 */
270
int
271
ssl_ctx_fake_private_key(char *buf, off_t len, const char **fake_key)
272
{
273
	BIO		*in;
274
	EVP_PKEY	*pkey = NULL;
275
	X509		*x509 = NULL;
276
	int		 ret = -1, keylen;
277
278
	if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
279
		log_warnx("%s: BIO_new_mem_buf failed", __func__);
280
		return (0);
281
	}
282
283
	if ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) {
284
		log_warnx("%s: PEM_read_bio_X509 failed", __func__);
285
		goto fail;
286
	}
287
288
	if ((pkey = X509_get_pubkey(x509)) == NULL) {
289
		log_warnx("%s: X509_get_pubkey failed", __func__);
290
		goto fail;
291
	}
292
293
	keylen = EVP_PKEY_size(pkey) * 8;
294
	switch(keylen) {
295
	case 1024:
296
		*fake_key = bogus_1024;
297
		ret = sizeof(bogus_1024);
298
		break;
299
	case 2048:
300
		*fake_key = bogus_2048;
301
		ret = sizeof(bogus_2048);
302
		break;
303
	case 4096:
304
		*fake_key = bogus_4096;
305
		ret = sizeof(bogus_4096);
306
		break;
307
	case 8192:
308
		*fake_key = bogus_8192;
309
		ret = sizeof(bogus_8192);
310
		break;
311
	default:
312
		log_warnx("%s: key size %d not support", __func__, keylen);
313
		ret = -1;
314
		break;
315
	}
316
fail:
317
	BIO_free(in);
318
319
	if (pkey != NULL)
320
		EVP_PKEY_free(pkey);
321
	if (x509 != NULL)
322
		X509_free(x509);
323
324
	return (ret);
325
}