diff options
author | jsing <> | 2016-08-22 14:51:37 +0000 |
---|---|---|
committer | jsing <> | 2016-08-22 14:51:37 +0000 |
commit | 74ebdd842595c2d6c66a0aa102dc5c4b98412c8d (patch) | |
tree | e04823f4dbd54041cadc277b3cfa2714bd318c36 /src/lib | |
parent | 60132b75420595a9684003b199d3299fe13ec457 (diff) | |
download | openbsd-74ebdd842595c2d6c66a0aa102dc5c4b98412c8d.tar.gz openbsd-74ebdd842595c2d6c66a0aa102dc5c4b98412c8d.tar.bz2 openbsd-74ebdd842595c2d6c66a0aa102dc5c4b98412c8d.zip |
Create contexts for server side SNI - these include the additional SSL_CTX
that is required for certificate switching with libssl and the certificate
itself so that we can match against the subject and SANs. Hook up the
servername callback and switch to the appropriate SSL_CTX if we find a
matching certificate.
ok beck@
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libtls/tls.c | 28 | ||||
-rw-r--r-- | src/lib/libtls/tls_internal.h | 15 | ||||
-rw-r--r-- | src/lib/libtls/tls_server.c | 134 |
3 files changed, 174 insertions, 3 deletions
diff --git a/src/lib/libtls/tls.c b/src/lib/libtls/tls.c index bf0e1f769f..df610fe238 100644 --- a/src/lib/libtls/tls.c +++ b/src/lib/libtls/tls.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: tls.c,v 1.46 2016/08/15 14:04:23 jsing Exp $ */ | 1 | /* $OpenBSD: tls.c,v 1.47 2016/08/22 14:51:37 jsing Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> |
4 | * | 4 | * |
@@ -177,6 +177,24 @@ tls_set_errorx(struct tls *ctx, const char *fmt, ...) | |||
177 | return (rv); | 177 | return (rv); |
178 | } | 178 | } |
179 | 179 | ||
180 | struct tls_sni_ctx * | ||
181 | tls_sni_ctx_new(void) | ||
182 | { | ||
183 | return (calloc(1, sizeof(struct tls_sni_ctx))); | ||
184 | } | ||
185 | |||
186 | void | ||
187 | tls_sni_ctx_free(struct tls_sni_ctx *sni_ctx) | ||
188 | { | ||
189 | if (sni_ctx == NULL) | ||
190 | return; | ||
191 | |||
192 | SSL_CTX_free(sni_ctx->ssl_ctx); | ||
193 | X509_free(sni_ctx->ssl_cert); | ||
194 | |||
195 | free(sni_ctx); | ||
196 | } | ||
197 | |||
180 | struct tls * | 198 | struct tls * |
181 | tls_new(void) | 199 | tls_new(void) |
182 | { | 200 | { |
@@ -376,6 +394,8 @@ tls_free(struct tls *ctx) | |||
376 | void | 394 | void |
377 | tls_reset(struct tls *ctx) | 395 | tls_reset(struct tls *ctx) |
378 | { | 396 | { |
397 | struct tls_sni_ctx *sni, *nsni; | ||
398 | |||
379 | SSL_CTX_free(ctx->ssl_ctx); | 399 | SSL_CTX_free(ctx->ssl_ctx); |
380 | SSL_free(ctx->ssl_conn); | 400 | SSL_free(ctx->ssl_conn); |
381 | X509_free(ctx->ssl_peer_cert); | 401 | X509_free(ctx->ssl_peer_cert); |
@@ -397,6 +417,12 @@ tls_reset(struct tls *ctx) | |||
397 | tls_free_conninfo(ctx->conninfo); | 417 | tls_free_conninfo(ctx->conninfo); |
398 | free(ctx->conninfo); | 418 | free(ctx->conninfo); |
399 | ctx->conninfo = NULL; | 419 | ctx->conninfo = NULL; |
420 | |||
421 | for (sni = ctx->sni_ctx; sni != NULL; sni = nsni) { | ||
422 | nsni = sni->next; | ||
423 | tls_sni_ctx_free(sni); | ||
424 | } | ||
425 | ctx->sni_ctx = NULL; | ||
400 | } | 426 | } |
401 | 427 | ||
402 | int | 428 | int |
diff --git a/src/lib/libtls/tls_internal.h b/src/lib/libtls/tls_internal.h index bbd231e00e..428e29c857 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.39 2016/08/15 15:44:58 jsing Exp $ */ | 1 | /* $OpenBSD: tls_internal.h,v 1.40 2016/08/22 14:51:37 jsing 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> |
@@ -91,6 +91,13 @@ struct tls_conninfo { | |||
91 | #define TLS_EOF_NO_CLOSE_NOTIFY (1 << 0) | 91 | #define TLS_EOF_NO_CLOSE_NOTIFY (1 << 0) |
92 | #define TLS_HANDSHAKE_COMPLETE (1 << 1) | 92 | #define TLS_HANDSHAKE_COMPLETE (1 << 1) |
93 | 93 | ||
94 | struct tls_sni_ctx { | ||
95 | struct tls_sni_ctx *next; | ||
96 | |||
97 | SSL_CTX *ssl_ctx; | ||
98 | X509 *ssl_cert; | ||
99 | }; | ||
100 | |||
94 | struct tls { | 101 | struct tls { |
95 | struct tls_config *config; | 102 | struct tls_config *config; |
96 | struct tls_error error; | 103 | struct tls_error error; |
@@ -103,11 +110,17 @@ struct tls { | |||
103 | 110 | ||
104 | SSL *ssl_conn; | 111 | SSL *ssl_conn; |
105 | SSL_CTX *ssl_ctx; | 112 | SSL_CTX *ssl_ctx; |
113 | |||
114 | struct tls_sni_ctx *sni_ctx; | ||
115 | |||
106 | X509 *ssl_peer_cert; | 116 | X509 *ssl_peer_cert; |
107 | 117 | ||
108 | struct tls_conninfo *conninfo; | 118 | struct tls_conninfo *conninfo; |
109 | }; | 119 | }; |
110 | 120 | ||
121 | struct tls_sni_ctx *tls_sni_ctx_new(void); | ||
122 | void tls_sni_ctx_free(struct tls_sni_ctx *sni_ctx); | ||
123 | |||
111 | struct tls *tls_new(void); | 124 | struct tls *tls_new(void); |
112 | struct tls *tls_server_conn(struct tls *ctx); | 125 | struct tls *tls_server_conn(struct tls *ctx); |
113 | 126 | ||
diff --git a/src/lib/libtls/tls_server.c b/src/lib/libtls/tls_server.c index 40096ae99f..044678c705 100644 --- a/src/lib/libtls/tls_server.c +++ b/src/lib/libtls/tls_server.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: tls_server.c,v 1.24 2016/08/18 15:52:03 jsing Exp $ */ | 1 | /* $OpenBSD: tls_server.c,v 1.25 2016/08/22 14:51:37 jsing Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> |
4 | * | 4 | * |
@@ -15,6 +15,10 @@ | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <sys/socket.h> | ||
19 | |||
20 | #include <arpa/inet.h> | ||
21 | |||
18 | #include <openssl/ec.h> | 22 | #include <openssl/ec.h> |
19 | #include <openssl/err.h> | 23 | #include <openssl/err.h> |
20 | #include <openssl/ssl.h> | 24 | #include <openssl/ssl.h> |
@@ -63,6 +67,92 @@ tls_server_alpn_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, | |||
63 | } | 67 | } |
64 | 68 | ||
65 | static int | 69 | static int |
70 | tls_servername_cb(SSL *ssl, int *al, void *arg) | ||
71 | { | ||
72 | struct tls *ctx = (struct tls *)arg; | ||
73 | struct tls_sni_ctx *sni_ctx; | ||
74 | union tls_addr addrbuf; | ||
75 | struct tls *conn_ctx; | ||
76 | const char *name; | ||
77 | |||
78 | if ((conn_ctx = SSL_get_app_data(ssl)) == NULL) | ||
79 | goto err; | ||
80 | |||
81 | if ((name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)) == NULL) { | ||
82 | /* | ||
83 | * The servername callback gets called even when there is no | ||
84 | * TLS servername extension provided by the client. Sigh! | ||
85 | */ | ||
86 | return (SSL_TLSEXT_ERR_NOACK); | ||
87 | } | ||
88 | |||
89 | /* Per RFC 6066 section 3: ensure that name is not an IP literal. */ | ||
90 | if (inet_pton(AF_INET, name, &addrbuf) == 1 || | ||
91 | inet_pton(AF_INET6, name, &addrbuf) == 1) | ||
92 | goto err; | ||
93 | |||
94 | free((char *)conn_ctx->servername); | ||
95 | if ((conn_ctx->servername = strdup(name)) == NULL) | ||
96 | goto err; | ||
97 | |||
98 | /* Find appropriate SSL context for requested servername. */ | ||
99 | for (sni_ctx = ctx->sni_ctx; sni_ctx != NULL; sni_ctx = sni_ctx->next) { | ||
100 | if (tls_check_name(ctx, sni_ctx->ssl_cert, name) == 0) { | ||
101 | SSL_set_SSL_CTX(conn_ctx->ssl_conn, sni_ctx->ssl_ctx); | ||
102 | return (SSL_TLSEXT_ERR_OK); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | /* No match, use the existing context/certificate. */ | ||
107 | return (SSL_TLSEXT_ERR_OK); | ||
108 | |||
109 | err: | ||
110 | /* | ||
111 | * There is no way to tell libssl that an internal failure occurred. | ||
112 | * The only option we have is to return a fatal alert. | ||
113 | */ | ||
114 | *al = TLS1_AD_INTERNAL_ERROR; | ||
115 | return (SSL_TLSEXT_ERR_ALERT_FATAL); | ||
116 | } | ||
117 | |||
118 | static int | ||
119 | tls_keypair_load_cert(struct tls_keypair *keypair, struct tls_error *error, | ||
120 | X509 **cert) | ||
121 | { | ||
122 | char *errstr = "unknown"; | ||
123 | BIO *cert_bio = NULL; | ||
124 | int ssl_err; | ||
125 | |||
126 | X509_free(*cert); | ||
127 | *cert = NULL; | ||
128 | |||
129 | if (keypair->cert_mem == NULL) { | ||
130 | tls_error_set(error, "keypair has no certificate"); | ||
131 | goto err; | ||
132 | } | ||
133 | if ((cert_bio = BIO_new_mem_buf(keypair->cert_mem, | ||
134 | keypair->cert_len)) == NULL) { | ||
135 | tls_error_set(error, "failed to create certificate bio"); | ||
136 | goto err; | ||
137 | } | ||
138 | if ((*cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL)) == NULL) { | ||
139 | if ((ssl_err = ERR_peek_error()) != 0) | ||
140 | errstr = ERR_error_string(ssl_err, NULL); | ||
141 | tls_error_set(error, "failed to load certificate: %s", errstr); | ||
142 | goto err; | ||
143 | } | ||
144 | |||
145 | BIO_free(cert_bio); | ||
146 | |||
147 | return (0); | ||
148 | |||
149 | err: | ||
150 | BIO_free(cert_bio); | ||
151 | |||
152 | return (-1); | ||
153 | } | ||
154 | |||
155 | static int | ||
66 | tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx, | 156 | tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx, |
67 | struct tls_keypair *keypair) | 157 | struct tls_keypair *keypair) |
68 | { | 158 | { |
@@ -76,6 +166,16 @@ tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx, | |||
76 | goto err; | 166 | goto err; |
77 | } | 167 | } |
78 | 168 | ||
169 | if (SSL_CTX_set_tlsext_servername_callback(*ssl_ctx, | ||
170 | tls_servername_cb) != 1) { | ||
171 | tls_set_error(ctx, "failed to set servername callback"); | ||
172 | goto err; | ||
173 | } | ||
174 | if (SSL_CTX_set_tlsext_servername_arg(*ssl_ctx, ctx) != 1) { | ||
175 | tls_set_error(ctx, "failed to set servername callback arg"); | ||
176 | goto err; | ||
177 | } | ||
178 | |||
79 | if (tls_configure_ssl(ctx, *ssl_ctx) != 0) | 179 | if (tls_configure_ssl(ctx, *ssl_ctx) != 0) |
80 | goto err; | 180 | goto err; |
81 | if (tls_configure_ssl_keypair(ctx, *ssl_ctx, keypair, 1) != 0) | 181 | if (tls_configure_ssl_keypair(ctx, *ssl_ctx, keypair, 1) != 0) |
@@ -134,12 +234,44 @@ tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx, | |||
134 | return (-1); | 234 | return (-1); |
135 | } | 235 | } |
136 | 236 | ||
237 | static int | ||
238 | tls_configure_server_sni(struct tls *ctx) | ||
239 | { | ||
240 | struct tls_sni_ctx **sni_ctx; | ||
241 | struct tls_keypair *kp; | ||
242 | |||
243 | if (ctx->config->keypair->next == NULL) | ||
244 | return (0); | ||
245 | |||
246 | /* Set up additional SSL contexts for SNI. */ | ||
247 | sni_ctx = &ctx->sni_ctx; | ||
248 | for (kp = ctx->config->keypair->next; kp != NULL; kp = kp->next) { | ||
249 | if ((*sni_ctx = tls_sni_ctx_new()) == NULL) { | ||
250 | tls_set_errorx(ctx, "out of memory"); | ||
251 | goto err; | ||
252 | } | ||
253 | if (tls_configure_server_ssl(ctx, &(*sni_ctx)->ssl_ctx, kp) == -1) | ||
254 | goto err; | ||
255 | if (tls_keypair_load_cert(kp, &ctx->error, | ||
256 | &(*sni_ctx)->ssl_cert) == -1) | ||
257 | goto err; | ||
258 | sni_ctx = &(*sni_ctx)->next; | ||
259 | } | ||
260 | |||
261 | return (0); | ||
262 | |||
263 | err: | ||
264 | return (-1); | ||
265 | } | ||
266 | |||
137 | int | 267 | int |
138 | tls_configure_server(struct tls *ctx) | 268 | tls_configure_server(struct tls *ctx) |
139 | { | 269 | { |
140 | if (tls_configure_server_ssl(ctx, &ctx->ssl_ctx, | 270 | if (tls_configure_server_ssl(ctx, &ctx->ssl_ctx, |
141 | ctx->config->keypair) == -1) | 271 | ctx->config->keypair) == -1) |
142 | goto err; | 272 | goto err; |
273 | if (tls_configure_server_sni(ctx) == -1) | ||
274 | goto err; | ||
143 | 275 | ||
144 | return (0); | 276 | return (0); |
145 | 277 | ||