diff options
| -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 | ||
