From 3297473435ad53b6691d6c772f83457a72134c48 Mon Sep 17 00:00:00 2001 From: Andreas Kotes Date: Wed, 16 Apr 2014 16:27:00 +0200 Subject: store & verify server cert fingerprint --- vchat-config.h | 1 + vchat-ssl.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- vchat.h | 2 +- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/vchat-config.h b/vchat-config.h index 2628dc1..0291100 100755 --- a/vchat-config.h +++ b/vchat-config.h @@ -38,6 +38,7 @@ static volatile configoption configoptions[] = { {CF_KEYFILE, CO_STR, "keyfile", "~/.vchat/key", NULL, { NULL } }, {CF_FORMFILE, CO_STR, "formatfile", "~/.vchat/formats", NULL, { NULL } }, {CF_LOGINSCRIPT, CO_STR, "loginscript","~/.vchat/loginscript", NULL, { NULL } }, + {CF_FINGERPRINT, CO_STR, "fingerprint","~/.vchat/fingerprint", NULL, { NULL } }, {CF_ENCODING, CO_STR, "encoding", NULL, NULL, { .pstr = &encoding }}, {CF_USESSL, CO_INT, "usessl", (char *) 1, (char *)-1, { NULL } }, {CF_VERIFYSSL, CO_INT, "verifyssl", (char *) 2, (char *)-1, { NULL } }, diff --git a/vchat-ssl.c b/vchat-ssl.c index 68e3699..d240cbd 100755 --- a/vchat-ssl.c +++ b/vchat-ssl.c @@ -153,16 +153,81 @@ int vc_connect_ssl( BIO **conn, vc_x509store_t *vc_store ) cipher = SSL_get_current_cipher(sslp); if (cipher) { char cipher_desc[TMPSTRSIZE]; - snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE)); + snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE)); writecf(FS_SERV, tmpstr); } else { - snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR] Cipher not known / SSL object can't be queried!"); + snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!"); writecf(FS_ERR, tmpstr); } /* Accept being connected, _if_ verification passed */ - if (sslp && SSL_get_verify_result(sslp) == X509_V_OK) - return 0; + if (sslp) { + long result = SSL_get_verify_result(sslp); + + /* show & verify fingerprint */ + if (result == X509_V_OK) { + X509 *peercert = SSL_get_peer_certificate(sslp); + + /* FIXME: this IS bad code */ + char new_fingerprint[TMPSTRSIZE] = ""; + char old_fingerprint[TMPSTRSIZE] = ""; + FILE *fingerprint_file = NULL; + + unsigned int fingerprint_len; + unsigned char fingerprint_bin[EVP_MAX_MD_SIZE]; + + /* show basic information about peer cert */ + snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0)); + writecf(FS_SERV, tmpstr); + snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0)); + writecf(FS_SERV, tmpstr); + + /* calculate fingerprint */ + if (X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len)) { + char shorttmpstr[3] = "XX"; + int j; + for (j=0; j<(int)fingerprint_len; j++) { + if (j) + strncat(new_fingerprint, ":", TMPSTRSIZE); + snprintf(shorttmpstr, 3, "%02X", fingerprint_bin[j]); + strncat(new_fingerprint, shorttmpstr, TMPSTRSIZE); + } + snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] from server: %s", new_fingerprint); + writecf(FS_SERV, tmpstr); + } + + // we don't need the peercert anymore + X509_free(peercert); + + fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r"); + if (fingerprint_file) { + fgets(old_fingerprint, TMPSTRSIZE, fingerprint_file); + fclose(fingerprint_file); + + /* verify fingerprint matches stored version */ + if (!strncmp(new_fingerprint, old_fingerprint, TMPSTRSIZE)) + return 0; + else { + snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] from %s: %s", getstroption(CF_FINGERPRINT), old_fingerprint); + writecf(FS_ERR, tmpstr); + writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?"); + return 1; + } + } else { + /* FIXME: there might be other errors than missing file */ + fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w"); + if (!fingerprint_file) { + snprintf (tmpstr, TMPSTRSIZE, "Can't write fingerprint file, %s.", strerror(errno)); + writecf(FS_ERR, tmpstr); + } else { + fputs(new_fingerprint, fingerprint_file); + fclose(fingerprint_file); + writecf(FS_SERV, "Stored fingerprint."); + return 0; + } + } + } + } } } @@ -236,7 +301,7 @@ X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) int vc_verify_callback(int ok, X509_STORE_CTX *store) { if(!ok) { - snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR] %s", + snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR ] %s", X509_verify_cert_error_string(store->error)); writecf(FS_ERR, tmpstr); } diff --git a/vchat.h b/vchat.h index a0797d5..16ee181 100755 --- a/vchat.h +++ b/vchat.h @@ -30,7 +30,7 @@ typedef struct servermessage servermessage; /* configuration types and variable numbers */ typedef enum { CO_NIL, CO_STR, CO_INT } conftype; typedef enum { CF_NIL, CF_NICK, CF_FROM, CF_SERVERHOST, CF_SERVERPORT, -CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_FORMFILE, CF_LOGINSCRIPT, +CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_FORMFILE, CF_LOGINSCRIPT, CF_FINGERPRINT, CF_USESSL, CF_VERIFYSSL, CF_USECERT, CF_PRIVHEIGHT, CF_PRIVCOLLAPS, CF_HSCROLL, CF_CHANNEL, CF_USETIME, CF_USETOPIC, CF_SCROLLBPRIV, CF_SCROLLBACK, CF_SCROLLBPRIVT, CF_SCROLLBACKT, CF_ENCODING, CF_BELLPRIV, CF_CASEFIRST, CF_AUTORECONN, CF_KEEPALIVE } confopt; -- cgit v1.2.3