summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2017-04-10 17:11:13 +0000
committerjsing <>2017-04-10 17:11:13 +0000
commit1fb5784eee903ab9b8621581b6128aaccf2d3120 (patch)
tree2ba4db6e1d15d0e16b83f40c86378539156871c3 /src
parenta887f273016c6b1a211de9fd477d86b2b8c26792 (diff)
downloadopenbsd-1fb5784eee903ab9b8621581b6128aaccf2d3120.tar.gz
openbsd-1fb5784eee903ab9b8621581b6128aaccf2d3120.tar.bz2
openbsd-1fb5784eee903ab9b8621581b6128aaccf2d3120.zip
Rework name verification code so that a match is indicated via an argument,
rather than return codes. More strictly follow RFC 6125, in particular only check the CN if there are no SAN identifiers present in the certificate (per section 6.4.4). Previous behaviour questioned by Daniel Stenberg <daniel at haxx dot se>. ok beck@ jca@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libtls/tls_client.c14
-rw-r--r--src/lib/libtls/tls_internal.h5
-rw-r--r--src/lib/libtls/tls_peer.c9
-rw-r--r--src/lib/libtls/tls_server.c11
-rw-r--r--src/lib/libtls/tls_verify.c84
5 files changed, 76 insertions, 47 deletions
diff --git a/src/lib/libtls/tls_client.c b/src/lib/libtls/tls_client.c
index a1e2caa717..0e519684ef 100644
--- a/src/lib/libtls/tls_client.c
+++ b/src/lib/libtls/tls_client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_client.c,v 1.40 2017/01/26 12:56:37 jsing Exp $ */ 1/* $OpenBSD: tls_client.c,v 1.41 2017/04/10 17:11:13 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -289,7 +289,7 @@ int
289tls_handshake_client(struct tls *ctx) 289tls_handshake_client(struct tls *ctx)
290{ 290{
291 X509 *cert = NULL; 291 X509 *cert = NULL;
292 int ssl_ret; 292 int match, ssl_ret;
293 int rv = -1; 293 int rv = -1;
294 294
295 if ((ctx->flags & TLS_CLIENT) == 0) { 295 if ((ctx->flags & TLS_CLIENT) == 0) {
@@ -311,11 +311,11 @@ tls_handshake_client(struct tls *ctx)
311 tls_set_errorx(ctx, "no server certificate"); 311 tls_set_errorx(ctx, "no server certificate");
312 goto err; 312 goto err;
313 } 313 }
314 if ((rv = tls_check_name(ctx, cert, 314 if (tls_check_name(ctx, cert, ctx->servername, &match) == -1)
315 ctx->servername)) != 0) { 315 goto err;
316 if (rv != -2) 316 if (!match) {
317 tls_set_errorx(ctx, "name `%s' not present in" 317 tls_set_errorx(ctx, "name `%s' not present in"
318 " server certificate", ctx->servername); 318 " server certificate", ctx->servername);
319 goto err; 319 goto err;
320 } 320 }
321 } 321 }
diff --git a/src/lib/libtls/tls_internal.h b/src/lib/libtls/tls_internal.h
index 7bbc14ca86..bd23249e57 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.56 2017/04/07 08:48:30 jsing Exp $ */ 1/* $OpenBSD: tls_internal.h,v 1.57 2017/04/10 17:11:13 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>
@@ -186,7 +186,8 @@ void tls_sni_ctx_free(struct tls_sni_ctx *sni_ctx);
186struct tls *tls_new(void); 186struct tls *tls_new(void);
187struct tls *tls_server_conn(struct tls *ctx); 187struct tls *tls_server_conn(struct tls *ctx);
188 188
189int tls_check_name(struct tls *ctx, X509 *cert, const char *servername); 189int tls_check_name(struct tls *ctx, X509 *cert, const char *servername,
190 int *match);
190int tls_configure_server(struct tls *ctx); 191int tls_configure_server(struct tls *ctx);
191 192
192int tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx); 193int tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx);
diff --git a/src/lib/libtls/tls_peer.c b/src/lib/libtls/tls_peer.c
index 1a9065dfb1..ec97a30838 100644
--- a/src/lib/libtls/tls_peer.c
+++ b/src/lib/libtls/tls_peer.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_peer.c,v 1.7 2017/04/05 03:19:22 beck Exp $ */ 1/* $OpenBSD: tls_peer.c,v 1.8 2017/04/10 17:11:13 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org> 4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
@@ -55,10 +55,15 @@ tls_peer_cert_provided(struct tls *ctx)
55int 55int
56tls_peer_cert_contains_name(struct tls *ctx, const char *name) 56tls_peer_cert_contains_name(struct tls *ctx, const char *name)
57{ 57{
58 int match;
59
58 if (ctx->ssl_peer_cert == NULL) 60 if (ctx->ssl_peer_cert == NULL)
59 return (0); 61 return (0);
60 62
61 return (tls_check_name(ctx, ctx->ssl_peer_cert, name) == 0); 63 if (tls_check_name(ctx, ctx->ssl_peer_cert, name, &match) == -1)
64 return (0);
65
66 return (match);
62} 67}
63 68
64time_t 69time_t
diff --git a/src/lib/libtls/tls_server.c b/src/lib/libtls/tls_server.c
index 51deff2510..39c6ca79e9 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.35 2017/01/31 15:57:43 jsing Exp $ */ 1/* $OpenBSD: tls_server.c,v 1.36 2017/04/10 17:11:13 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -75,11 +75,13 @@ tls_servername_cb(SSL *ssl, int *al, void *arg)
75 union tls_addr addrbuf; 75 union tls_addr addrbuf;
76 struct tls *conn_ctx; 76 struct tls *conn_ctx;
77 const char *name; 77 const char *name;
78 int match;
78 79
79 if ((conn_ctx = SSL_get_app_data(ssl)) == NULL) 80 if ((conn_ctx = SSL_get_app_data(ssl)) == NULL)
80 goto err; 81 goto err;
81 82
82 if ((name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)) == NULL) { 83 if ((name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)) ==
84 NULL) {
83 /* 85 /*
84 * The servername callback gets called even when there is no 86 * The servername callback gets called even when there is no
85 * TLS servername extension provided by the client. Sigh! 87 * TLS servername extension provided by the client. Sigh!
@@ -98,7 +100,10 @@ tls_servername_cb(SSL *ssl, int *al, void *arg)
98 100
99 /* Find appropriate SSL context for requested servername. */ 101 /* Find appropriate SSL context for requested servername. */
100 for (sni_ctx = ctx->sni_ctx; sni_ctx != NULL; sni_ctx = sni_ctx->next) { 102 for (sni_ctx = ctx->sni_ctx; sni_ctx != NULL; sni_ctx = sni_ctx->next) {
101 if (tls_check_name(ctx, sni_ctx->ssl_cert, name) == 0) { 103 if (tls_check_name(ctx, sni_ctx->ssl_cert, name,
104 &match) == -1)
105 goto err;
106 if (match) {
102 SSL_set_SSL_CTX(conn_ctx->ssl_conn, sni_ctx->ssl_ctx); 107 SSL_set_SSL_CTX(conn_ctx->ssl_conn, sni_ctx->ssl_ctx);
103 return (SSL_TLSEXT_ERR_OK); 108 return (SSL_TLSEXT_ERR_OK);
104 } 109 }
diff --git a/src/lib/libtls/tls_verify.c b/src/lib/libtls/tls_verify.c
index 23e58ebef7..3bd1057d0c 100644
--- a/src/lib/libtls/tls_verify.c
+++ b/src/lib/libtls/tls_verify.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_verify.c,v 1.18 2016/11/04 15:32:40 jsing Exp $ */ 1/* $OpenBSD: tls_verify.c,v 1.19 2017/04/10 17:11:13 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 * 4 *
@@ -27,11 +27,6 @@
27#include <tls.h> 27#include <tls.h>
28#include "tls_internal.h" 28#include "tls_internal.h"
29 29
30static int tls_match_name(const char *cert_name, const char *name);
31static int tls_check_subject_altname(struct tls *ctx, X509 *cert,
32 const char *name);
33static int tls_check_common_name(struct tls *ctx, X509 *cert, const char *name);
34
35static int 30static int
36tls_match_name(const char *cert_name, const char *name) 31tls_match_name(const char *cert_name, const char *name)
37{ 32{
@@ -84,20 +79,28 @@ tls_match_name(const char *cert_name, const char *name)
84 return -1; 79 return -1;
85} 80}
86 81
87/* See RFC 5280 section 4.2.1.6 for SubjectAltName details. */ 82/*
83 * See RFC 5280 section 4.2.1.6 for SubjectAltName details.
84 * alt_match is set to 1 if a matching alternate name is found.
85 * alt_exists is set to 1 if any known alternate name exists in the certificate.
86 */
88static int 87static int
89tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name) 88tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
89 int *alt_match, int *alt_exists)
90{ 90{
91 STACK_OF(GENERAL_NAME) *altname_stack = NULL; 91 STACK_OF(GENERAL_NAME) *altname_stack = NULL;
92 union tls_addr addrbuf; 92 union tls_addr addrbuf;
93 int addrlen, type; 93 int addrlen, type;
94 int count, i; 94 int count, i;
95 int rv = -1; 95 int rv = 0;
96
97 *alt_match = 0;
98 *alt_exists = 0;
96 99
97 altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name, 100 altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name,
98 NULL, NULL); 101 NULL, NULL);
99 if (altname_stack == NULL) 102 if (altname_stack == NULL)
100 return -1; 103 return 0;
101 104
102 if (inet_pton(AF_INET, name, &addrbuf) == 1) { 105 if (inet_pton(AF_INET, name, &addrbuf) == 1) {
103 type = GEN_IPADD; 106 type = GEN_IPADD;
@@ -115,6 +118,10 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name)
115 GENERAL_NAME *altname; 118 GENERAL_NAME *altname;
116 119
117 altname = sk_GENERAL_NAME_value(altname_stack, i); 120 altname = sk_GENERAL_NAME_value(altname_stack, i);
121
122 if (altname->type == GEN_DNS || altname->type == GEN_IPADD)
123 *alt_exists = 1;
124
118 if (altname->type != type) 125 if (altname->type != type)
119 continue; 126 continue;
120 127
@@ -133,7 +140,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name)
133 "NUL byte in subjectAltName, " 140 "NUL byte in subjectAltName, "
134 "probably a malicious certificate", 141 "probably a malicious certificate",
135 name); 142 name);
136 rv = -2; 143 rv = -1;
137 break; 144 break;
138 } 145 }
139 146
@@ -143,16 +150,16 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name)
143 * dNSName must be rejected. 150 * dNSName must be rejected.
144 */ 151 */
145 if (strcmp(data, " ") == 0) { 152 if (strcmp(data, " ") == 0) {
146 tls_set_error(ctx, 153 tls_set_errorx(ctx,
147 "error verifying name '%s': " 154 "error verifying name '%s': "
148 "a dNSName of \" \" must not be " 155 "a dNSName of \" \" must not be "
149 "used", name); 156 "used", name);
150 rv = -2; 157 rv = -1;
151 break; 158 break;
152 } 159 }
153 160
154 if (tls_match_name(data, name) == 0) { 161 if (tls_match_name(data, name) == 0) {
155 rv = 0; 162 *alt_match = 1;
156 break; 163 break;
157 } 164 }
158 } else { 165 } else {
@@ -174,7 +181,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name)
174 tls_set_errorx(ctx, 181 tls_set_errorx(ctx,
175 "Unexpected negative length for an " 182 "Unexpected negative length for an "
176 "IP address: %d", datalen); 183 "IP address: %d", datalen);
177 rv = -2; 184 rv = -1;
178 break; 185 break;
179 } 186 }
180 187
@@ -184,7 +191,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name)
184 */ 191 */
185 if (datalen == addrlen && 192 if (datalen == addrlen &&
186 memcmp(data, &addrbuf, addrlen) == 0) { 193 memcmp(data, &addrbuf, addrlen) == 0) {
187 rv = 0; 194 *alt_match = 1;
188 break; 195 break;
189 } 196 }
190 } 197 }
@@ -195,13 +202,16 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name)
195} 202}
196 203
197static int 204static int
198tls_check_common_name(struct tls *ctx, X509 *cert, const char *name) 205tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
206 int *cn_match)
199{ 207{
200 X509_NAME *subject_name; 208 X509_NAME *subject_name;
201 char *common_name = NULL; 209 char *common_name = NULL;
202 union tls_addr addrbuf; 210 union tls_addr addrbuf;
203 int common_name_len; 211 int common_name_len;
204 int rv = -1; 212 int rv = 0;
213
214 *cn_match = 0;
205 215
206 subject_name = X509_get_subject_name(cert); 216 subject_name = X509_get_subject_name(cert);
207 if (subject_name == NULL) 217 if (subject_name == NULL)
@@ -225,38 +235,46 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name)
225 tls_set_errorx(ctx, "error verifying name '%s': " 235 tls_set_errorx(ctx, "error verifying name '%s': "
226 "NUL byte in Common Name field, " 236 "NUL byte in Common Name field, "
227 "probably a malicious certificate", name); 237 "probably a malicious certificate", name);
228 rv = -2; 238 rv = -1;
229 goto out; 239 goto out;
230 } 240 }
231 241
242 /*
243 * We don't want to attempt wildcard matching against IP addresses,
244 * so perform a simple comparison here.
245 */
232 if (inet_pton(AF_INET, name, &addrbuf) == 1 || 246 if (inet_pton(AF_INET, name, &addrbuf) == 1 ||
233 inet_pton(AF_INET6, name, &addrbuf) == 1) { 247 inet_pton(AF_INET6, name, &addrbuf) == 1) {
234 /*
235 * We don't want to attempt wildcard matching against IP
236 * addresses, so perform a simple comparison here.
237 */
238 if (strcmp(common_name, name) == 0) 248 if (strcmp(common_name, name) == 0)
239 rv = 0; 249 *cn_match = 1;
240 else
241 rv = -1;
242 goto out; 250 goto out;
243 } 251 }
244 252
245 if (tls_match_name(common_name, name) == 0) 253 if (tls_match_name(common_name, name) == 0)
246 rv = 0; 254 *cn_match = 1;
255
247 out: 256 out:
248 free(common_name); 257 free(common_name);
249 return rv; 258 return rv;
250} 259}
251 260
252int 261int
253tls_check_name(struct tls *ctx, X509 *cert, const char *name) 262tls_check_name(struct tls *ctx, X509 *cert, const char *name, int *match)
254{ 263{
255 int rv; 264 int alt_exists;
256 265
257 rv = tls_check_subject_altname(ctx, cert, name); 266 *match = 0;
258 if (rv == 0 || rv == -2) 267
259 return rv; 268 if (tls_check_subject_altname(ctx, cert, name, match,
269 &alt_exists) == -1)
270 return -1;
271
272 /*
273 * As per RFC 6125 section 6.4.4, if any known alternate name existed
274 * in the certificate, we do not attempt to match on the CN.
275 */
276 if (*match || alt_exists)
277 return 0;
260 278
261 return tls_check_common_name(ctx, cert, name); 279 return tls_check_common_name(ctx, cert, name, match);
262} 280}