2 network-ssl.c : SSL support
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <openssl/crypto.h>
29 #include <openssl/x509.h>
30 #include <openssl/x509v3.h>
31 #include <openssl/pem.h>
32 #include <openssl/ssl.h>
33 #include <openssl/err.h>
36 #include <validator/validator.h>
37 #include <validator/val_dane.h>
40 /* ssl i/o channel object */
48 unsigned int verify:1;
53 static int ssl_inited = FALSE;
55 static void irssi_ssl_free(GIOChannel *handle)
57 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
58 g_io_channel_unref(chan->giochan);
60 SSL_CTX_free(chan->ctx);
64 /* Checks if the given string has internal NUL characters. */
65 static gboolean has_internal_nul(const char* str, int len) {
66 /* Remove trailing nul characters. They would give false alarms */
67 while (len > 0 && str[len-1] == 0)
69 return strlen(str) != len;
72 /* tls_dns_name - Extract valid DNS name from subjectAltName value */
73 static const char *tls_dns_name(const GENERAL_NAME * gn)
77 /* We expect the OpenSSL library to construct GEN_DNS extension objects as
78 ASN1_IA5STRING values. Check we got the right union member. */
79 if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) {
80 g_warning("Invalid ASN1 value type in subjectAltName");
84 /* Safe to treat as an ASCII string possibly holding a DNS name */
85 dnsname = (char *) ASN1_STRING_data(gn->d.ia5);
87 if (has_internal_nul(dnsname, ASN1_STRING_length(gn->d.ia5))) {
88 g_warning("Internal NUL in subjectAltName");
95 /* tls_text_name - extract certificate property value by name */
96 static char *tls_text_name(X509_NAME *name, int nid)
99 X509_NAME_ENTRY *entry;
100 ASN1_STRING *entry_str;
102 unsigned char *utf8_value;
105 if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
109 entry = X509_NAME_get_entry(name, pos);
110 g_return_val_if_fail(entry != NULL, NULL);
111 entry_str = X509_NAME_ENTRY_get_data(entry);
112 g_return_val_if_fail(entry_str != NULL, NULL);
114 /* Convert everything into UTF-8. It's up to OpenSSL to do something
115 reasonable when converting ASCII formats that contain non-ASCII
117 if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
118 g_warning("Error decoding ASN.1 type=%d", ASN1_STRING_type(entry_str));
122 if (has_internal_nul((char *)utf8_value, utf8_length)) {
123 g_warning("NUL character in hostname in certificate");
124 OPENSSL_free(utf8_value);
128 result = g_strdup((char *) utf8_value);
129 OPENSSL_free(utf8_value);
134 /** check if a hostname in the certificate matches the hostname we used for the connection */
135 static gboolean match_hostname(const char *cert_hostname, const char *hostname)
137 const char *hostname_left;
139 if (!strcasecmp(cert_hostname, hostname)) { /* exact match */
141 } else if (cert_hostname[0] == '*' && cert_hostname[1] == '.' && cert_hostname[2] != 0) { /* wildcard match */
142 /* The initial '*' matches exactly one hostname component */
143 hostname_left = strchr(hostname, '.');
144 if (hostname_left != NULL && ! strcasecmp(hostname_left + 1, cert_hostname + 2)) {
151 /* based on verify_extract_name from tls_client.c in postfix */
152 static gboolean irssi_ssl_verify_hostname(X509 *cert, const char *hostname)
154 int gen_index, gen_count;
155 gboolean matched = FALSE, has_dns_name = FALSE;
156 const char *cert_dns_name;
157 char *cert_subject_cn;
158 const GENERAL_NAME *gn;
159 STACK_OF(GENERAL_NAME) * gens;
161 /* Verify the dNSName(s) in the peer certificate against the hostname. */
162 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
164 gen_count = sk_GENERAL_NAME_num(gens);
165 for (gen_index = 0; gen_index < gen_count && !matched; ++gen_index) {
166 gn = sk_GENERAL_NAME_value(gens, gen_index);
167 if (gn->type != GEN_DNS)
170 /* Even if we have an invalid DNS name, we still ultimately
171 ignore the CommonName, because subjectAltName:DNS is
172 present (though malformed). */
174 cert_dns_name = tls_dns_name(gn);
175 if (cert_dns_name && *cert_dns_name) {
176 matched = match_hostname(cert_dns_name, hostname);
180 /* Free stack *and* member GENERAL_NAME objects */
181 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
186 /* The CommonName in the issuer DN is obsolete when SubjectAltName is available. */
187 g_warning("None of the Subject Alt Names in the certificate match hostname '%s'", hostname);
190 } else { /* No subjectAltNames, look at CommonName */
191 cert_subject_cn = tls_text_name(X509_get_subject_name(cert), NID_commonName);
192 if (cert_subject_cn && *cert_subject_cn) {
193 matched = match_hostname(cert_subject_cn, hostname);
195 g_warning("SSL certificate common name '%s' doesn't match host name '%s'", cert_subject_cn, hostname);
198 g_warning("No subjectAltNames and no valid common name in certificate");
200 free(cert_subject_cn);
206 static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, const char* hostname, int port, X509 *cert, SERVER_REC *server)
211 struct val_daneparams daneparams;
212 struct val_danestatus *danestatus = NULL;
214 // Check if a TLSA record is available.
215 daneparams.port = port;
216 daneparams.proto = DANE_PARAM_PROTO_TCP;
218 dane_ret = val_getdaneinfo(NULL, hostname, &daneparams, &danestatus);
220 if (dane_ret == VAL_DANE_NOERROR) {
221 signal_emit("tlsa available", 1, server);
224 if (danestatus != NULL) {
225 int do_certificate_check = 1;
227 if (val_dane_check(NULL, ssl, danestatus, &do_certificate_check) != VAL_DANE_NOERROR) {
228 g_warning("DANE: TLSA record for hostname %s port %d could not be verified", hostname, port);
229 signal_emit("tlsa verification failed", 1, server);
230 val_free_dane(danestatus);
234 signal_emit("tlsa verification success", 1, server);
235 val_free_dane(danestatus);
237 if (do_certificate_check == 0) {
243 result = SSL_get_verify_result(ssl);
244 if (result != X509_V_OK) {
245 unsigned char md[EVP_MAX_MD_SIZE];
249 g_warning("Could not verify SSL servers certificate: %s",
250 X509_verify_cert_error_string(result));
251 if ((str = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) == NULL)
252 g_warning(" Could not get subject-name from peer certificate");
254 g_warning(" Subject : %s", str);
257 if ((str = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)) == NULL)
258 g_warning(" Could not get issuer-name from peer certificate");
260 g_warning(" Issuer : %s", str);
263 if (! X509_digest(cert, EVP_md5(), md, &n))
264 g_warning(" Could not get fingerprint from peer certificate");
266 char hex[] = "0123456789ABCDEF";
267 char fp[EVP_MAX_MD_SIZE*3];
268 if (n < sizeof(fp)) {
270 for (i = 0; i < n; i++) {
271 fp[i*3+0] = hex[(md[i] >> 4) & 0xF];
272 fp[i*3+1] = hex[(md[i] >> 0) & 0xF];
273 fp[i*3+2] = i == n - 1 ? '\0' : ':';
275 g_warning(" MD5 Fingerprint : %s", fp);
279 } else if (! irssi_ssl_verify_hostname(cert, hostname)){
285 static GIOStatus irssi_ssl_read(GIOChannel *handle, gchar *buf, gsize len, gsize *ret, GError **gerr)
287 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
292 ret1 = SSL_read(chan->ssl, buf, len);
296 err = SSL_get_error(chan->ssl, ret1);
297 if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
298 return G_IO_STATUS_AGAIN;
299 else if(err == SSL_ERROR_ZERO_RETURN)
300 return G_IO_STATUS_EOF;
301 else if (err == SSL_ERROR_SYSCALL)
303 errstr = ERR_reason_error_string(ERR_get_error());
304 if (errstr == NULL && ret1 == -1)
305 errstr = strerror(errno);
307 errstr = "server closed connection unexpectedly";
311 errstr = ERR_reason_error_string(ERR_get_error());
313 errstr = "unknown SSL error";
315 errmsg = g_strdup_printf("SSL read error: %s", errstr);
316 *gerr = g_error_new_literal(G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED,
319 return G_IO_STATUS_ERROR;
324 return G_IO_STATUS_NORMAL;
327 return G_IO_STATUS_ERROR;
330 static GIOStatus irssi_ssl_write(GIOChannel *handle, const gchar *buf, gsize len, gsize *ret, GError **gerr)
332 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
337 ret1 = SSL_write(chan->ssl, (const char *)buf, len);
341 err = SSL_get_error(chan->ssl, ret1);
342 if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
343 return G_IO_STATUS_AGAIN;
344 else if(err == SSL_ERROR_ZERO_RETURN)
345 errstr = "server closed connection";
346 else if (err == SSL_ERROR_SYSCALL)
348 errstr = ERR_reason_error_string(ERR_get_error());
349 if (errstr == NULL && ret1 == -1)
350 errstr = strerror(errno);
352 errstr = "server closed connection unexpectedly";
356 errstr = ERR_reason_error_string(ERR_get_error());
358 errstr = "unknown SSL error";
360 errmsg = g_strdup_printf("SSL write error: %s", errstr);
361 *gerr = g_error_new_literal(G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED,
364 return G_IO_STATUS_ERROR;
369 return G_IO_STATUS_NORMAL;
372 return G_IO_STATUS_ERROR;
375 static GIOStatus irssi_ssl_seek(GIOChannel *handle, gint64 offset, GSeekType type, GError **gerr)
377 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
379 return chan->giochan->funcs->io_seek(handle, offset, type, gerr);
382 static GIOStatus irssi_ssl_close(GIOChannel *handle, GError **gerr)
384 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
386 return chan->giochan->funcs->io_close(handle, gerr);
389 static GSource *irssi_ssl_create_watch(GIOChannel *handle, GIOCondition cond)
391 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
393 return chan->giochan->funcs->io_create_watch(handle, cond);
396 static GIOStatus irssi_ssl_set_flags(GIOChannel *handle, GIOFlags flags, GError **gerr)
398 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
400 return chan->giochan->funcs->io_set_flags(handle, flags, gerr);
403 static GIOFlags irssi_ssl_get_flags(GIOChannel *handle)
405 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
407 return chan->giochan->funcs->io_get_flags(handle);
410 static GIOFuncs irssi_ssl_channel_funcs = {
415 irssi_ssl_create_watch,
421 static gboolean irssi_ssl_init(void)
424 SSL_load_error_strings();
425 OpenSSL_add_all_algorithms();
432 static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_REC *server)
440 const char *mycert = server->connrec->ssl_cert;
441 const char *mypkey = server->connrec->ssl_pkey;
442 const char *cafile = server->connrec->ssl_cafile;
443 const char *capath = server->connrec->ssl_capath;
444 gboolean verify = server->connrec->ssl_verify;
446 g_return_val_if_fail(handle != NULL, NULL);
448 if(!ssl_inited && !irssi_ssl_init())
451 if(!(fd = g_io_channel_unix_get_fd(handle)))
454 ctx = SSL_CTX_new(SSLv23_client_method());
456 g_error("Could not allocate memory for SSL context");
459 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
461 if (mycert && *mycert) {
462 char *scert = NULL, *spkey = NULL;
463 scert = convert_home(mycert);
464 if (mypkey && *mypkey)
465 spkey = convert_home(mypkey);
466 if (! SSL_CTX_use_certificate_file(ctx, scert, SSL_FILETYPE_PEM))
467 g_warning("Loading of client certificate '%s' failed", mycert);
468 else if (! SSL_CTX_use_PrivateKey_file(ctx, spkey ? spkey : scert, SSL_FILETYPE_PEM))
469 g_warning("Loading of private key '%s' failed", mypkey ? mypkey : mycert);
470 else if (! SSL_CTX_check_private_key(ctx))
471 g_warning("Private key does not match the certificate");
476 if ((cafile && *cafile) || (capath && *capath)) {
477 char *scafile = NULL;
478 char *scapath = NULL;
479 if (cafile && *cafile)
480 scafile = convert_home(cafile);
481 if (capath && *capath)
482 scapath = convert_home(capath);
483 if (! SSL_CTX_load_verify_locations(ctx, scafile, scapath)) {
484 g_warning("Could not load CA list for verifying SSL server certificate");
494 if (!SSL_CTX_set_default_verify_paths(ctx))
495 g_warning("Could not load default certificates");
498 if(!(ssl = SSL_new(ctx)))
500 g_warning("Failed to allocate SSL structure");
505 if(!SSL_set_fd(ssl, fd))
507 g_warning("Failed to associate socket to SSL stream");
513 SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE |
514 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
516 chan = g_new0(GIOSSLChannel, 1);
518 chan->giochan = handle;
521 chan->server = server;
523 chan->verify = verify;
525 gchan = (GIOChannel *)chan;
526 gchan->funcs = &irssi_ssl_channel_funcs;
527 g_io_channel_init(gchan);
528 gchan->is_readable = gchan->is_writeable = TRUE;
529 gchan->use_buffer = FALSE;
534 GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server)
536 GIOChannel *handle, *ssl_handle;
538 handle = net_connect_ip(ip, port, my_ip);
541 ssl_handle = irssi_ssl_get_iochannel(handle, port, server);
542 if (ssl_handle == NULL)
543 g_io_channel_unref(handle);
547 int irssi_ssl_handshake(GIOChannel *handle)
549 GIOSSLChannel *chan = (GIOSSLChannel *)handle;
554 ret = SSL_connect(chan->ssl);
556 err = SSL_get_error(chan->ssl, ret);
558 case SSL_ERROR_WANT_READ:
560 case SSL_ERROR_WANT_WRITE:
562 case SSL_ERROR_ZERO_RETURN:
563 g_warning("SSL handshake failed: %s", "server closed connection");
565 case SSL_ERROR_SYSCALL:
566 errstr = ERR_reason_error_string(ERR_get_error());
567 if (errstr == NULL && ret == -1)
568 errstr = strerror(errno);
569 g_warning("SSL handshake failed: %s", errstr != NULL ? errstr : "server closed connection unexpectedly");
572 errstr = ERR_reason_error_string(ERR_get_error());
573 g_warning("SSL handshake failed: %s", errstr != NULL ? errstr : "unknown SSL error");
578 cert = SSL_get_peer_certificate(chan->ssl);
580 g_warning("SSL server supplied no certificate");
583 ret = !chan->verify || irssi_ssl_verify(chan->ssl, chan->ctx, chan->server->connrec->address, chan->port, cert, chan->server);
588 #else /* HAVE_OPENSSL */
590 GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server)
592 g_warning("Connection failed: SSL support not enabled in this build.");
597 #endif /* ! HAVE_OPENSSL */