diff options
author | ailin-nemui <ailin-nemui@users.noreply.github.com> | 2016-10-31 15:15:45 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-31 15:15:45 +0100 |
commit | 1652c8a561486c630e573002af7d43a34915c871 (patch) | |
tree | 582199846e88cf93228f42740ac6e08933869979 /src | |
parent | fb78787d4e2098612979b45df3237b67effbbc3a (diff) | |
parent | bc4e2c9ade41182ff643a94bbcb72ffe86b0e67c (diff) | |
download | irssi-1652c8a561486c630e573002af7d43a34915c871.zip |
Merge pull request #557 from irssi/ahf/tls-pr
TLS enhancements
Diffstat (limited to 'src')
-rw-r--r-- | src/core/Makefile.am | 2 | ||||
-rw-r--r-- | src/core/chat-commands.c | 48 | ||||
-rw-r--r-- | src/core/misc.c | 20 | ||||
-rw-r--r-- | src/core/misc.h | 4 | ||||
-rw-r--r-- | src/core/network-openssl.c | 378 | ||||
-rw-r--r-- | src/core/server-connect-rec.h | 18 | ||||
-rw-r--r-- | src/core/server-setup-rec.h | 18 | ||||
-rw-r--r-- | src/core/servers-reconnect.c | 16 | ||||
-rw-r--r-- | src/core/servers-setup.c | 132 | ||||
-rw-r--r-- | src/core/servers.c | 34 | ||||
-rw-r--r-- | src/core/session.c | 19 | ||||
-rw-r--r-- | src/core/tls.c | 214 | ||||
-rw-r--r-- | src/core/tls.h | 90 | ||||
-rw-r--r-- | src/fe-common/core/Makefile.am | 2 | ||||
-rw-r--r-- | src/fe-common/core/fe-common-core.c | 5 | ||||
-rw-r--r-- | src/fe-common/core/fe-server.c | 71 | ||||
-rw-r--r-- | src/fe-common/core/fe-tls.c | 94 | ||||
-rw-r--r-- | src/fe-common/core/fe-tls.h | 25 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.c | 13 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.h | 14 | ||||
-rw-r--r-- | src/fe-common/irc/fe-irc-server.c | 34 | ||||
-rw-r--r-- | src/irc/core/irc-servers.c | 4 | ||||
-rwxr-xr-x | src/perl/get-signals.pl | 1 | ||||
-rw-r--r-- | src/perl/perl-common.c | 3 |
24 files changed, 1004 insertions, 255 deletions
diff --git a/src/core/Makefile.am b/src/core/Makefile.am index af323234..10bd035a 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -46,6 +46,7 @@ libcore_a_SOURCES = \ special-vars.c \ utf8.c \ wcwidth.c \ + tls.c \ write-buffer.c structure_headers = \ @@ -97,5 +98,6 @@ pkginc_core_HEADERS = \ special-vars.h \ utf8.h \ window-item-def.h \ + tls.h \ write-buffer.h \ $(structure_headers) diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c index a9404fa3..c737b810 100644 --- a/src/core/chat-commands.c +++ b/src/core/chat-commands.c @@ -99,27 +99,31 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr, else if (g_hash_table_lookup(optlist, "4") != NULL) conn->family = AF_INET; - if (g_hash_table_lookup(optlist, "ssl") != NULL) - conn->use_ssl = TRUE; - if ((tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL) - conn->ssl_cert = g_strdup(tmp); - if ((tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL) - conn->ssl_pkey = g_strdup(tmp); - if ((tmp = g_hash_table_lookup(optlist, "ssl_pass")) != NULL) - conn->ssl_pass = g_strdup(tmp); - if (g_hash_table_lookup(optlist, "ssl_verify") != NULL) - conn->ssl_verify = TRUE; - if ((tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL) - conn->ssl_cafile = g_strdup(tmp); - if ((tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL) - conn->ssl_capath = g_strdup(tmp); - if ((tmp = g_hash_table_lookup(optlist, "ssl_ciphers")) != NULL) - conn->ssl_ciphers = g_strdup(tmp); - if ((conn->ssl_capath != NULL && conn->ssl_capath[0] != '\0') - || (conn->ssl_cafile != NULL && conn->ssl_cafile[0] != '\0')) - conn->ssl_verify = TRUE; - if ((conn->ssl_cert != NULL && conn->ssl_cert[0] != '\0') || conn->ssl_verify) - conn->use_ssl = TRUE; + if (g_hash_table_lookup(optlist, "tls") != NULL || g_hash_table_lookup(optlist, "ssl") != NULL) + conn->use_tls = TRUE; + if ((tmp = g_hash_table_lookup(optlist, "tls_cert")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL) + conn->tls_cert = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_pkey")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL) + conn->tls_pkey = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_pass")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_pass")) != NULL) + conn->tls_pass = g_strdup(tmp); + if (g_hash_table_lookup(optlist, "tls_verify") != NULL || g_hash_table_lookup(optlist, "ssl_verify") != NULL) + conn->tls_verify = TRUE; + if ((tmp = g_hash_table_lookup(optlist, "tls_cafile")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL) + conn->tls_cafile = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_capath")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL) + conn->tls_capath = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_ciphers")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_ciphers")) != NULL) + conn->tls_ciphers = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_pinned_cert")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_pinned_cert")) != NULL) + conn->tls_pinned_cert = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_pinned_pubkey")) != NULL || (tmp = g_hash_table_lookup(optlist, "ssl_pinned_pubkey")) != NULL) + conn->tls_pinned_pubkey = g_strdup(tmp); + if ((conn->tls_capath != NULL && conn->tls_capath[0] != '\0') + || (conn->tls_cafile != NULL && conn->tls_cafile[0] != '\0')) + conn->tls_verify = TRUE; + if ((conn->tls_cert != NULL && conn->tls_cert[0] != '\0') || conn->tls_verify) + conn->use_tls = TRUE; if (g_hash_table_lookup(optlist, "!") != NULL) conn->no_autojoin_channels = TRUE; @@ -494,7 +498,7 @@ void chat_commands_init(void) signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server); signal_add("server sendmsg", (SIGNAL_FUNC) sig_server_sendmsg); - command_set_options("connect", "4 6 !! -network ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers +host noproxy -rawlog noautosendcmd"); + command_set_options("connect", "4 6 !! -network ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers +ssl_pinned_cert +ssl_pinned_pubkey tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_ciphers +tls_pinned_cert +tls_pinned_pubkey +host noproxy -rawlog noautosendcmd"); command_set_options("msg", "channel nick"); } diff --git a/src/core/misc.c b/src/core/misc.c index bc9f504e..0bb1f7e6 100644 --- a/src/core/misc.c +++ b/src/core/misc.c @@ -930,3 +930,23 @@ char **strsplit_len(const char *str, int len, gboolean onspace) return ret; } + +char *binary_to_hex(unsigned char *buffer, size_t size) +{ + static const char hex[] = "0123456789ABCDEF"; + char *result = NULL; + int i; + + if (buffer == NULL || size == 0) + return NULL; + + result = g_malloc(3 * size); + + for (i = 0; i < size; i++) { + result[i * 3 + 0] = hex[(buffer[i] >> 4) & 0xf]; + result[i * 3 + 1] = hex[(buffer[i] >> 0) & 0xf]; + result[i * 3 + 2] = i == size - 1 ? '\0' : ':'; + } + + return result; +} diff --git a/src/core/misc.h b/src/core/misc.h index c095e131..00637da0 100644 --- a/src/core/misc.h +++ b/src/core/misc.h @@ -109,4 +109,8 @@ int find_substr(const char *list, const char *item); /* split `str' into `len' sized substrings */ char **strsplit_len(const char *str, int len, gboolean onspace); +/* Convert a given buffer to a printable, colon-delimited, hex string and + * return a pointer to the newly allocated buffer */ +char *binary_to_hex(unsigned char *buffer, size_t size); + #endif diff --git a/src/core/network-openssl.c b/src/core/network-openssl.c index a18e6fc7..7a1d6e34 100644 --- a/src/core/network-openssl.c +++ b/src/core/network-openssl.c @@ -22,8 +22,8 @@ #include "network.h" #include "misc.h" #include "servers.h" - -#ifdef HAVE_OPENSSL +#include "signals.h" +#include "tls.h" #include <openssl/crypto.h> #include <openssl/x509.h> @@ -32,11 +32,6 @@ #include <openssl/ssl.h> #include <openssl/err.h> -#ifdef HAVE_DANE -#include <validator/validator.h> -#include <validator/val_dane.h> -#endif - /* ssl i/o channel object */ typedef struct { @@ -203,78 +198,13 @@ static gboolean irssi_ssl_verify_hostname(X509 *cert, const char *hostname) return matched; } -static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, const char* hostname, int port, X509 *cert, SERVER_REC *server) +static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, const char* hostname, int port, X509 *cert, SERVER_REC *server, TLS_REC *tls_rec) { long result; -#ifdef HAVE_DANE - int dane_ret; - struct val_daneparams daneparams; - struct val_danestatus *danestatus = NULL; - - // Check if a TLSA record is available. - daneparams.port = port; - daneparams.proto = DANE_PARAM_PROTO_TCP; - - dane_ret = val_getdaneinfo(NULL, hostname, &daneparams, &danestatus); - - if (dane_ret == VAL_DANE_NOERROR) { - signal_emit("tlsa available", 1, server); - } - - if (danestatus != NULL) { - int do_certificate_check = 1; - - if (val_dane_check(NULL, ssl, danestatus, &do_certificate_check) != VAL_DANE_NOERROR) { - g_warning("DANE: TLSA record for hostname %s port %d could not be verified", hostname, port); - signal_emit("tlsa verification failed", 1, server); - val_free_dane(danestatus); - return FALSE; - } - - signal_emit("tlsa verification success", 1, server); - val_free_dane(danestatus); - - if (do_certificate_check == 0) { - return TRUE; - } - } -#endif result = SSL_get_verify_result(ssl); if (result != X509_V_OK) { - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned int n; - char *str; - - g_warning("Could not verify SSL servers certificate: %s", - X509_verify_cert_error_string(result)); - if ((str = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) == NULL) - g_warning(" Could not get subject-name from peer certificate"); - else { - g_warning(" Subject : %s", str); - free(str); - } - if ((str = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)) == NULL) - g_warning(" Could not get issuer-name from peer certificate"); - else { - g_warning(" Issuer : %s", str); - free(str); - } - if (! X509_digest(cert, EVP_md5(), md, &n)) - g_warning(" Could not get fingerprint from peer certificate"); - else { - char hex[] = "0123456789ABCDEF"; - char fp[EVP_MAX_MD_SIZE*3]; - if (n < sizeof(fp)) { - unsigned int i; - for (i = 0; i < n; i++) { - fp[i*3+0] = hex[(md[i] >> 4) & 0xF]; - fp[i*3+1] = hex[(md[i] >> 0) & 0xF]; - fp[i*3+2] = i == n - 1 ? '\0' : ':'; - } - g_warning(" MD5 Fingerprint : %s", fp); - } - } + g_warning("Could not verify TLS servers certificate: %s", X509_verify_cert_error_string(result)); return FALSE; } else if (! irssi_ssl_verify_hostname(cert, hostname)){ return FALSE; @@ -457,13 +387,13 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_ SSL *ssl; SSL_CTX *ctx = NULL; - const char *mycert = server->connrec->ssl_cert; - const char *mypkey = server->connrec->ssl_pkey; - const char *mypass = server->connrec->ssl_pass; - const char *cafile = server->connrec->ssl_cafile; - const char *capath = server->connrec->ssl_capath; - const char *ciphers = server->connrec->ssl_ciphers; - gboolean verify = server->connrec->ssl_verify; + const char *mycert = server->connrec->tls_cert; + const char *mypkey = server->connrec->tls_pkey; + const char *mypass = server->connrec->tls_pass; + const char *cafile = server->connrec->tls_cafile; + const char *capath = server->connrec->tls_capath; + const char *ciphers = server->connrec->tls_ciphers; + gboolean verify = server->connrec->tls_verify; g_return_val_if_fail(handle != NULL, NULL); @@ -482,7 +412,8 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); SSL_CTX_set_default_passwd_cb(ctx, get_pem_password_callback); SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)mypass); - if (ciphers && *ciphers) { + + if (ciphers != NULL && ciphers[0] != '\0') { if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) g_warning("No valid SSL cipher suite could be selected"); } @@ -511,7 +442,7 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_ if (capath && *capath) scapath = convert_home(capath); if (! SSL_CTX_load_verify_locations(ctx, scafile, scapath)) { - g_warning("Could not load CA list for verifying SSL server certificate"); + g_warning("Could not load CA list for verifying TLS server certificate"); g_free(scafile); g_free(scapath); SSL_CTX_free(ctx); @@ -565,6 +496,192 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_ return gchan; } +static void set_cipher_info(TLS_REC *tls, SSL *ssl) +{ + g_return_if_fail(tls != NULL); + g_return_if_fail(ssl != NULL); + + tls_rec_set_protocol_version(tls, SSL_get_version(ssl)); + + tls_rec_set_cipher(tls, SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))); + tls_rec_set_cipher_size(tls, SSL_get_cipher_bits(ssl, NULL)); +} + +static void set_pubkey_info(TLS_REC *tls, X509 *cert, unsigned char *cert_fingerprint, size_t cert_fingerprint_size, unsigned char *public_key_fingerprint, size_t public_key_fingerprint_size) +{ + g_return_if_fail(tls != NULL); + g_return_if_fail(cert != NULL); + + EVP_PKEY *pubkey = NULL; + char *cert_fingerprint_hex = NULL; + char *public_key_fingerprint_hex = NULL; + + BIO *bio = NULL; + char buffer[128]; + size_t length; + + pubkey = X509_get_pubkey(cert); + + cert_fingerprint_hex = binary_to_hex(cert_fingerprint, cert_fingerprint_size); + tls_rec_set_certificate_fingerprint(tls, cert_fingerprint_hex); + tls_rec_set_certificate_fingerprint_algorithm(tls, "SHA256"); + + // Show algorithm. + switch (EVP_PKEY_id(pubkey)) { + case EVP_PKEY_RSA: + tls_rec_set_public_key_algorithm(tls, "RSA"); + break; + + case EVP_PKEY_DSA: + tls_rec_set_public_key_algorithm(tls, "DSA"); + break; + + case EVP_PKEY_EC: + tls_rec_set_public_key_algorithm(tls, "EC"); + break; + + default: + tls_rec_set_public_key_algorithm(tls, "Unknown"); + break; + } + + public_key_fingerprint_hex = binary_to_hex(public_key_fingerprint, public_key_fingerprint_size); + tls_rec_set_public_key_fingerprint(tls, public_key_fingerprint_hex); + tls_rec_set_public_key_size(tls, EVP_PKEY_bits(pubkey)); + tls_rec_set_public_key_fingerprint_algorithm(tls, "SHA256"); + + // Read the NotBefore timestamp. + bio = BIO_new(BIO_s_mem()); + ASN1_TIME_print(bio, X509_get_notBefore(cert)); + length = BIO_read(bio, buffer, sizeof(buffer)); + buffer[length] = '\0'; + BIO_free(bio); + tls_rec_set_not_before(tls, buffer); + + // Read the NotAfter timestamp. + bio = BIO_new(BIO_s_mem()); + ASN1_TIME_print(bio, X509_get_notAfter(cert)); + length = BIO_read(bio, buffer, sizeof(buffer)); + buffer[length] = '\0'; + BIO_free(bio); + tls_rec_set_not_after(tls, buffer); + + g_free(cert_fingerprint_hex); + g_free(public_key_fingerprint_hex); + EVP_PKEY_free(pubkey); +} + +static void set_peer_cert_chain_info(TLS_REC *tls, SSL *ssl) +{ + g_return_if_fail(tls != NULL); + g_return_if_fail(ssl != NULL); + + int nid; + char *key = NULL; + char *value = NULL; + STACK_OF(X509) *chain = NULL; + int i; + int j; + TLS_CERT_REC *cert_rec = NULL; + X509_NAME *name = NULL; + X509_NAME_ENTRY *entry = NULL; + TLS_CERT_ENTRY_REC *tls_cert_entry_rec = NULL; + ASN1_STRING *data = NULL; + + chain = SSL_get_peer_cert_chain(ssl); + + if (chain == NULL) + return; + + for (i = 0; i < sk_X509_num(chain); i++) { + cert_rec = tls_cert_create_rec(); + + // Subject. + name = X509_get_subject_name(sk_X509_value(chain, i)); + + for (j = 0; j < X509_NAME_entry_count(name); j++) { + entry = X509_NAME_get_entry(name, j); + + nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry)); + key = (char *)OBJ_nid2sn(nid); + + if (key == NULL) + key = (char *)OBJ_nid2ln(nid); + + data = X509_NAME_ENTRY_get_data(entry); + value = (char *)ASN1_STRING_data(data); + + tls_cert_entry_rec = tls_cert_entry_create_rec(key, value); + tls_cert_rec_append_subject_entry(cert_rec, tls_cert_entry_rec); + } + + // Issuer. + name = X509_get_issuer_name(sk_X509_value(chain, i)); + + for (j = 0; j < X509_NAME_entry_count(name); j++) { + entry = X509_NAME_get_entry(name, j); + + nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry)); + key = (char *)OBJ_nid2sn(nid); + + if (key == NULL) + key = (char *)OBJ_nid2ln(nid); + + data = X509_NAME_ENTRY_get_data(entry); + value = (char *)ASN1_STRING_data(data); + + tls_cert_entry_rec = tls_cert_entry_create_rec(key, value); + tls_cert_rec_append_issuer_entry(cert_rec, tls_cert_entry_rec); + } + + tls_rec_append_cert(tls, cert_rec); + } +} + +static void set_server_temporary_key_info(TLS_REC *tls, SSL *ssl) +{ + g_return_if_fail(tls != NULL); + g_return_if_fail(ssl != NULL); + +#ifdef SSL_get_server_tmp_key + // Show ephemeral key information. + EVP_PKEY *ephemeral_key = NULL; + EC_KEY *ec_key = NULL; + char *ephemeral_key_algorithm = NULL; + char *cname = NULL; + int nid; + + if (SSL_get_server_tmp_key(ssl, &ephemeral_key)) { + switch (EVP_PKEY_id(ephemeral_key)) { + case EVP_PKEY_DH: + tls_rec_set_ephemeral_key_algorithm(tls, "DH"); + tls_rec_set_ephemeral_key_size(tls, EVP_PKEY_bits(ephemeral_key)); + break; + + case EVP_PKEY_EC: + ec_key = EVP_PKEY_get1_EC_KEY(ephemeral_key); + nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); + EC_KEY_free(ec_key); + cname = (char *)OBJ_nid2sn(nid); + ephemeral_key_algorithm = g_strdup_printf("ECDH: %s", cname); + + tls_rec_set_ephemeral_key_algorithm(tls, ephemeral_key_algorithm); + tls_rec_set_ephemeral_key_size(tls, EVP_PKEY_bits(ephemeral_key)); + + g_free_and_null(ephemeral_key_algorithm); + break; + + default: + tls_rec_set_ephemeral_key_algorithm(tls, "Unknown"); + tls_rec_set_ephemeral_key_size(tls, EVP_PKEY_bits(ephemeral_key)); + break; + } + + EVP_PKEY_free(ephemeral_key); + } +#endif // SSL_get_server_tmp_key. +} + GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server) { GIOChannel *handle, *ssl_handle; @@ -582,8 +699,19 @@ int irssi_ssl_handshake(GIOChannel *handle) { GIOSSLChannel *chan = (GIOSSLChannel *)handle; int ret, err; - X509 *cert; - const char *errstr; + const char *errstr = NULL; + X509 *cert = NULL; + X509_PUBKEY *pubkey = NULL; + int pubkey_size = 0; + unsigned char *pubkey_der = NULL; + unsigned char *pubkey_der_tmp = NULL; + unsigned char pubkey_fingerprint[EVP_MAX_MD_SIZE]; + unsigned int pubkey_fingerprint_size; + unsigned char cert_fingerprint[EVP_MAX_MD_SIZE]; + unsigned int cert_fingerprint_size; + const char *pinned_cert_fingerprint = chan->server->connrec->tls_pinned_cert; + const char *pinned_pubkey_fingerprint = chan->server->connrec->tls_pinned_pubkey; + TLS_REC *tls = NULL; ERR_clear_error(); ret = SSL_connect(chan->ssl); @@ -611,22 +739,74 @@ int irssi_ssl_handshake(GIOChannel *handle) } cert = SSL_get_peer_certificate(chan->ssl); + pubkey = X509_get_X509_PUBKEY(cert); + if (cert == NULL) { - g_warning("SSL server supplied no certificate"); - return -1; + g_warning("TLS server supplied no certificate"); + ret = 0; + goto done; } - ret = !chan->verify || irssi_ssl_verify(chan->ssl, chan->ctx, chan->server->connrec->address, chan->port, cert, chan->server); - X509_free(cert); - return ret ? 0 : -1; -} -#else /* HAVE_OPENSSL */ + if (pubkey == NULL) { + g_warning("TLS server supplied no certificate public key"); + ret = 0; + goto done; + } -GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server) -{ - g_warning("Connection failed: SSL support not enabled in this build."); - errno = ENOSYS; - return NULL; -} + if (! X509_digest(cert, EVP_sha256(), cert_fingerprint, &cert_fingerprint_size)) { + g_warning("Unable to generate certificate fingerprint"); + ret = 0; + goto done; + } + + pubkey_size = i2d_X509_PUBKEY(pubkey, NULL); + pubkey_der = pubkey_der_tmp = g_new(unsigned char, pubkey_size); + i2d_X509_PUBKEY(pubkey, &pubkey_der_tmp); + + EVP_Digest(pubkey_der, pubkey_size, pubkey_fingerprint, &pubkey_fingerprint_size, EVP_sha256(), 0); + + tls = tls_create_rec(); + set_cipher_info(tls, chan->ssl); + set_pubkey_info(tls, cert, cert_fingerprint, cert_fingerprint_size, pubkey_fingerprint, pubkey_fingerprint_size); + set_peer_cert_chain_info(tls, chan->ssl); + set_server_temporary_key_info(tls, chan->ssl); + + // Emit the TLS rec. + signal_emit("tls handshake finished", 2, chan->server, tls); + + ret = 1; + + if (pinned_cert_fingerprint != NULL && pinned_cert_fingerprint[0] != '\0') { + ret = g_ascii_strcasecmp(pinned_cert_fingerprint, tls->certificate_fingerprint) == 0; + + if (! ret) { + g_warning(" Pinned certificate mismatch"); + goto done; + } + } -#endif /* ! HAVE_OPENSSL */ + if (pinned_pubkey_fingerprint != NULL && pinned_pubkey_fingerprint[0] != '\0') { + ret = g_ascii_strcasecmp(pinned_pubkey_fingerprint, tls->public_key_fingerprint) == 0; + + if (! ret) { + g_warning(" Pinned public key mismatch"); + goto done; + } + } + + if (chan->verify) { + ret = irssi_ssl_verify(chan->ssl, chan->ctx, chan->server->connrec->address, chan->port, cert, chan->server, tls); + + if (! ret) { + // irssi_ssl_verify emits a warning itself. + goto done; + } + } + +done: + tls_rec_free(tls); + X509_free(cert); + g_free(pubkey_der); + + return ret ? 0 : -1; +} diff --git a/src/core/server-connect-rec.h b/src/core/server-connect-rec.h index 80c5761b..fa348769 100644 --- a/src/core/server-connect-rec.h +++ b/src/core/server-connect-rec.h @@ -23,12 +23,14 @@ char *nick; char *username; char *realname; -char *ssl_cert; -char *ssl_pkey; -char *ssl_pass; -char *ssl_cafile; -char *ssl_capath; -char *ssl_ciphers; +char *tls_cert; +char *tls_pkey; +char *tls_pass; +char *tls_cafile; +char *tls_capath; +char *tls_ciphers; +char *tls_pinned_cert; +char *tls_pinned_pubkey; GIOChannel *connect_handle; /* connect using this handle */ @@ -38,8 +40,8 @@ unsigned int reconnecting:1; /* we're trying to reconnect any connection */ unsigned int no_autojoin_channels:1; /* don't autojoin any channels */ unsigned int no_autosendcmd:1; /* don't execute autosendcmd */ unsigned int unix_socket:1; /* Connect using named unix socket */ -unsigned int use_ssl:1; /* this connection uses SSL */ -unsigned int ssl_verify:1; +unsigned int use_tls:1; /* this connection uses TLS */ +unsigned int tls_verify:1; unsigned int no_connect:1; /* don't connect() at all, it's done by plugin */ char *channels; char *away_reason; diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h index 2c9614c7..e6b0431c 100644 --- a/src/core/server-setup-rec.h +++ b/src/core/server-setup-rec.h @@ -11,12 +11,14 @@ char *password; int sasl_mechanism; char *sasl_password; -char *ssl_cert; -char *ssl_pkey; -char *ssl_pass; -char *ssl_cafile; -char *ssl_capath; -char *ssl_ciphers; +char *tls_cert; +char *tls_pkey; +char *tls_pass; +char *tls_cafile; +char *tls_capath; +char *tls_ciphers; +char *tls_pinned_cert; +char *tls_pinned_pubkey; char *own_host; /* address to use when connecting this server */ IPADDR *own_ip4, *own_ip6; /* resolved own_address if not NULL */ @@ -28,7 +30,7 @@ unsigned int no_proxy:1; unsigned int last_failed:1; /* if last connection attempt failed */ unsigned int banned:1; /* if we're banned from this server */ unsigned int dns_error:1; /* DNS said the host doesn't exist */ -unsigned int use_ssl:1; /* this connection uses SSL */ -unsigned int ssl_verify:1; +unsigned int use_tls:1; /* this connection uses TLS */ +unsigned int tls_verify:1; GHashTable *module_data; diff --git a/src/core/servers-reconnect.c b/src/core/servers-reconnect.c index 58c9dd09..1727704c 100644 --- a/src/core/servers-reconnect.c +++ b/src/core/servers-reconnect.c @@ -192,13 +192,15 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info) dest->no_autosendcmd = src->no_autosendcmd; dest->unix_socket = src->unix_socket; - dest->use_ssl = src->use_ssl; - dest->ssl_cert = g_strdup(src->ssl_cert); - dest->ssl_pkey = g_strdup(src->ssl_pkey); - dest->ssl_verify = src->ssl_verify; - dest->ssl_cafile = g_strdup(src->ssl_cafile); - dest->ssl_capath = g_strdup(src->ssl_capath); - dest->ssl_ciphers = g_strdup(src->ssl_ciphers); + dest->use_tls = src->use_tls; + dest->tls_cert = g_strdup(src->tls_cert); + dest->tls_pkey = g_strdup(src->tls_pkey); + dest->tls_verify = src->tls_verify; + dest->tls_cafile = g_strdup(src->tls_cafile); + dest->tls_capath = g_strdup(src->tls_capath); + dest->tls_ciphers = g_strdup(src->tls_ciphers); + dest->tls_pinned_cert = g_strdup(src->tls_pinned_cert); + dest->tls_pinned_pubkey = g_strdup(src->tls_pinned_pubkey); return dest; } diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c index 0cecfece..9492c58c 100644 --- a/src/core/servers-setup.c +++ b/src/core/servers-setup.c @@ -167,20 +167,24 @@ static void server_setup_fill_server(SERVER_CONNECT_REC *conn, if (sserver->port > 0 && conn->port <= 0) conn->port = sserver->port; - conn->use_ssl = sserver->use_ssl; - if (conn->ssl_cert == NULL && sserver->ssl_cert != NULL && sserver->ssl_cert[0] != '\0') - conn->ssl_cert = g_strdup(sserver->ssl_cert); - if (conn->ssl_pkey == NULL && sserver->ssl_pkey != NULL && sserver->ssl_pkey[0] != '\0') - conn->ssl_pkey = g_strdup(sserver->ssl_pkey); - if (conn->ssl_pass == NULL && sserver->ssl_pass != NULL && sserver->ssl_pass[0] != '\0') - conn->ssl_pass = g_strdup(sserver->ssl_pass); - conn->ssl_verify = sserver->ssl_verify; - if (conn->ssl_cafile == NULL && sserver->ssl_cafile != NULL && sserver->ssl_cafile[0] != '\0') - conn->ssl_cafile = g_strdup(sserver->ssl_cafile); - if (conn->ssl_capath == NULL && sserver->ssl_capath != NULL && sserver->ssl_capath[0] != '\0') - conn->ssl_capath = g_strdup(sserver->ssl_capath); - if (conn->ssl_ciphers == NULL && sserver->ssl_ciphers != NULL && sserver->ssl_ciphers[0] != '\0') - conn->ssl_ciphers = g_strdup(sserver->ssl_ciphers); + conn->use_tls = sserver->use_tls; + if (conn->tls_cert == NULL && sserver->tls_cert != NULL && sserver->tls_cert[0] != '\0') + conn->tls_cert = g_strdup(sserver->tls_cert); + if (conn->tls_pkey == NULL && sserver->tls_pkey != NULL && sserver->tls_pkey[0] != '\0') + conn->tls_pkey = g_strdup(sserver->tls_pkey); + if (conn->tls_pass == NULL && sserver->tls_pass != NULL && sserver->tls_pass[0] != '\0') + conn->tls_pass = g_strdup(sserver->tls_pass); + conn->tls_verify = sserver->tls_verify; + if (conn->tls_cafile == NULL && sserver->tls_cafile != NULL && sserver->tls_cafile[0] != '\0') + conn->tls_cafile = g_strdup(sserver->tls_cafile); + if (conn->tls_capath == NULL && sserver->tls_capath != NULL && sserver->tls_capath[0] != '\0') + conn->tls_capath = g_strdup(sserver->tls_capath); + if (conn->tls_ciphers == NULL && sserver->tls_ciphers != NULL && sserver->tls_ciphers[0] != '\0') + conn->tls_ciphers = g_strdup(sserver->tls_ciphers); + if (conn->tls_pinned_cert == NULL && sserver->tls_pinned_cert != NULL && sserver->tls_pinned_cert[0] != '\0') + conn->tls_pinned_cert = g_strdup(sserver->tls_pinned_cert); + if (conn->tls_pinned_pubkey == NULL && sserver->tls_pinned_pubkey != NULL && sserver->tls_pinned_pubkey[0] != '\0') + conn->tls_pinned_pubkey = g_strdup(sserver->tls_pinned_pubkey); server_setup_fill_reconn(conn, sserver); @@ -362,9 +366,10 @@ SERVER_SETUP_REC *server_setup_find(const char *address, int port, static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node) { SERVER_SETUP_REC *rec; - CHATNET_REC *chatnetrec; + CHATNET_REC *chatnetrec; char *server, *chatnet, *family; int port; + char *value = NULL; g_return_val_if_fail(node != NULL, NULL); @@ -390,7 +395,7 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node) chatnet_create(chatnetrec); } - family = config_node_get_str(node, "family", ""); + family = config_node_get_str(node, "family", ""); rec = CHAT_PROTOCOL(chatnetrec)->create_server_setup(); rec->type = module_get_uniq_id("SERVER SETUP", 0); @@ -400,18 +405,55 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node) (g_ascii_strcasecmp(family, "inet") == 0 ? AF_INET : 0); rec->address = g_strdup(server); rec->password = g_strdup(config_node_get_str(node, "password", NULL)); - rec->use_ssl = config_node_get_bool(node, "use_ssl", FALSE); - rec->ssl_cert = g_strdup(config_node_get_str(node, "ssl_cert", NULL)); - rec->ssl_pkey = g_strdup(config_node_get_str(node, "ssl_pkey", NULL)); - rec->ssl_pass = g_strdup(config_node_get_str(node, "ssl_pass", NULL)); - rec->ssl_verify = config_node_get_bool(node, "ssl_verify", FALSE); - rec->ssl_cafile = g_strdup(config_node_get_str(node, "ssl_cafile", NULL)); - rec->ssl_capath = g_strdup(config_node_get_str(node, "ssl_capath", NULL)); - rec->ssl_ciphers = g_strdup(config_node_get_str(node, "ssl_ciphers", NULL)); - if (rec->ssl_cafile || rec->ssl_capath) - rec->ssl_verify = TRUE; - if (rec->ssl_cert != NULL || rec->ssl_verify) - rec->use_ssl = TRUE; + + rec->use_tls = config_node_get_bool(node, "use_tls", FALSE) || config_node_get_bool(node, "use_ssl", FALSE); + rec->tls_verify = config_node_get_bool(node, "tls_verify", FALSE) || config_node_get_bool(node, "ssl_verify", FALSE); + + value = config_node_get_str(node, "tls_cert", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_cert", NULL); + rec->tls_cert = g_strdup(value); + + value = config_node_get_str(node, "tls_pkey", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_pkey", NULL); + rec->tls_pkey = g_strdup(value); + + value = config_node_get_str(node, "tls_pass", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_pass", NULL); + rec->tls_pass = g_strdup(value); + + value = config_node_get_str(node, "tls_cafile", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_cafile", NULL); + rec->tls_cafile = g_strdup(value); + + value = config_node_get_str(node, "tls_capath", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_capath", NULL); + rec->tls_capath = g_strdup(value); + + value = config_node_get_str(node, "tls_ciphers", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_ciphers", NULL); + rec->tls_ciphers = g_strdup(value); + + value = config_node_get_str(node, "tls_pinned_cert", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_pinned_cert", NULL); + rec->tls_pinned_cert = g_strdup(value); + + value = config_node_get_str(node, "tls_pinned_pubkey", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_pinned_pubkey", NULL); + rec->tls_pinned_pubkey = g_strdup(value); + + if (rec->tls_cafile || rec->tls_capath) + rec->tls_verify = TRUE; + if (rec->tls_cert != NULL || rec->tls_verify) + rec->use_tls = TRUE; + rec->port = port; rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE); rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE); @@ -463,14 +505,18 @@ static void server_setup_save(SERVER_SETUP_REC *rec) iconfig_node_set_int(node, "port", rec->port); iconfig_node_set_str(node, "password", rec->password); - iconfig_node_set_bool(node, "use_ssl", rec->use_ssl); - iconfig_node_set_str(node, "ssl_cert", rec->ssl_cert); - iconfig_node_set_str(node, "ssl_pkey", rec->ssl_pkey); - iconfig_node_set_str(node, "ssl_pass", rec->ssl_pass); - iconfig_node_set_bool(node, "ssl_verify", rec->ssl_verify); - iconfig_node_set_str(node, "ssl_cafile", rec->ssl_cafile); - iconfig_node_set_str(node, "ssl_capath", rec->ssl_capath); - iconfig_node_set_str(node, "ssl_ciphers", rec->ssl_ciphers); + + iconfig_node_set_bool(node, "use_tls", rec->use_tls); + iconfig_node_set_str(node, "tls_cert", rec->tls_cert); + iconfig_node_set_str(node, "tls_pkey", rec->tls_pkey); + iconfig_node_set_str(node, "tls_pass", rec->tls_pass); + iconfig_node_set_bool(node, "tls_verify", rec->tls_verify); + iconfig_node_set_str(node, "tls_cafile", rec->tls_cafile); + iconfig_node_set_str(node, "tls_capath", rec->tls_capath); + iconfig_node_set_str(node, "tls_ciphers", rec->tls_ciphers); + iconfig_node_set_str(node, "tls_pinned_cert", rec->tls_pinned_cert); + iconfig_node_set_str(node, "tls_pinned_pubkey", rec->tls_pinned_pubkey); + iconfig_node_set_str(node, "own_host", rec->own_host); iconfig_node_set_str(node, "family", @@ -514,12 +560,14 @@ static void server_setup_destroy(SERVER_SETUP_REC *rec) g_free_not_null(rec->own_ip6); g_free_not_null(rec->chatnet); g_free_not_null(rec->password); - g_free_not_null(rec->ssl_cert); - g_free_not_null(rec->ssl_pkey); - g_free_not_null(rec->ssl_pass); - g_free_not_null(rec->ssl_cafile); - g_free_not_null(rec->ssl_capath); - g_free_not_null(rec->ssl_ciphers); + g_free_not_null(rec->tls_cert); + g_free_not_null(rec->tls_pkey); + g_free_not_null(rec->tls_pass); + g_free_not_null(rec->tls_cafile); + g_free_not_null(rec->tls_capath); + g_free_not_null(rec->tls_ciphers); + g_free_not_null(rec->tls_pinned_cert); + g_free_not_null(rec->tls_pinned_pubkey); g_free(rec->address); g_free(rec); } diff --git a/src/core/servers.c b/src/core/servers.c index d6297c4d..b9faab81 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -167,7 +167,6 @@ static void server_connect_callback_init(SERVER_REC *server, GIOChannel *handle) server_connect_finished(server); } -#ifdef HAVE_OPENSSL static void server_connect_callback_init_ssl(SERVER_REC *server, GIOChannel *handle) { int error; @@ -198,7 +197,6 @@ static void server_connect_callback_init_ssl(SERVER_REC *server, GIOChannel *han server_connect_finished(server); } -#endif static void server_real_connect(SERVER_REC *server, IPADDR *ip, const char *unix_socket) @@ -221,7 +219,7 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip, own_ip = IPADDR_IS_V6(ip) ? server->connrec->own_ip6 : server->connrec->own_ip4; port = server->connrec->proxy != NULL ? server->connrec->proxy_port : server->connrec->port; - handle = server->connrec->use_ssl ? + handle = server->connrec->use_tls ? net_connect_ip_ssl(ip, port, own_ip, server) : net_connect_ip(ip, port, own_ip); } else { handle = net_connect_unix(unix_socket); @@ -239,7 +237,7 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip, } server->no_reconnect = TRUE; } - if (server->connrec->use_ssl && errno == ENOSYS) + if (server->connrec->use_tls && errno == ENOSYS) server->no_reconnect = TRUE; server->connection_lost = TRUE; @@ -247,11 +245,9 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip, g_free(errmsg2); } else { server->handle = net_sendbuffer_create(handle, 0); -#ifdef HAVE_OPENSSL - if (server->connrec->use_ssl) + if (server->connrec->use_tls) server_connect_callback_init_ssl(server, handle); else -#endif server->connect_tag = g_input_add(handle, G_INPUT_WRITE | G_INPUT_READ, (GInputFunction) @@ -626,22 +622,24 @@ void server_connect_unref(SERVER_CONNECT_REC *conn) g_free_not_null(conn->own_ip4); g_free_not_null(conn->own_ip6); - g_free_not_null(conn->password); - g_free_not_null(conn->nick); - g_free_not_null(conn->username); + g_free_not_null(conn->password); + g_free_not_null(conn->nick); + g_free_not_null(conn->username); g_free_not_null(conn->realname); - g_free_not_null(conn->ssl_cert); - g_free_not_null(conn->ssl_pkey); - g_free_not_null(conn->ssl_pass); - g_free_not_null(conn->ssl_cafile); - g_free_not_null(conn->ssl_capath); - g_free_not_null(conn->ssl_ciphers); + g_free_not_null(conn->tls_cert); + g_free_not_null(conn->tls_pkey); + g_free_not_null(conn->tls_pass); + g_free_not_null(conn->tls_cafile); + g_free_not_null(conn->tls_capath); + g_free_not_null(conn->tls_ciphers); + g_free_not_null(conn->tls_pinned_cert); + g_free_not_null(conn->tls_pinned_pubkey); g_free_not_null(conn->channels); - g_free_not_null(conn->away_reason); + g_free_not_null(conn->away_reason); - conn->type = 0; + conn->type = 0; g_free(conn); } diff --git a/src/core/session.c b/src/core/session.c index 17d80076..34190c52 100644 --- a/src/core/session.c +++ b/src/core/session.c @@ -150,8 +150,7 @@ static void session_save_server(SERVER_REC *server, CONFIG_REC *config, node = config_node_section(config, node, NULL, NODE_TYPE_BLOCK); - config_node_set_str(config, node, "chat_type", - chat_protocol_find_id(server->chat_type)->name); + config_node_set_str(config, node, "chat_type", chat_protocol_find_id(server->chat_type)->name); config_node_set_str(config, node, "address", server->connrec->address); config_node_set_int(config, node, "port", server->connrec->port); config_node_set_str(config, node, "chatnet", server->connrec->chatnet); @@ -159,13 +158,15 @@ static void session_save_server(SERVER_REC *server, CONFIG_REC *config, config_node_set_str(config, node, "nick", server->nick); config_node_set_str(config, node, "version", server->version); - config_node_set_bool(config, node, "use_ssl", server->connrec->use_ssl); - config_node_set_str(config, node, "ssl_cert", server->connrec->ssl_cert); - config_node_set_str(config, node, "ssl_pkey", server->connrec->ssl_pkey); - config_node_set_bool(config, node, "ssl_verify", server->connrec->ssl_verify); - config_node_set_str(config, node, "ssl_cafile", server->connrec->ssl_cafile); - config_node_set_str(config, node, "ssl_capath", server->connrec->ssl_capath); - config_node_set_str(config, node, "ssl_ciphers", server->connrec->ssl_ciphers); + config_node_set_bool(config, node, "use_tls", server->connrec->use_tls); + config_node_set_str(config, node, "tls_cert", server->connrec->tls_cert); + config_node_set_str(config, node, "tls_pkey", server->connrec->tls_pkey); + config_node_set_bool(config, node, "tls_verify", server->connrec->tls_verify); + config_node_set_str(config, node, "tls_cafile", server->connrec->tls_cafile); + config_node_set_str(config, node, "tls_capath", server->connrec->tls_capath); + config_node_set_str(config, node, "tls_ciphers", server->connrec->tls_ciphers); + config_node_set_str(config, node, "tls_pinned_cert", server->connrec->tls_pinned_cert); + config_node_set_str(config, node, "tls_pinned_pubkey", server->connrec->tls_pinned_pubkey); handle = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle)); config_node_set_int(config, node, "handle", handle); diff --git a/src/core/tls.c b/src/core/tls.c new file mode 100644 index 00000000..3bddd773 --- /dev/null +++ b/src/core/tls.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2015 Alexander Færøy <ahf@irssi.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA + */ + +#include "module.h" + +#include "tls.h" + +TLS_REC *tls_create_rec() +{ + TLS_REC *rec = g_new0(TLS_REC, 1); + g_return_val_if_fail(rec != NULL, NULL); + + return rec; +} + +void tls_rec_free(TLS_REC *tls_rec) +{ + if (tls_rec == NULL) + return; + + g_free_and_null(tls_rec->protocol_version); + g_free_and_null(tls_rec->cipher); + g_free_and_null(tls_rec->public_key_algorithm); + g_free_and_null(tls_rec->public_key_fingerprint); + g_free_and_null(tls_rec->public_key_fingerprint_algorithm); + g_free_and_null(tls_rec->certificate_fingerprint); + g_free_and_null(tls_rec->certificate_fingerprint_algorithm); + g_free_and_null(tls_rec->not_after); + g_free_and_null(tls_rec->not_before); + g_free_and_null(tls_rec->ephemeral_key_algorithm); + + if (tls_rec->certs != NULL) { + g_slist_foreach(tls_rec->certs, (GFunc)tls_cert_rec_free, NULL); + g_slist_free(tls_rec->certs); + tls_rec->certs = NULL; + } + + g_free(tls_rec); +} + +void tls_rec_set_protocol_version(TLS_REC *tls_rec, const char *protocol_version) +{ + g_return_if_fail(tls_rec != NULL); + + tls_rec->protocol_version = g_strdup(protocol_version); +} + +void tls_rec_set_cipher(TLS_REC *tls_rec, const char *cipher) +{ + g_return_if_fail(tls_rec != NULL); + + tls_rec->cipher = g_strdup(cipher); +} + +void tls_rec_set_cipher_size(TLS_REC *tls_rec, size_t size) +{ + g_return_if_fail(tls_rec != NULL); + + tls_rec->cipher_size = size; +} + +void tls_rec_set_public_key_algorithm(TLS_REC *tls_rec, const char *algorithm) +{ + g_return_if_fail(tls_rec != NULL); + + tls_rec->public_key_algorithm = g_strdup(algorithm); +} + +void tls_rec_set_public_key_fingerprint(TLS_REC *tls_rec, const char *fingerprint) +{ + g_return_if_fail(tls_rec != NULL); + + tls_rec->public_key_fingerprint = g_strdup(fingerprint); +} + +void tls_rec_set_public_key_fingerprint_algorithm(TLS_REC *tls_rec, const char *algorithm) +{ + g_return_if_fail(tls_rec != NULL); + + tls_rec->public_key_fingerprint_algorithm = g_strdup(algorithm); +} + +void tls_rec_set_public_key_size(TLS_REC *tls_rec, size_t size) +{ + g_return_if_fail(tls_rec != NULL); + tls_rec->public_key_size = size; +} + +void tls_rec_set_certificate_fingerprint(TLS_REC *tls_rec, const char *fingerprint) +{ + g_return_if_fail(tls_rec != NULL); + + tls_rec->certificate_fingerprint = g_strdup(fingerprint); +} + +void tls_rec_set_certificate_fingerprint_algorithm(TLS_REC *tls_rec, const char *algorithm) +{ + g_return_if_fail(tls_rec != NULL); + + tls_rec->certificate_fingerprint_algorithm = g_strdup(algorithm); +} + +void tls_rec_set_not_after(TLS_REC *tls_rec, const char *not_after) +{ + g_return_if_fail(tls_rec != NULL); + tls_rec->not_after = g_strdup(not_after); +} + +void tls_rec_set_not_before(TLS_REC *tls_rec, const char *not_before) +{ + g_return_if_fail(tls_rec != NULL); + tls_rec->not_before = g_strdup(not_before); +} + +void tls_rec_set_ephemeral_key_algorithm(TLS_REC *tls_rec, const char *algorithm) +{ + g_return_if_fail(tls_rec != NULL); + tls_rec->ephemeral_key_algorithm = g_strdup(algorithm); +} + +void tls_rec_set_ephemeral_key_size(TLS_REC *tls_rec, size_t size) +{ + g_return_if_fail(tls_rec != NULL); + tls_rec->ephemeral_key_size = size; +} + +void tls_rec_append_cert(TLS_REC *tls_rec, TLS_CERT_REC *tls_cert_rec) +{ + g_return_if_fail(tls_rec != NULL); + g_return_if_fail(tls_cert_rec != NULL); + + tls_rec->certs = g_slist_append(tls_rec->certs, tls_cert_rec); +} + +TLS_CERT_REC *tls_cert_create_rec() +{ + TLS_CERT_REC *rec = g_new0(TLS_CERT_REC, 1); + g_return_val_if_fail(rec != NULL, NULL); + + return rec; +} + +void tls_cert_rec_append_subject_entry(TLS_CERT_REC *tls_cert_rec, TLS_CERT_ENTRY_REC *tls_cert_entry_rec) +{ + g_return_if_fail(tls_cert_rec != NULL); + g_return_if_fail(tls_cert_entry_rec != NULL); + + tls_cert_rec->subject = g_slist_append(tls_cert_rec->subject, tls_cert_entry_rec); +} + +void tls_cert_rec_append_issuer_entry(TLS_CERT_REC *tls_cert_rec, TLS_CERT_ENTRY_REC *tls_cert_entry_rec) +{ + g_return_if_fail(tls_cert_rec != NULL); + g_return_if_fail(tls_cert_entry_rec != NULL); + + tls_cert_rec->issuer = g_slist_append(tls_cert_rec->issuer, tls_cert_entry_rec); +} + +void tls_cert_rec_free(TLS_CERT_REC *tls_cert_rec) +{ + if (tls_cert_rec == NULL) + return; + + if (tls_cert_rec->subject != NULL) { + g_slist_foreach(tls_cert_rec->subject, (GFunc)tls_cert_entry_rec_free, NULL); + g_slist_free(tls_cert_rec->subject); + tls_cert_rec->subject = NULL; + } + + if (tls_cert_rec->issuer != NULL) { + g_slist_foreach(tls_cert_rec->issuer, (GFunc)tls_cert_entry_rec_free, NULL); + g_slist_free(tls_cert_rec->issuer); + tls_cert_rec->issuer = NULL; + } + + g_free(tls_cert_rec); +} + +TLS_CERT_ENTRY_REC *tls_cert_entry_create_rec(const char *name, const char *value) +{ + TLS_CERT_ENTRY_REC *rec = g_new0(TLS_CERT_ENTRY_REC, 1); + g_return_val_if_fail(rec != NULL, NULL); + + rec->name = g_strdup(name); + rec->value = g_strdup(value); + + return rec; +} + +void tls_cert_entry_rec_free(TLS_CERT_ENTRY_REC *tls_cert_entry) +{ + if (tls_cert_entry == NULL) + return; + + g_free_and_null(tls_cert_entry->name); + g_free_and_null(tls_cert_entry->value); + + g_free(tls_cert_entry); +} diff --git a/src/core/tls.h b/src/core/tls.h new file mode 100644 index 00000000..9ba4ac47 --- /dev/null +++ b/src/core/tls.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 Alexander Færøy <ahf@irssi.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA + */ + +#ifndef __TLS_H +#define __TLS_H + +#include <openssl/ssl.h> + +#include <stdbool.h> + +typedef struct _TLS_REC TLS_REC; +typedef struct _TLS_CERT_REC TLS_CERT_REC; +typedef struct _TLS_CERT_ENTRY_REC TLS_CERT_ENTRY_REC; + +struct _TLS_REC { + char *protocol_version; + char *cipher; + size_t cipher_size; + + char *public_key_algorithm; + char *public_key_fingerprint; + char *public_key_fingerprint_algorithm; + size_t public_key_size; + + char *certificate_fingerprint; + char *certificate_fingerprint_algorithm; + + char *not_after; + char *not_before; + + char *ephemeral_key_algorithm; + size_t ephemeral_key_size; + + GSList *certs; +}; + +struct _TLS_CERT_REC { + GSList *subject; + GSList *issuer; +}; + +struct _TLS_CERT_ENTRY_REC { + char *name; + char *value; +}; + +TLS_REC *tls_create_rec(); +void tls_rec_free(TLS_REC *tls_rec); + +void tls_rec_set_protocol_version(TLS_REC *tls_rec, const char *protocol_version); +void tls_rec_set_cipher(TLS_REC *tls_rec, const char *cipher); +void tls_rec_set_cipher_size(TLS_REC *tls_rec, size_t size); +void tls_rec_set_public_key_algorithm(TLS_REC *tls_rec, const char *algorithm); +void tls_rec_set_public_key_fingerprint(TLS_REC *tls_rec, const char *fingerprint); +void tls_rec_set_public_key_fingerprint_algorithm(TLS_REC *tls_rec, const char *algorithm); +void tls_rec_set_public_key_size(TLS_REC *tls_rec, size_t size); +void tls_rec_set_certificate_fingerprint(TLS_REC *tls_rec, const char *fingerprint); +void tls_rec_set_certificate_fingerprint_algorithm(TLS_REC *tls_rec, const char *algorithm); +void tls_rec_set_not_after(TLS_REC *tls_rec, const char *not_after); +void tls_rec_set_not_before(TLS_REC *tls_rec, const char *not_before); +void tls_rec_set_ephemeral_key_algorithm(TLS_REC *tls_rec, const char *algorithm); +void tls_rec_set_ephemeral_key_size(TLS_REC *tls_rec, size_t size); + +void tls_rec_append_cert(TLS_REC *tls_rec, TLS_CERT_REC *tls_cert_rec); + +TLS_CERT_REC *tls_cert_create_rec(); +void tls_cert_rec_free(TLS_CERT_REC *tls_cert_rec); + +void tls_cert_rec_append_subject_entry(TLS_CERT_REC *tls_cert_rec, TLS_CERT_ENTRY_REC *tls_cert_entry_rec); +void tls_cert_rec_append_issuer_entry(TLS_CERT_REC *tls_cert_rec, TLS_CERT_ENTRY_REC *tls_cert_entry_rec); + +TLS_CERT_ENTRY_REC *tls_cert_entry_create_rec(const char *name, const char *value); +void tls_cert_entry_rec_free(TLS_CERT_ENTRY_REC *tls_cert_entry); + +#endif diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am index 63f91fa6..6efff411 100644 --- a/src/fe-common/core/Makefile.am +++ b/src/fe-common/core/Makefile.am @@ -24,6 +24,7 @@ libfe_common_core_a_SOURCES = \ fe-queries.c \ fe-server.c \ fe-settings.c \ + fe-tls.c \ formats.c \ hilight-text.c \ keyboard.c \ @@ -48,6 +49,7 @@ pkginc_fe_common_core_HEADERS = \ fe-exec.h \ fe-messages.h \ fe-queries.h \ + fe-tls.h \ formats.h \ hilight-text.h \ keyboard.h \ diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c index 1b2ab1e2..fd0e6cf0 100644 --- a/src/fe-common/core/fe-common-core.c +++ b/src/fe-common/core/fe-common-core.c @@ -88,6 +88,9 @@ void fe_server_deinit(void); void fe_settings_init(void); void fe_settings_deinit(void); +void fe_tls_init(void); +void fe_tls_deinit(void); + void window_commands_init(void); void window_commands_deinit(void); @@ -176,6 +179,7 @@ void fe_common_core_init(void) fe_modules_init(); fe_server_init(); fe_settings_init(); + fe_tls_init(); windows_init(); window_activity_init(); window_commands_init(); @@ -217,6 +221,7 @@ void fe_common_core_deinit(void) fe_modules_deinit(); fe_server_deinit(); fe_settings_deinit(); + fe_tls_deinit(); windows_deinit(); window_activity_deinit(); window_commands_deinit(); diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c index 468cb707..f4c1d3ee 100644 --- a/src/fe-common/core/fe-server.c +++ b/src/fe-common/core/fe-server.c @@ -154,42 +154,66 @@ static void cmd_server_add_modify(const char *data, gboolean add) else if (g_hash_table_lookup(optlist, "4")) rec->family = AF_INET; - if (g_hash_table_lookup(optlist, "ssl")) - rec->use_ssl = TRUE; + if (g_hash_table_lookup(optlist, "tls") || g_hash_table_lookup(optlist, "ssl")) + rec->use_tls = TRUE; - value = g_hash_table_lookup(optlist, "ssl_cert"); + value = g_hash_table_lookup(optlist, "tls_cert"); + if (value == NULL) + value = g_hash_table_lookup(optlist, "ssl_cert"); if (value != NULL && *value != '\0') - rec->ssl_cert = g_strdup(value); + rec->tls_cert = g_strdup(value); - value = g_hash_table_lookup(optlist, "ssl_pkey"); + value = g_hash_table_lookup(optlist, "tls_pkey"); + if (value == NULL) + value = g_hash_table_lookup(optlist, "ssl_pkey"); if (value != NULL && *value != '\0') - rec->ssl_pkey = g_strdup(value); + rec->tls_pkey = g_strdup(value); - value = g_hash_table_lookup(optlist, "ssl_pass"); + value = g_hash_table_lookup(optlist, "tls_pass"); + if (value == NULL) + value = g_hash_table_lookup(optlist, "ssl_pass"); if (value != NULL && *value != '\0') - rec->ssl_pass = g_strdup(value); + rec->tls_pass = g_strdup(value); - if (g_hash_table_lookup(optlist, "ssl_verify")) - rec->ssl_verify = TRUE; + if (g_hash_table_lookup(optlist, "tls_verify") || g_hash_table_lookup(optlist, "ssl_verify")) + rec->tls_verify = TRUE; - value = g_hash_table_lookup(optlist, "ssl_cafile"); + value = g_hash_table_lookup(optlist, "tls_cafile"); + if (value == NULL) + value = g_hash_table_lookup(optlist, "ssl_cafile"); if (value != NULL && *value != '\0') - rec->ssl_cafile = g_strdup(value); + rec->tls_cafile = g_strdup(value); - value = g_hash_table_lookup(optlist, "ssl_capath"); + value = g_hash_table_lookup(optlist, "tls_capath"); + if (value == NULL) + value = g_hash_table_lookup(optlist, "ssl_capath"); if (value != NULL && *value != '\0') - rec->ssl_capath = g_strdup(value); + rec->tls_capath = g_strdup(value); - value = g_hash_table_lookup(optlist, "ssl_ciphers"); + value = g_hash_table_lookup(optlist, "tls_ciphers"); + if (value == NULL) + value = g_hash_table_lookup(optlist, "ssl_ciphers"); if (value != NULL && *value != '\0') - rec->ssl_ciphers = g_strdup(value); + rec->tls_ciphers = g_strdup(value); - if ((rec->ssl_cafile != NULL && rec->ssl_cafile[0] != '\0') - || (rec->ssl_capath != NULL && rec->ssl_capath[0] != '\0')) - rec->ssl_verify = TRUE; + value = g_hash_table_lookup(optlist, "tls_pinned_cert"); + if (value == NULL) + value = g_hash_table_lookup(optlist, "ssl_pinned_cert"); + if (value != NULL && *value != '\0') + rec->tls_pinned_cert = g_strdup(value); + + value = g_hash_table_lookup(optlist, "tls_pinned_pubkey"); + if (value == NULL) + value = g_hash_table_lookup(optlist, "ssl_pinned_pubkey"); + if (value != NULL && *value != '\0') + rec->tls_pinned_pubkey = g_strdup(value); - if ((rec->ssl_cert != NULL && rec->ssl_cert[0] != '\0') || rec->ssl_verify == TRUE) - rec->use_ssl = TRUE; + if ((rec->tls_cafile != NULL && rec->tls_cafile[0] != '\0') + || (rec->tls_capath != NULL && rec->tls_capath[0] != '\0')) + rec->tls_verify = TRUE; + + if ((rec->tls_cert != NULL && rec->tls_cert[0] != '\0') || rec->tls_verify == TRUE) + rec->use_tls = TRUE; if (g_hash_table_lookup(optlist, "auto")) rec->autoconnect = TRUE; if (g_hash_table_lookup(optlist, "noauto")) rec->autoconnect = FALSE; @@ -409,8 +433,9 @@ void fe_server_init(void) command_bind("server remove", NULL, (SIGNAL_FUNC) cmd_server_remove); command_bind_first("server", NULL, (SIGNAL_FUNC) server_command); command_bind_first("disconnect", NULL, (SIGNAL_FUNC) server_command); - command_set_options("server add", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers auto noauto proxy noproxy -host -port noautosendcmd"); - command_set_options("server modify", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers auto noauto proxy noproxy -host -port noautosendcmd"); + + command_set_options("server add", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers +ssl_fingerprint tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_ciphers +tls_pinned_cert +tls_pinned_pubkey auto noauto proxy noproxy -host -port noautosendcmd"); + command_set_options("server modify", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers +ssl_fingerprint tls +tls_cert +tls_pkey +tls_pass tls_verify +tls_cafile +tls_capath +tls_ciphers +tls_pinned_cert +tls_pinned_pubkey auto noauto proxy noproxy -host -port noautosendcmd"); signal_add("server looking", (SIGNAL_FUNC) sig_server_looking); signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting); diff --git a/src/fe-common/core/fe-tls.c b/src/fe-common/core/fe-tls.c new file mode 100644 index 00000000..ed206d18 --- /dev/null +++ b/src/fe-common/core/fe-tls.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015 Alexander Færøy <ahf@irssi.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA + */ + +#include "module.h" +#include "signals.h" +#include "settings.h" +#include "levels.h" +#include "tls.h" + +#include "module-formats.h" +#include "printtext.h" + +#include "fe-tls.h" + +static void tls_handshake_finished(SERVER_REC *server, TLS_REC *tls) +{ + GSList *certs = NULL; + GSList *subject = NULL; + GSList *issuer = NULL; + GString *str = NULL; + TLS_CERT_ENTRY_REC *data = NULL; + + if (! settings_get_bool("tls_verbose_connect")) + return; + + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_HEADER); + + for (certs = tls->certs; certs != NULL; certs = certs->next) { + TLS_CERT_REC *tls_cert_rec = certs->data; + str = g_string_new(NULL); + + for (subject = tls_cert_rec->subject; subject != NULL; subject = subject->next) { + data = subject->data; + g_string_append_printf(str, "%s: %s, ", data->name, data->value); + } + + if (str->len > 1) + g_string_truncate(str, str->len - 2); + + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_SUBJECT, str->str); + g_string_free(str, TRUE); + + str = g_string_new(NULL); + + for (issuer = tls_cert_rec->issuer; issuer != NULL; issuer = issuer->next) { + data = issuer->data; + g_string_append_printf(str, "%s: %s, ", data->name, data->value); + } + + if (str->len > 1) + g_string_truncate(str, str->len - 2); + + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_ISSUER, str->str); + g_string_free(str, TRUE); + } + + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_PROTOCOL_VERSION, tls->protocol_version, tls->cipher_size, tls->cipher); + + if (tls->ephemeral_key_algorithm != NULL) + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_EPHEMERAL_KEY, tls->ephemeral_key_size, tls->ephemeral_key_algorithm); + else + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_EPHEMERAL_KEY_UNAVAILBLE); + + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_PUBKEY, tls->public_key_size, tls->public_key_algorithm, tls->not_before, tls->not_after); + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_PUBKEY_FINGERPRINT, tls->public_key_fingerprint, tls->public_key_fingerprint_algorithm); + printformat(server, NULL, MSGLEVEL_CLIENTNOTICE, TXT_TLS_CERT_FINGERPRINT, tls->certificate_fingerprint, tls->certificate_fingerprint_algorithm); +} + +void fe_tls_init(void) +{ + settings_add_bool("lookandfeel", "tls_verbose_connect", TRUE); + + signal_add("tls handshake finished", (SIGNAL_FUNC)tls_handshake_finished); +} + +void fe_tls_deinit(void) +{ + signal_remove("tls handshake finished", (SIGNAL_FUNC)tls_handshake_finished); +} diff --git a/src/fe-common/core/fe-tls.h b/src/fe-common/core/fe-tls.h new file mode 100644 index 00000000..f0082477 --- /dev/null +++ b/src/fe-common/core/fe-tls.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015 Alexander Færøy <ahf@irssi.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA + */ + +#ifndef __FE_TLS_H +#define __FE_TLS_H + +void fe_tls_init(void); +void fe_tls_deinit(void); + +#endif diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index 5c07f14c..da9705be 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -291,5 +291,18 @@ FORMAT_REC fecommon_core_formats[] = { { "completion_line", "%#$[10]0 $[!40]1 $2", 3, { 0, 0, 0 } }, { "completion_footer", "", 0 }, + /* ---- */ + { NULL, "TLS", 0 }, + + { "tls_ephemeral_key", "EDH Key: {hilight $0} bit {hilight $1}", 2, { 1, 0 } }, + { "tls_ephemeral_key_unavailable", "EDH Key: {error N/A}", 0 }, + { "tls_pubkey", "Public Key: {hilight $0} bit {hilight $1}, valid from {hilight $2} to {hilight $3}", 4, { 1, 0, 0, 0 } }, + { "tls_cert_header", "Certificate Chain:", 0 }, + { "tls_cert_subject", " Subject: {hilight $0}", 1, { 0 } }, + { "tls_cert_issuer", " Issuer: {hilight $0}", 1, { 0 } }, + { "tls_pubkey_fingerprint", "Public Key Fingerprint: {hilight $0} ({hilight $1})", 2, { 0, 0 } }, + { "tls_cert_fingerprint", "Certificate Fingerprint: {hilight $0} ({hilight $1})", 2, { 0, 0 } }, + { "tls_protocol_version", "Protocol: {hilight $0} ({hilight $1} bit, {hilight $2})", 3, { 0, 1, 0 } }, + { NULL, NULL, 0 } }; diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h index 2b45ff6b..a9ed28c5 100644 --- a/src/fe-common/core/module-formats.h +++ b/src/fe-common/core/module-formats.h @@ -254,7 +254,19 @@ enum { TXT_COMPLETION_REMOVED, TXT_COMPLETION_HEADER, TXT_COMPLETION_LINE, - TXT_COMPLETION_FOOTER + TXT_COMPLETION_FOOTER, + + TLS_FILL_15, + + TXT_TLS_EPHEMERAL_KEY, + TXT_TLS_EPHEMERAL_KEY_UNAVAILBLE, + TXT_TLS_PUBKEY, + TXT_TLS_CERT_HEADER, + TXT_TLS_CERT_SUBJECT, + TXT_TLS_CERT_ISSUER, + TXT_TLS_PUBKEY_FINGERPRINT, + TXT_TLS_CERT_FINGERPRINT, + TXT_TLS_PROTOCOL_VERSION }; extern FORMAT_REC fecommon_core_formats[]; diff --git a/src/fe-common/irc/fe-irc-server.c b/src/fe-common/irc/fe-irc-server.c index 2e22d6f2..c4435d8f 100644 --- a/src/fe-common/irc/fe-irc-server.c +++ b/src/fe-common/irc/fe-irc-server.c @@ -108,23 +108,27 @@ static void cmd_server_list(const char *data) g_string_append(str, "autoconnect, "); if (rec->no_proxy) g_string_append(str, "noproxy, "); - if (rec->use_ssl) { - g_string_append(str, "ssl, "); - if (rec->ssl_cert) { - g_string_append_printf(str, "ssl_cert: %s, ", rec->ssl_cert); - if (rec->ssl_pkey) - g_string_append_printf(str, "ssl_pkey: %s, ", rec->ssl_pkey); - if (rec->ssl_pass) + if (rec->use_tls) { + g_string_append(str, "tls, "); + if (rec->tls_cert) { + g_string_append_printf(str, "tls_cert: %s, ", rec->tls_cert); + if (rec->tls_pkey) + g_string_append_printf(str, "tls_pkey: %s, ", rec->tls_pkey); + if (rec->tls_pass) g_string_append_printf(str, "(pass), "); } - if (rec->ssl_verify) - g_string_append(str, "ssl_verify, "); - if (rec->ssl_cafile) - g_string_append_printf(str, "ssl_cafile: %s, ", rec->ssl_cafile); - if (rec->ssl_capath) - g_string_append_printf(str, "ssl_capath: %s, ", rec->ssl_capath); - if (rec->ssl_ciphers) - g_string_append_printf(str, "ssl_ciphers: %s, ", rec->ssl_ciphers); + if (rec->tls_verify) + g_string_append(str, "tls_verify, "); + if (rec->tls_cafile) + g_string_append_printf(str, "tls_cafile: %s, ", rec->tls_cafile); + if (rec->tls_capath) + g_string_append_printf(str, "tls_capath: %s, ", rec->tls_capath); + if (rec->tls_ciphers) + g_string_append_printf(str, "tls_ciphers: %s, ", rec->tls_ciphers); + if (rec->tls_pinned_cert) + g_string_append_printf(str, "tls_pinned_cert: %s, ", rec->tls_pinned_cert); + if (rec->tls_pinned_pubkey) + g_string_append_printf(str, "tls_pinned_pubkey: %s, ", rec->tls_pinned_pubkey); } if (rec->max_cmds_at_once > 0) diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index 79aeb227..3117e345 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -310,7 +310,7 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn) if (server->connrec->port <= 0) { server->connrec->port = - server->connrec->use_ssl ? 6697 : 6667; + server->connrec->use_tls ? 6697 : 6667; } server->cmd_queue_speed = ircconn->cmd_queue_speed > 0 ? @@ -328,7 +328,7 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn) ircconn->max_whois : DEFAULT_MAX_WHOIS; server->max_msgs_in_cmd = ircconn->max_msgs > 0 ? ircconn->max_msgs : DEFAULT_MAX_MSGS; - server->connrec->use_ssl = conn->use_ssl; + server->connrec->use_tls = conn->use_tls; modes_server_init(server); diff --git a/src/perl/get-signals.pl b/src/perl/get-signals.pl index 529d35b1..806bcafa 100755 --- a/src/perl/get-signals.pl +++ b/src/perl/get-signals.pl @@ -37,6 +37,7 @@ while (<STDIN>) { RAWLOG_REC => 'Irssi::Rawlog', IGNORE_REC => 'Irssi::Ignore', MODULE_REC => 'Irssi::Module', + TLS_REC => 'iobject', # irc BAN_REC => 'Irssi::Irc::Ban', diff --git a/src/perl/perl-common.c b/src/perl/perl-common.c index b641867f..1d08319f 100644 --- a/src/perl/perl-common.c +++ b/src/perl/perl-common.c @@ -301,7 +301,8 @@ void perl_connect_fill_hash(HV *hv, SERVER_CONNECT_REC *conn) (void) hv_store(hv, "no_autojoin_channels", 20, newSViv(conn->no_autojoin_channels), 0); (void) hv_store(hv, "no_autosendcmd", 14, newSViv(conn->no_autosendcmd), 0); (void) hv_store(hv, "unix_socket", 11, newSViv(conn->unix_socket), 0); - (void) hv_store(hv, "use_ssl", 7, newSViv(conn->use_ssl), 0); + (void) hv_store(hv, "use_ssl", 7, newSViv(conn->use_tls), 0); + (void) hv_store(hv, "use_tls", 7, newSViv(conn->use_tls), 0); (void) hv_store(hv, "no_connect", 10, newSViv(conn->no_connect), 0); } |