summaryrefslogtreecommitdiff
path: root/src/lib/libtls/tls_signer.c
diff options
context:
space:
mode:
authoreric <>2022-01-25 21:51:24 +0000
committereric <>2022-01-25 21:51:24 +0000
commit5bc45eb57d3df492a992eb97f4f9efadef0b060c (patch)
treef7e1f8bcb82bc7a21b3720f212d7fbf3f1d02872 /src/lib/libtls/tls_signer.c
parentc8578f33457bc1465ca08176ebca6e8aac53fcd3 (diff)
downloadopenbsd-5bc45eb57d3df492a992eb97f4f9efadef0b060c.tar.gz
openbsd-5bc45eb57d3df492a992eb97f4f9efadef0b060c.tar.bz2
openbsd-5bc45eb57d3df492a992eb97f4f9efadef0b060c.zip
Introduce a signer interface intented to make TLS privsep simpler
to implement. Add a tls_config_set_sign_cb() function that allows to register a callback for the signing operation on a tls_config. When used, the context installs fake pivate keys internally, and the callback receives the hash of the public key. Add a tls_signer_*() set of functions to manage tls_signer objects. A tls_signer is an opaque structure on which keys are added. It is used to compute signatures with private keys identified by their associated public key hash. Discussed with and ok jsing@ tb@
Diffstat (limited to 'src/lib/libtls/tls_signer.c')
-rw-r--r--src/lib/libtls/tls_signer.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/src/lib/libtls/tls_signer.c b/src/lib/libtls/tls_signer.c
new file mode 100644
index 0000000000..690cb51615
--- /dev/null
+++ b/src/lib/libtls/tls_signer.c
@@ -0,0 +1,376 @@
1/* $OpenBSD: tls_signer.c,v 1.1 2022/01/25 21:51:24 eric Exp $ */
2/*
3 * Copyright (c) 2021 Eric Faurot <eric@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <openssl/err.h>
19
20#include "tls.h"
21#include "tls_internal.h"
22
23struct tls_signer_key {
24 char *hash;
25 RSA *rsa;
26 EC_KEY *ecdsa;
27 struct tls_signer_key *next;
28};
29
30struct tls_signer {
31 struct tls_error error;
32 struct tls_signer_key *keys;
33};
34
35static pthread_mutex_t signer_method_lock = PTHREAD_MUTEX_INITIALIZER;
36
37struct tls_signer *
38tls_signer_new(void)
39{
40 struct tls_signer *signer;
41
42 if ((signer = calloc(1, sizeof(*signer))) == NULL)
43 return (NULL);
44
45 return (signer);
46}
47
48void
49tls_signer_free(struct tls_signer *signer)
50{
51 struct tls_signer_key *skey;
52
53 if (signer == NULL)
54 return;
55
56 tls_error_clear(&signer->error);
57
58 while (signer->keys) {
59 skey = signer->keys;
60 signer->keys = skey->next;
61 RSA_free(skey->rsa);
62 EC_KEY_free(skey->ecdsa);
63 free(skey->hash);
64 free(skey);
65 }
66
67 free(signer);
68}
69
70const char *
71tls_signer_error(struct tls_signer *signer)
72{
73 return (signer->error.msg);
74}
75
76int
77tls_signer_add_keypair_mem(struct tls_signer *signer, const uint8_t *cert,
78 size_t cert_len, const uint8_t *key, size_t key_len)
79{
80 struct tls_signer_key *skey = NULL;
81 char *errstr = "unknown";
82 int ssl_err;
83 EVP_PKEY *pkey = NULL;
84 X509 *x509 = NULL;
85 BIO *bio = NULL;
86 char *hash = NULL;
87
88 /* Compute certificate hash */
89 if ((bio = BIO_new_mem_buf(cert, cert_len)) == NULL) {
90 tls_error_setx(&signer->error,
91 "failed to create certificate bio");
92 goto err;
93 }
94 if ((x509 = PEM_read_bio_X509(bio, NULL, tls_password_cb,
95 NULL)) == NULL) {
96 if ((ssl_err = ERR_peek_error()) != 0)
97 errstr = ERR_error_string(ssl_err, NULL);
98 tls_error_setx(&signer->error, "failed to load certificate: %s",
99 errstr);
100 goto err;
101 }
102 if (tls_cert_pubkey_hash(x509, &hash) == -1) {
103 tls_error_setx(&signer->error,
104 "failed to get certificate hash");
105 goto err;
106 }
107
108 X509_free(x509);
109 x509 = NULL;
110 BIO_free(bio);
111 bio = NULL;
112
113 /* Read private key */
114 if ((bio = BIO_new_mem_buf(key, key_len)) == NULL) {
115 tls_error_setx(&signer->error, "failed to create key bio");
116 goto err;
117 }
118 if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
119 NULL)) == NULL) {
120 tls_error_setx(&signer->error, "failed to read private key");
121 goto err;
122 }
123
124 if ((skey = calloc(1, sizeof(*skey))) == NULL) {
125 tls_error_set(&signer->error, "failed to create key entry");
126 goto err;
127 }
128 skey->hash = hash;
129 if ((skey->rsa = EVP_PKEY_get1_RSA(pkey)) == NULL &&
130 (skey->ecdsa = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
131 tls_error_setx(&signer->error, "unknown key type");
132 goto err;
133 }
134
135 skey->next = signer->keys;
136 signer->keys = skey;
137 EVP_PKEY_free(pkey);
138 BIO_free(bio);
139
140 return (0);
141
142 err:
143 EVP_PKEY_free(pkey);
144 X509_free(x509);
145 BIO_free(bio);
146 free(hash);
147 free(skey);
148
149 return (-1);
150}
151
152int
153tls_signer_add_keypair_file(struct tls_signer *signer, const char *cert_file,
154 const char *key_file)
155{
156 char *cert = NULL, *key = NULL;
157 size_t cert_len, key_len;
158 int rv = -1;
159
160 if (tls_config_load_file(&signer->error, "certificate", cert_file,
161 &cert, &cert_len) == -1)
162 goto err;
163
164 if (tls_config_load_file(&signer->error, "key", key_file, &key,
165 &key_len) == -1)
166 goto err;
167
168 rv = tls_signer_add_keypair_mem(signer, cert, cert_len, key, key_len);
169
170 err:
171 free(cert);
172 free(key);
173
174 return (rv);
175}
176
177static int
178tls_sign_rsa(struct tls_signer *signer, struct tls_signer_key *skey,
179 const uint8_t *dgst, size_t dgstlen, uint8_t **psig, size_t *psiglen,
180 int padding)
181{
182
183 char *buf;
184 int siglen, r;
185
186 *psig = NULL;
187 *psiglen = 0;
188
189 siglen = RSA_size(skey->rsa);
190 if (siglen <= 0) {
191 tls_error_setx(&signer->error, "incorrect RSA_size: %d",
192 siglen);
193 return (-1);
194 }
195
196 if ((buf = malloc(siglen)) == NULL) {
197 tls_error_set(&signer->error, "RSA sign");
198 return (-1);
199 }
200
201 r = RSA_private_encrypt((int)dgstlen, dgst, buf, skey->rsa, padding);
202 if (r == -1) {
203 tls_error_setx(&signer->error, "RSA_private_encrypt failed");
204 free(buf);
205 return (-1);
206 }
207
208 *psig = buf;
209 *psiglen = (size_t)r;
210
211 return (0);
212}
213
214static int
215tls_sign_ecdsa(struct tls_signer *signer, struct tls_signer_key *skey,
216 const uint8_t *dgst, size_t dgstlen, uint8_t **psig, size_t *psiglen)
217{
218 unsigned char *sig;
219 unsigned int siglen;
220
221 *psig = NULL;
222 *psiglen = 0;
223
224 siglen = ECDSA_size(skey->ecdsa);
225 if (siglen == 0) {
226 tls_error_setx(&signer->error, "incorrect ECDSA_size: %u",
227 siglen);
228 return (-1);
229 }
230 if ((sig = malloc(siglen)) == NULL) {
231 tls_error_set(&signer->error, "ECDSA sign");
232 return (-1);
233 }
234
235 if (!ECDSA_sign(0, dgst, dgstlen, sig, &siglen, skey->ecdsa)) {
236 tls_error_setx(&signer->error, "ECDSA_sign failed");
237 free(sig);
238 return (-1);
239 }
240
241 *psig = sig;
242 *psiglen = siglen;
243
244 return (0);
245}
246
247int
248tls_signer_sign(struct tls_signer *signer, const char *hash,
249 const uint8_t *dgst, size_t dgstlen, uint8_t **psig, size_t *psiglen,
250 int padding)
251{
252 struct tls_signer_key *skey;
253
254 for (skey = signer->keys; skey; skey = skey->next)
255 if (!strcmp(hash, skey->hash))
256 break;
257
258 if (skey == NULL) {
259 tls_error_setx(&signer->error, "key not found");
260 return (-1);
261 }
262
263 if (skey->rsa != NULL)
264 return tls_sign_rsa(signer, skey, dgst, dgstlen, psig, psiglen,
265 padding);
266
267 if (skey->ecdsa != NULL)
268 return tls_sign_ecdsa(signer, skey, dgst, dgstlen, psig, psiglen);
269
270 tls_error_setx(&signer->error, "unknown key type");
271 return (-1);
272}
273
274static int
275tls_rsa_priv_enc(int srclen, const unsigned char *src, unsigned char *to,
276 RSA *rsa, int padding)
277{
278 struct tls_config *config;
279 const char *hash;
280 size_t tolen;
281
282 hash = RSA_get_ex_data(rsa, 0);
283 config = RSA_get_ex_data(rsa, 1);
284
285 if (hash == NULL || config == NULL)
286 return (-1);
287
288 if (config->sign_cb(config->sign_cb_arg, hash, (const uint8_t *)src,
289 srclen, (uint8_t *)to, &tolen, padding) == -1)
290 return (-1);
291
292 if (tolen > INT_MAX)
293 return (-1);
294
295 return ((int)tolen);
296}
297
298RSA_METHOD *
299tls_signer_rsa_method(void)
300{
301 static RSA_METHOD *rsa_method = NULL;
302
303 pthread_mutex_lock(&signer_method_lock);
304
305 if (rsa_method != NULL)
306 goto out;
307
308 rsa_method = RSA_meth_new("libtls RSA method", 0);
309 if (rsa_method == NULL)
310 goto out;
311
312 RSA_meth_set_priv_enc(rsa_method, tls_rsa_priv_enc);
313
314 out:
315 pthread_mutex_unlock(&signer_method_lock);
316
317 return (rsa_method);
318}
319
320static ECDSA_SIG *
321tls_ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
322 const BIGNUM *rp, EC_KEY *eckey)
323{
324 struct tls_config *config;
325 ECDSA_SIG *sig = NULL;
326 const unsigned char *tsigbuf;
327 const char *hash;
328 char *sigbuf;
329 size_t siglen;
330
331 hash = ECDSA_get_ex_data(eckey, 0);
332 config = ECDSA_get_ex_data(eckey, 1);
333
334 if (hash == NULL || config == NULL)
335 return (NULL);
336
337 siglen = ECDSA_size(eckey);
338 if ((sigbuf = malloc(siglen)) == NULL)
339 return (NULL);
340
341 if (config->sign_cb(config->sign_cb_arg, hash, dgst, dgst_len, sigbuf,
342 &siglen, 0) != -1) {
343 tsigbuf = sigbuf;
344 sig = d2i_ECDSA_SIG(NULL, &tsigbuf, siglen);
345 }
346 free(sigbuf);
347
348 return (sig);
349}
350
351ECDSA_METHOD *
352tls_signer_ecdsa_method(void)
353{
354 static ECDSA_METHOD *ecdsa_method = NULL;
355
356 pthread_mutex_lock(&signer_method_lock);
357
358 if (ecdsa_method != NULL)
359 goto out;
360
361 ecdsa_method = calloc(1, sizeof(*ecdsa_method));
362 if (ecdsa_method == NULL)
363 goto out;
364
365 ecdsa_method->ecdsa_do_sign = tls_ecdsa_do_sign;
366 ecdsa_method->name = strdup("libtls ECDSA method");
367 if (ecdsa_method->name == NULL) {
368 free(ecdsa_method);
369 ecdsa_method = NULL;
370 }
371
372 out:
373 pthread_mutex_unlock(&signer_method_lock);
374
375 return (ecdsa_method);
376}