1024: Verify server certificate hostname with OpenSSL
[elinks/elinks-j605.git] / src / network / ssl / socket.c
blobf82bf871a7d68ccd69aa8b177de322ebd774388c
1 /* SSL socket workshop */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #ifdef CONFIG_OPENSSL
8 #include <openssl/ssl.h>
9 #include <openssl/x509v3.h>
10 #define USE_OPENSSL
11 #elif defined(CONFIG_NSS_COMPAT_OSSL)
12 #include <nss_compat_ossl/nss_compat_ossl.h>
13 #define USE_OPENSSL
14 #elif defined(CONFIG_GNUTLS)
15 #include <gnutls/gnutls.h>
16 #include <gnutls/x509.h>
17 #else
18 #error "Huh?! You have SSL enabled, but not OPENSSL nor GNUTLS!! And then you want exactly *what* from me?"
19 #endif
21 #ifdef HAVE_ARPA_INET_H
22 #include <arpa/inet.h>
23 #endif
24 #include <errno.h>
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h>
27 #endif
29 #include "elinks.h"
31 #include "config/options.h"
32 #include "main/select.h"
33 #include "network/connection.h"
34 #include "network/socket.h"
35 #include "network/ssl/match-hostname.h"
36 #include "network/ssl/socket.h"
37 #include "network/ssl/ssl.h"
38 #include "protocol/uri.h"
39 #include "util/memory.h"
42 /* SSL errors */
43 #ifdef USE_OPENSSL
44 #define SSL_ERROR_WANT_READ2 9999 /* XXX */
45 #define SSL_ERROR_WANT_WRITE2 SSL_ERROR_WANT_WRITE
46 #define SSL_ERROR_SYSCALL2 SSL_ERROR_SYSCALL
47 #elif defined(CONFIG_GNUTLS)
48 #define SSL_ERROR_NONE GNUTLS_E_SUCCESS
49 #define SSL_ERROR_WANT_READ GNUTLS_E_AGAIN
50 #define SSL_ERROR_WANT_READ2 GNUTLS_E_INTERRUPTED
51 #define SSL_ERROR_WANT_WRITE GNUTLS_E_AGAIN
52 #define SSL_ERROR_WANT_WRITE2 GNUTLS_E_INTERRUPTED
53 #define SSL_ERROR_SYSCALL GNUTLS_E_PUSH_ERROR
54 #define SSL_ERROR_SYSCALL2 GNUTLS_E_PULL_ERROR
55 #endif
57 #ifdef USE_OPENSSL
59 #define ssl_do_connect(socket) SSL_get_error(socket->ssl, SSL_connect(socket->ssl))
60 #define ssl_do_write(socket, data, len) SSL_write(socket->ssl, data, len)
61 #define ssl_do_read(socket, data, len) SSL_read(socket->ssl, data, len)
62 #define ssl_do_close(socket) /* Hmh? No idea.. */
64 #elif defined(CONFIG_GNUTLS)
66 #define ssl_do_connect(conn) gnutls_handshake(*((ssl_t *) socket->ssl))
67 #define ssl_do_write(socket, data, len) gnutls_record_send(*((ssl_t *) socket->ssl), data, len)
68 #define ssl_do_read(socket, data, len) gnutls_record_recv(*((ssl_t *) socket->ssl), data, len)
69 /* We probably don't handle this entirely correctly.. */
70 #define ssl_do_close(socket) gnutls_bye(*((ssl_t *) socket->ssl), GNUTLS_SHUT_RDWR);
72 #endif
75 /* Refuse to negotiate TLS 1.0 and later protocols on @socket->ssl.
76 * Without this, connecting to <https://www-s.uiuc.edu/> with GnuTLS
77 * 1.3.5 would result in an SSL error. The bug may be in the server
78 * (Netscape-Enterprise/3.6 SP3), in GnuTLS, or in ELinks; please log
79 * your findings to ELinks bug 712. */
80 static void
81 ssl_set_no_tls(struct socket *socket)
83 #ifdef CONFIG_OPENSSL
84 ((ssl_t *) socket->ssl)->options |= SSL_OP_NO_TLSv1;
85 #elif defined(CONFIG_GNUTLS)
86 /* There is another gnutls_priority_set_direct call elsewhere
87 * in ELinks. If you change the priorities here, please check
88 * whether that one needs to be changed as well.
90 * GnuTLS 2.12.x is said to support "-VERS-TLS-ALL" too, but
91 * that version hasn't yet been released as of May 2011. */
92 gnutls_priority_set_direct(*(ssl_t *) socket->ssl,
93 "SECURE:-CTYPE-OPENPGP"
94 ":+VERS-SSL3.0:-VERS-TLS1.0"
95 ":-VERS-TLS1.1:-VERS-TLS1.2"
96 ":%SSL3_RECORD_VERSION",
97 NULL);
98 #endif
102 #ifdef CONFIG_GNUTLS
103 static int
104 verify_certificates(struct socket *socket)
106 gnutls_x509_crt_t cert;
107 gnutls_session_t session = *(ssl_t *)socket->ssl;
108 struct connection *conn = socket->conn;
109 const gnutls_datum_t *cert_list;
110 unsigned char *hostname;
111 int ret;
112 unsigned int cert_list_size, status;
115 ret = gnutls_certificate_verify_peers2(session, &status);
116 if (ret) return ret;
117 if (status) return status;
119 /* If the certificate is of a type for which verification has
120 * not yet been implemented, then reject it. This way, a fake
121 * server cannot avoid verification by using a strange type of
122 * certificate.
124 * OpenPGP certificates shouldn't even get this far anyway,
125 * because init_ssl_connection() tells GnuTLS to disable
126 * OpenPGP, and ELinks never calls
127 * gnutls_certificate_set_openpgp_keyring_file, so status
128 * should have been GNUTLS_CERT_SIGNER_NOT_FOUND. */
129 if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
130 return -7;
132 if (gnutls_x509_crt_init(&cert) < 0) {
133 return -1;
136 cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
137 if (!cert_list) {
138 return -2;
141 if (gnutls_x509_crt_import(cert, &cert_list[0],
142 GNUTLS_X509_FMT_DER) < 0) {
143 return -3;
145 if (gnutls_x509_crt_get_expiration_time(cert) < time(NULL)) {
146 gnutls_x509_crt_deinit(cert);
147 return -4;
150 if (gnutls_x509_crt_get_activation_time(cert) > time(NULL)) {
151 gnutls_x509_crt_deinit(cert);
152 return -5;
155 /* Because RFC 5280 defines dNSName as an IA5String, it can
156 * only contain ASCII characters. Internationalized domain
157 * names must thus be in Punycode form. Because GnuTLS 2.8.6
158 * does not itself support IDN, ELinks must convert. */
159 hostname = get_uri_string(conn->uri, URI_HOST | URI_IDN);
160 if (!hostname) return -6;
162 ret = !gnutls_x509_crt_check_hostname(cert, hostname);
163 gnutls_x509_crt_deinit(cert);
164 mem_free(hostname);
165 return ret;
167 #endif /* CONFIG_GNUTLS */
169 #ifdef USE_OPENSSL
171 /** Checks whether the host component of a URI matches a host name in
172 * the server certificate.
174 * @param[in] uri_host
175 * The host name (or IP address) to which the user wanted to connect.
176 * Should be in UTF-8.
177 * @param[in] cert_host_asn1
178 * A host name found in the server certificate: either as commonName
179 * in the subject field, or as a dNSName in the subjectAltName
180 * extension. This may contain wildcards, as specified in RFC 2818
181 * section 3.1.
183 * @return
184 * Nonzero if the host matches. Zero if it doesn't, or on error.
186 * If @a uri_host is an IP address literal rather than a host name,
187 * then this function returns 0, meaning that the host name does not match.
188 * According to RFC 2818, if the certificate is intended to match an
189 * IP address, then it must have that IP address as an iPAddress
190 * SubjectAltName, rather than in commonName. For comparing those,
191 * match_uri_host_ip() must be used instead of this function. */
192 static int
193 match_uri_host_name(const unsigned char *uri_host,
194 ASN1_STRING *cert_host_asn1)
196 const size_t uri_host_len = strlen(uri_host);
197 unsigned char *cert_host = NULL;
198 int cert_host_len;
199 int matched = 0;
201 if (is_ip_address(uri_host, uri_host_len))
202 goto mismatch;
204 /* This function is used for both dNSName and commonName.
205 * Although dNSName is always an IA5 string, commonName allows
206 * many other encodings too. Normalize all to UTF-8. */
207 cert_host_len = ASN1_STRING_to_UTF8(&cert_host,
208 cert_host_asn1);
209 if (cert_host_len < 0)
210 goto mismatch;
212 matched = match_hostname_pattern(uri_host, uri_host_len,
213 cert_host, cert_host_len);
215 mismatch:
216 if (cert_host)
217 OPENSSL_free(cert_host);
218 return matched;
221 /** Checks whether the host component of a URI matches an IP address
222 * in the server certificate.
224 * @param[in] uri_host
225 * The IP address (or host name) to which the user wanted to connect.
226 * Should be in UTF-8.
227 * @param[in] cert_host_asn1
228 * An IP address found as iPAddress in the subjectAltName extension
229 * of the server certificate. According to RFC 5280 section 4.2.1.6,
230 * that is an octet string in network byte order. According to
231 * RFC 2818 section 3.1, wildcards are not allowed.
233 * @return
234 * Nonzero if the host matches. Zero if it doesn't, or on error.
236 * If @a uri_host is a host name rather than an IP address literal,
237 * then this function returns 0, meaning that the address does not match.
238 * This function does not try to resolve the host name to an IP address
239 * and compare that to @a cert_host_asn1, because such an approach would
240 * be vulnerable to DNS spoofing.
242 * This function does not support the address-and-netmask format used
243 * in the name constraints extension of a CA certificate (RFC 5280
244 * section 4.2.1.10). */
245 static int
246 match_uri_host_ip(const unsigned char *uri_host,
247 ASN1_OCTET_STRING *cert_host_asn1)
249 const unsigned char *cert_host_addr = ASN1_STRING_data(cert_host_asn1);
250 struct in_addr uri_host_in;
251 #ifdef CONFIG_IPV6
252 struct in6_addr uri_host_in6;
253 #endif
255 /* RFC 5280 defines the iPAddress alternative of GeneralName
256 * as an OCTET STRING. Verify that the type is indeed that.
257 * This is an assertion because, if someone puts the wrong
258 * type of data there, then it will not even be recognized as
259 * an iPAddress, and this function will not be called.
261 * (Because GeneralName is defined in an implicitly tagged
262 * ASN.1 module, the OCTET STRING tag is not part of the DER
263 * encoding. BER also allows a constructed encoding where
264 * each substring begins with the OCTET STRING tag; but ITU-T
265 * Rec. X.690 (07/2002) subclause 8.21 says those would be
266 * OCTET STRING even if the outer string were of some other
267 * type. "A Layman's Guide to a Subset of ASN.1, BER, and
268 * DER" (Kaliski, 1993) claims otherwise, though.) */
269 assert(ASN1_STRING_type(cert_host_asn1) == V_ASN1_OCTET_STRING);
270 if_assert_failed return 0;
272 /* cert_host_addr, url_host_in, and url_host_in6 are all in
273 * network byte order. */
274 switch (ASN1_STRING_length(cert_host_asn1)) {
275 case 4:
276 return inet_aton(uri_host, &uri_host_in) != 0
277 && memcmp(cert_host_addr, &uri_host_in.s_addr, 4) == 0;
279 #ifdef CONFIG_IPV6
280 case 16:
281 return inet_pton(AF_INET6, uri_host, &uri_host_in6) == 1
282 && memcmp(cert_host_addr, &uri_host_in6.s6_addr, 16) == 0;
283 #endif
285 default:
286 return 0;
290 /** Verify one certificate in the server certificate chain.
291 * This callback is documented in SSL_set_verify(3). */
292 static int
293 verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
295 X509 *cert;
296 SSL *ssl;
297 struct socket *socket;
298 struct connection *conn;
299 unsigned char *host_in_uri;
300 GENERAL_NAMES *alts;
301 int saw_dns_name = 0;
302 int matched = 0;
304 /* If OpenSSL already found a problem, keep that. */
305 if (!preverify_ok)
306 return 0;
308 /* Examine only the server certificate, not CA certificates. */
309 if (X509_STORE_CTX_get_error_depth(ctx) != 0)
310 return preverify_ok;
312 cert = X509_STORE_CTX_get_current_cert(ctx);
313 ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
314 socket = SSL_get_ex_data(ssl, socket_SSL_ex_data_idx);
315 conn = socket->conn;
316 host_in_uri = get_uri_string(conn->uri, URI_HOST | URI_IDN);
317 if (!host_in_uri)
318 return 0;
320 /* RFC 5280 section 4.2.1.6 describes the subjectAltName extension.
321 * RFC 2818 section 3.1 says Common Name must not be used
322 * if dNSName is present. */
323 alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
324 if (alts != NULL) {
325 int alt_count;
326 int alt_pos;
327 GENERAL_NAME *alt;
329 alt_count = sk_GENERAL_NAME_num(alts);
330 for (alt_pos = 0; !matched && alt_pos < alt_count; ++alt_pos) {
331 alt = sk_GENERAL_NAME_value(alts, alt_pos);
332 if (alt->type == GEN_DNS) {
333 saw_dns_name = 1;
334 matched = match_uri_host_name(host_in_uri,
335 alt->d.dNSName);
336 } else if (alt->type == GEN_IPADD) {
337 matched = match_uri_host_ip(host_in_uri,
338 alt->d.iPAddress);
342 /* Free the GENERAL_NAMES list and each element. */
343 sk_GENERAL_NAME_pop_free(alts, GENERAL_NAME_free);
346 if (!matched && !saw_dns_name) {
347 X509_NAME *name;
348 int cn_index;
349 X509_NAME_ENTRY *entry = NULL;
351 name = X509_get_subject_name(cert);
352 cn_index = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
353 if (cn_index >= 0)
354 entry = X509_NAME_get_entry(name, cn_index);
355 if (entry != NULL)
356 matched = match_uri_host_name(host_in_uri,
357 X509_NAME_ENTRY_get_data(entry));
360 mem_free(host_in_uri);
361 return matched;
364 #endif /* USE_OPENSSL */
366 static void
367 ssl_want_read(struct socket *socket)
369 if (socket->no_tls)
370 ssl_set_no_tls(socket);
372 switch (ssl_do_connect(socket)) {
373 case SSL_ERROR_NONE:
374 #ifdef CONFIG_GNUTLS
375 if (get_opt_bool("connection.ssl.cert_verify", NULL)
376 && verify_certificates(socket)) {
377 socket->ops->retry(socket, connection_state(S_SSL_ERROR));
378 return;
380 #endif
382 /* Report successful SSL connection setup. */
383 complete_connect_socket(socket, NULL, NULL);
384 break;
386 case SSL_ERROR_WANT_READ:
387 case SSL_ERROR_WANT_READ2:
388 break;
390 default:
391 socket->no_tls = !socket->no_tls;
392 socket->ops->retry(socket, connection_state(S_SSL_ERROR));
396 /* Return -1 on error, 0 or success. */
398 ssl_connect(struct socket *socket)
400 int ret;
401 unsigned char *server_name;
402 struct connection *conn = socket->conn;
404 /* TODO: Recode server_name to UTF-8. */
405 server_name = get_uri_string(conn->proxied_uri, URI_HOST);
406 if (!server_name) {
407 socket->ops->done(socket, connection_state(S_OUT_OF_MEM));
408 return -1;
411 /* RFC 3546 says literal IPv4 and IPv6 addresses are not allowed. */
412 if (is_ip_address(server_name, strlen(server_name)))
413 mem_free_set(&server_name, NULL);
415 if (init_ssl_connection(socket, server_name) == S_SSL_ERROR) {
416 mem_free_if(server_name);
417 socket->ops->done(socket, connection_state(S_SSL_ERROR));
418 return -1;
421 mem_free_if(server_name);
423 if (socket->no_tls)
424 ssl_set_no_tls(socket);
426 #ifdef USE_OPENSSL
427 SSL_set_fd(socket->ssl, socket->fd);
429 if (get_opt_bool("connection.ssl.cert_verify", NULL))
430 SSL_set_verify(socket->ssl, SSL_VERIFY_PEER
431 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
432 verify_callback);
434 if (get_opt_bool("connection.ssl.client_cert.enable", NULL)) {
435 unsigned char *client_cert;
437 #ifdef CONFIG_NSS_COMPAT_OSSL
438 client_cert = get_opt_str(
439 "connection.ssl.client_cert.nickname", NULL);
440 #else
441 client_cert = get_opt_str(
442 "connection.ssl.client_cert.file", NULL);
443 #endif
444 if (!*client_cert) {
445 client_cert = getenv("X509_CLIENT_CERT");
446 if (client_cert && !*client_cert)
447 client_cert = NULL;
450 if (client_cert) {
451 #ifdef CONFIG_NSS_COMPAT_OSSL
452 SSL_CTX_use_certificate_chain_file(
453 (SSL *) socket->ssl,
454 client_cert);
455 #else
456 SSL_CTX *ctx = ((SSL *) socket->ssl)->ctx;
458 SSL_CTX_use_certificate_chain_file(ctx, client_cert);
459 SSL_CTX_use_PrivateKey_file(ctx, client_cert,
460 SSL_FILETYPE_PEM);
461 #endif
465 #elif defined(CONFIG_GNUTLS)
466 /* GnuTLS uses function pointers for network I/O. The default
467 * functions take a file descriptor, but it must be passed in
468 * as a pointer. GnuTLS uses the GNUTLS_INT_TO_POINTER and
469 * GNUTLS_POINTER_TO_INT macros for these conversions, but
470 * those are unfortunately not in any public header. So
471 * ELinks must just cast the pointer the best it can and hope
472 * that the conversions match. */
473 gnutls_transport_set_ptr(*((ssl_t *) socket->ssl),
474 (gnutls_transport_ptr) (longptr_T) socket->fd);
476 /* TODO: Some certificates fuss. --pasky */
477 #endif
479 ret = ssl_do_connect(socket);
481 switch (ret) {
482 case SSL_ERROR_WANT_READ:
483 case SSL_ERROR_WANT_READ2:
484 socket->ops->set_state(socket, connection_state(S_SSL_NEG));
485 set_handlers(socket->fd, (select_handler_T) ssl_want_read,
486 NULL, (select_handler_T) dns_exception, socket);
487 return -1;
489 case SSL_ERROR_NONE:
490 #ifdef CONFIG_GNUTLS
491 if (!get_opt_bool("connection.ssl.cert_verify", NULL))
492 break;
494 if (!verify_certificates(socket))
495 #endif
496 break;
498 default:
499 if (ret != SSL_ERROR_NONE) {
500 /* DBG("sslerr %s", gnutls_strerror(ret)); */
501 socket->no_tls = !socket->no_tls;
504 connect_socket(socket, connection_state(S_SSL_ERROR));
505 return -1;
508 return 0;
511 /* Return enum socket_error on error, bytes written on success. */
512 ssize_t
513 ssl_write(struct socket *socket, unsigned char *data, int len)
515 ssize_t wr = ssl_do_write(socket, data, len);
517 if (wr <= 0) {
518 #ifdef USE_OPENSSL
519 int err = SSL_get_error(socket->ssl, wr);
520 #elif defined(CONFIG_GNUTLS)
521 int err = wr;
522 #endif
523 if (err == SSL_ERROR_WANT_WRITE ||
524 err == SSL_ERROR_WANT_WRITE2) {
525 return -1;
528 if (!wr) return SOCKET_CANT_WRITE;
530 if (err == SSL_ERROR_SYSCALL)
531 return SOCKET_SYSCALL_ERROR;
533 errno = S_SSL_ERROR;
534 return SOCKET_INTERNAL_ERROR;
537 return wr;
540 /* Return enum socket_error on error, bytes read on success. */
541 ssize_t
542 ssl_read(struct socket *socket, unsigned char *data, int len)
544 ssize_t rd = ssl_do_read(socket, data, len);
546 if (rd <= 0) {
547 #ifdef USE_OPENSSL
548 int err = SSL_get_error(socket->ssl, rd);
549 #elif defined(CONFIG_GNUTLS)
550 int err = rd;
551 #endif
553 #ifdef CONFIG_GNUTLS
554 if (err == GNUTLS_E_REHANDSHAKE)
555 return -1;
556 #endif
558 if (err == SSL_ERROR_WANT_READ ||
559 err == SSL_ERROR_WANT_READ2) {
560 return SOCKET_SSL_WANT_READ;
563 if (!rd) return SOCKET_CANT_READ;
565 if (err == SSL_ERROR_SYSCALL2)
566 return SOCKET_SYSCALL_ERROR;
568 errno = S_SSL_ERROR;
569 return SOCKET_INTERNAL_ERROR;
572 return rd;
576 ssl_close(struct socket *socket)
578 ssl_do_close(socket);
579 done_ssl_connection(socket);
581 return 0;