diff options
author | eric <> | 2022-01-25 21:51:24 +0000 |
---|---|---|
committer | eric <> | 2022-01-25 21:51:24 +0000 |
commit | 5bc45eb57d3df492a992eb97f4f9efadef0b060c (patch) | |
tree | f7e1f8bcb82bc7a21b3720f212d7fbf3f1d02872 /src | |
parent | c8578f33457bc1465ca08176ebca6e8aac53fcd3 (diff) | |
download | openbsd-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')
-rw-r--r-- | src/lib/libtls/Makefile | 3 | ||||
-rw-r--r-- | src/lib/libtls/Symbols.list | 6 | ||||
-rw-r--r-- | src/lib/libtls/tls.c | 20 | ||||
-rw-r--r-- | src/lib/libtls/tls.h | 18 | ||||
-rw-r--r-- | src/lib/libtls/tls_config.c | 13 | ||||
-rw-r--r-- | src/lib/libtls/tls_internal.h | 7 | ||||
-rw-r--r-- | src/lib/libtls/tls_signer.c | 376 |
7 files changed, 438 insertions, 5 deletions
diff --git a/src/lib/libtls/Makefile b/src/lib/libtls/Makefile index 23a6ed1f2a..78ff99b585 100644 --- a/src/lib/libtls/Makefile +++ b/src/lib/libtls/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | # $OpenBSD: Makefile,v 1.36 2020/06/09 16:53:53 deraadt Exp $ | 1 | # $OpenBSD: Makefile,v 1.37 2022/01/25 21:51:24 eric Exp $ |
2 | 2 | ||
3 | .include <bsd.own.mk> | 3 | .include <bsd.own.mk> |
4 | .ifndef NOMAN | 4 | .ifndef NOMAN |
@@ -35,6 +35,7 @@ SRCS= tls.c \ | |||
35 | tls_keypair.c \ | 35 | tls_keypair.c \ |
36 | tls_peer.c \ | 36 | tls_peer.c \ |
37 | tls_server.c \ | 37 | tls_server.c \ |
38 | tls_signer.c \ | ||
38 | tls_util.c \ | 39 | tls_util.c \ |
39 | tls_ocsp.c \ | 40 | tls_ocsp.c \ |
40 | tls_verify.c | 41 | tls_verify.c |
diff --git a/src/lib/libtls/Symbols.list b/src/lib/libtls/Symbols.list index 42c039d294..d00e5e0ce6 100644 --- a/src/lib/libtls/Symbols.list +++ b/src/lib/libtls/Symbols.list | |||
@@ -43,6 +43,7 @@ tls_config_set_protocols | |||
43 | tls_config_set_session_id | 43 | tls_config_set_session_id |
44 | tls_config_set_session_lifetime | 44 | tls_config_set_session_lifetime |
45 | tls_config_set_session_fd | 45 | tls_config_set_session_fd |
46 | tls_config_set_sign_cb | ||
46 | tls_config_set_verify_depth | 47 | tls_config_set_verify_depth |
47 | tls_config_skip_private_key_check | 48 | tls_config_skip_private_key_check |
48 | tls_config_use_fake_private_key | 49 | tls_config_use_fake_private_key |
@@ -87,5 +88,10 @@ tls_peer_ocsp_url | |||
87 | tls_read | 88 | tls_read |
88 | tls_reset | 89 | tls_reset |
89 | tls_server | 90 | tls_server |
91 | tls_signer_add_keypair_file | ||
92 | tls_signer_add_keypair_mem | ||
93 | tls_signer_free | ||
94 | tls_signer_new | ||
95 | tls_signer_sign | ||
90 | tls_unload_file | 96 | tls_unload_file |
91 | tls_write | 97 | tls_write |
diff --git a/src/lib/libtls/tls.c b/src/lib/libtls/tls.c index 608f0a3acd..fd525aa428 100644 --- a/src/lib/libtls/tls.c +++ b/src/lib/libtls/tls.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: tls.c,v 1.92 2021/10/21 14:31:21 tb Exp $ */ | 1 | /* $OpenBSD: tls.c,v 1.93 2022/01/25 21:51:24 eric Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> |
4 | * | 4 | * |
@@ -387,6 +387,8 @@ tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pke | |||
387 | static int | 387 | static int |
388 | tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *pkey) | 388 | tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *pkey) |
389 | { | 389 | { |
390 | RSA_METHOD *rsa_method; | ||
391 | ECDSA_METHOD *ecdsa_method; | ||
390 | RSA *rsa = NULL; | 392 | RSA *rsa = NULL; |
391 | EC_KEY *eckey = NULL; | 393 | EC_KEY *eckey = NULL; |
392 | int ret = -1; | 394 | int ret = -1; |
@@ -407,6 +409,14 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p | |||
407 | tls_set_errorx(ctx, "RSA key setup failure"); | 409 | tls_set_errorx(ctx, "RSA key setup failure"); |
408 | goto err; | 410 | goto err; |
409 | } | 411 | } |
412 | if (ctx->config->sign_cb == NULL) | ||
413 | break; | ||
414 | if ((rsa_method = tls_signer_rsa_method()) == NULL || | ||
415 | RSA_set_ex_data(rsa, 1, ctx->config) == 0 || | ||
416 | RSA_set_method(rsa, rsa_method) == 0) { | ||
417 | tls_set_errorx(ctx, "failed to setup RSA key"); | ||
418 | goto err; | ||
419 | } | ||
410 | break; | 420 | break; |
411 | case EVP_PKEY_EC: | 421 | case EVP_PKEY_EC: |
412 | if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL || | 422 | if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL || |
@@ -414,6 +424,14 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p | |||
414 | tls_set_errorx(ctx, "EC key setup failure"); | 424 | tls_set_errorx(ctx, "EC key setup failure"); |
415 | goto err; | 425 | goto err; |
416 | } | 426 | } |
427 | if (ctx->config->sign_cb == NULL) | ||
428 | break; | ||
429 | if ((ecdsa_method = tls_signer_ecdsa_method()) == NULL || | ||
430 | ECDSA_set_ex_data(eckey, 1, ctx->config) == 0 || | ||
431 | ECDSA_set_method(eckey, ecdsa_method) == 0) { | ||
432 | tls_set_errorx(ctx, "failed to setup EC key"); | ||
433 | goto err; | ||
434 | } | ||
417 | break; | 435 | break; |
418 | default: | 436 | default: |
419 | tls_set_errorx(ctx, "incorrect key type"); | 437 | tls_set_errorx(ctx, "incorrect key type"); |
diff --git a/src/lib/libtls/tls.h b/src/lib/libtls/tls.h index 20f55dcabd..22f04f4023 100644 --- a/src/lib/libtls/tls.h +++ b/src/lib/libtls/tls.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: tls.h,v 1.58 2020/01/22 06:44:02 beck Exp $ */ | 1 | /* $OpenBSD: tls.h,v 1.59 2022/01/25 21:51:24 eric Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> |
4 | * | 4 | * |
@@ -79,6 +79,9 @@ typedef ssize_t (*tls_read_cb)(struct tls *_ctx, void *_buf, size_t _buflen, | |||
79 | void *_cb_arg); | 79 | void *_cb_arg); |
80 | typedef ssize_t (*tls_write_cb)(struct tls *_ctx, const void *_buf, | 80 | typedef ssize_t (*tls_write_cb)(struct tls *_ctx, const void *_buf, |
81 | size_t _buflen, void *_cb_arg); | 81 | size_t _buflen, void *_cb_arg); |
82 | typedef int (*tls_sign_cb)(void *_cb_arg, const char *_hash, | ||
83 | const uint8_t *_dgst, size_t _dgstlen, uint8_t *_psig, size_t *_psiglen, | ||
84 | int _padding); | ||
82 | 85 | ||
83 | int tls_init(void); | 86 | int tls_init(void); |
84 | 87 | ||
@@ -135,6 +138,8 @@ int tls_config_set_ocsp_staple_file(struct tls_config *_config, | |||
135 | int tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols); | 138 | int tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols); |
136 | int tls_config_set_session_fd(struct tls_config *_config, int _session_fd); | 139 | int tls_config_set_session_fd(struct tls_config *_config, int _session_fd); |
137 | int tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth); | 140 | int tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth); |
141 | int tls_config_set_sign_cb(struct tls_config *_config, tls_sign_cb _cb, | ||
142 | void *_cb_arg); | ||
138 | 143 | ||
139 | void tls_config_prefer_ciphers_client(struct tls_config *_config); | 144 | void tls_config_prefer_ciphers_client(struct tls_config *_config); |
140 | void tls_config_prefer_ciphers_server(struct tls_config *_config); | 145 | void tls_config_prefer_ciphers_server(struct tls_config *_config); |
@@ -212,6 +217,17 @@ time_t tls_peer_ocsp_revocation_time(struct tls *_ctx); | |||
212 | time_t tls_peer_ocsp_this_update(struct tls *_ctx); | 217 | time_t tls_peer_ocsp_this_update(struct tls *_ctx); |
213 | const char *tls_peer_ocsp_url(struct tls *_ctx); | 218 | const char *tls_peer_ocsp_url(struct tls *_ctx); |
214 | 219 | ||
220 | struct tls_signer* tls_signer_new(void); | ||
221 | void tls_signer_free(struct tls_signer * _signer); | ||
222 | const char *tls_signer_error(struct tls_signer * _signer); | ||
223 | int tls_signer_add_keypair_file(struct tls_signer *_signer, | ||
224 | const char *_cert_file, const char *_key_file); | ||
225 | int tls_signer_add_keypair_mem(struct tls_signer *_signer, const uint8_t *_cert, | ||
226 | size_t _cert_len, const uint8_t *_key, size_t _key_len); | ||
227 | int tls_signer_sign(struct tls_signer *_signer, const char *_hash, | ||
228 | const uint8_t *_dgst, size_t _dgstlen, uint8_t **_psig, size_t *_psiglen, | ||
229 | int _padding); | ||
230 | |||
215 | #ifdef __cplusplus | 231 | #ifdef __cplusplus |
216 | } | 232 | } |
217 | #endif | 233 | #endif |
diff --git a/src/lib/libtls/tls_config.c b/src/lib/libtls/tls_config.c index 4ca497a032..15e218b4e0 100644 --- a/src/lib/libtls/tls_config.c +++ b/src/lib/libtls/tls_config.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: tls_config.c,v 1.64 2021/10/21 08:33:07 tb Exp $ */ | 1 | /* $OpenBSD: tls_config.c,v 1.65 2022/01/25 21:51:24 eric Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> |
4 | * | 4 | * |
@@ -738,6 +738,17 @@ tls_config_set_session_fd(struct tls_config *config, int session_fd) | |||
738 | } | 738 | } |
739 | 739 | ||
740 | int | 740 | int |
741 | tls_config_set_sign_cb(struct tls_config *config, tls_sign_cb cb, void *cb_arg) | ||
742 | { | ||
743 | config->use_fake_private_key = 1; | ||
744 | config->skip_private_key_check = 1; | ||
745 | config->sign_cb = cb; | ||
746 | config->sign_cb_arg = cb_arg; | ||
747 | |||
748 | return (0); | ||
749 | } | ||
750 | |||
751 | int | ||
741 | tls_config_set_verify_depth(struct tls_config *config, int verify_depth) | 752 | tls_config_set_verify_depth(struct tls_config *config, int verify_depth) |
742 | { | 753 | { |
743 | config->verify_depth = verify_depth; | 754 | config->verify_depth = verify_depth; |
diff --git a/src/lib/libtls/tls_internal.h b/src/lib/libtls/tls_internal.h index 5487b123ec..bc5044518b 100644 --- a/src/lib/libtls/tls_internal.h +++ b/src/lib/libtls/tls_internal.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: tls_internal.h,v 1.78 2021/01/21 19:09:10 eric Exp $ */ | 1 | /* $OpenBSD: tls_internal.h,v 1.79 2022/01/25 21:51:24 eric Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> | 3 | * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> |
4 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> | 4 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> |
@@ -112,6 +112,8 @@ struct tls_config { | |||
112 | int verify_time; | 112 | int verify_time; |
113 | int skip_private_key_check; | 113 | int skip_private_key_check; |
114 | int use_fake_private_key; | 114 | int use_fake_private_key; |
115 | tls_sign_cb sign_cb; | ||
116 | void *sign_cb_arg; | ||
115 | }; | 117 | }; |
116 | 118 | ||
117 | struct tls_conninfo { | 119 | struct tls_conninfo { |
@@ -291,6 +293,9 @@ int tls_cert_pubkey_hash(X509 *_cert, char **_hash); | |||
291 | 293 | ||
292 | int tls_password_cb(char *_buf, int _size, int _rwflag, void *_u); | 294 | int tls_password_cb(char *_buf, int _size, int _rwflag, void *_u); |
293 | 295 | ||
296 | RSA_METHOD *tls_signer_rsa_method(void); | ||
297 | ECDSA_METHOD *tls_signer_ecdsa_method(void); | ||
298 | |||
294 | __END_HIDDEN_DECLS | 299 | __END_HIDDEN_DECLS |
295 | 300 | ||
296 | /* XXX this function is not fully hidden so relayd can use it */ | 301 | /* XXX this function is not fully hidden so relayd can use it */ |
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 | |||
23 | struct tls_signer_key { | ||
24 | char *hash; | ||
25 | RSA *rsa; | ||
26 | EC_KEY *ecdsa; | ||
27 | struct tls_signer_key *next; | ||
28 | }; | ||
29 | |||
30 | struct tls_signer { | ||
31 | struct tls_error error; | ||
32 | struct tls_signer_key *keys; | ||
33 | }; | ||
34 | |||
35 | static pthread_mutex_t signer_method_lock = PTHREAD_MUTEX_INITIALIZER; | ||
36 | |||
37 | struct tls_signer * | ||
38 | tls_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 | |||
48 | void | ||
49 | tls_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 | |||
70 | const char * | ||
71 | tls_signer_error(struct tls_signer *signer) | ||
72 | { | ||
73 | return (signer->error.msg); | ||
74 | } | ||
75 | |||
76 | int | ||
77 | tls_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 | |||
152 | int | ||
153 | tls_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 | |||
177 | static int | ||
178 | tls_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 | |||
214 | static int | ||
215 | tls_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 | |||
247 | int | ||
248 | tls_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 | |||
274 | static int | ||
275 | tls_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 | |||
298 | RSA_METHOD * | ||
299 | tls_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 | |||
320 | static ECDSA_SIG * | ||
321 | tls_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 | |||
351 | ECDSA_METHOD * | ||
352 | tls_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 | } | ||