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/libtls/tls_server.c | |
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/libtls/tls_server.c')
-rw-r--r-- | src/lib/libtls/tls_server.c | 134 |
1 files changed, 133 insertions, 1 deletions
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 | ||