summaryrefslogtreecommitdiff
path: root/src/lib/libtls/tls_signer.c
diff options
context:
space:
mode:
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}