diff options
| author | Andreas Kotes <count@flatline.de> | 2014-04-16 16:27:00 +0200 |
|---|---|---|
| committer | Andreas Kotes <count@flatline.de> | 2014-04-16 16:27:00 +0200 |
| commit | 3297473435ad53b6691d6c772f83457a72134c48 (patch) | |
| tree | 9692f248fc19db010839f6c943a9c40809dcc340 | |
| parent | edba804a0cbd19e5c971c55661bcf83967573906 (diff) | |
store & verify server cert fingerprint
| -rwxr-xr-x | vchat-config.h | 1 | ||||
| -rwxr-xr-x | vchat-ssl.c | 75 | ||||
| -rwxr-xr-x | 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[] = { | |||
| 38 | {CF_KEYFILE, CO_STR, "keyfile", "~/.vchat/key", NULL, { NULL } }, | 38 | {CF_KEYFILE, CO_STR, "keyfile", "~/.vchat/key", NULL, { NULL } }, |
| 39 | {CF_FORMFILE, CO_STR, "formatfile", "~/.vchat/formats", NULL, { NULL } }, | 39 | {CF_FORMFILE, CO_STR, "formatfile", "~/.vchat/formats", NULL, { NULL } }, |
| 40 | {CF_LOGINSCRIPT, CO_STR, "loginscript","~/.vchat/loginscript", NULL, { NULL } }, | 40 | {CF_LOGINSCRIPT, CO_STR, "loginscript","~/.vchat/loginscript", NULL, { NULL } }, |
| 41 | {CF_FINGERPRINT, CO_STR, "fingerprint","~/.vchat/fingerprint", NULL, { NULL } }, | ||
| 41 | {CF_ENCODING, CO_STR, "encoding", NULL, NULL, { .pstr = &encoding }}, | 42 | {CF_ENCODING, CO_STR, "encoding", NULL, NULL, { .pstr = &encoding }}, |
| 42 | {CF_USESSL, CO_INT, "usessl", (char *) 1, (char *)-1, { NULL } }, | 43 | {CF_USESSL, CO_INT, "usessl", (char *) 1, (char *)-1, { NULL } }, |
| 43 | {CF_VERIFYSSL, CO_INT, "verifyssl", (char *) 2, (char *)-1, { NULL } }, | 44 | {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 ) | |||
| 153 | cipher = SSL_get_current_cipher(sslp); | 153 | cipher = SSL_get_current_cipher(sslp); |
| 154 | if (cipher) { | 154 | if (cipher) { |
| 155 | char cipher_desc[TMPSTRSIZE]; | 155 | char cipher_desc[TMPSTRSIZE]; |
| 156 | snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE)); | 156 | snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE)); |
| 157 | writecf(FS_SERV, tmpstr); | 157 | writecf(FS_SERV, tmpstr); |
| 158 | } else { | 158 | } else { |
| 159 | snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR] Cipher not known / SSL object can't be queried!"); | 159 | snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!"); |
| 160 | writecf(FS_ERR, tmpstr); | 160 | writecf(FS_ERR, tmpstr); |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | /* Accept being connected, _if_ verification passed */ | 163 | /* Accept being connected, _if_ verification passed */ |
| 164 | if (sslp && SSL_get_verify_result(sslp) == X509_V_OK) | 164 | if (sslp) { |
| 165 | return 0; | 165 | long result = SSL_get_verify_result(sslp); |
| 166 | |||
| 167 | /* show & verify fingerprint */ | ||
| 168 | if (result == X509_V_OK) { | ||
| 169 | X509 *peercert = SSL_get_peer_certificate(sslp); | ||
| 170 | |||
| 171 | /* FIXME: this IS bad code */ | ||
| 172 | char new_fingerprint[TMPSTRSIZE] = ""; | ||
| 173 | char old_fingerprint[TMPSTRSIZE] = ""; | ||
| 174 | FILE *fingerprint_file = NULL; | ||
| 175 | |||
| 176 | unsigned int fingerprint_len; | ||
| 177 | unsigned char fingerprint_bin[EVP_MAX_MD_SIZE]; | ||
| 178 | |||
| 179 | /* show basic information about peer cert */ | ||
| 180 | snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0)); | ||
| 181 | writecf(FS_SERV, tmpstr); | ||
| 182 | snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0)); | ||
| 183 | writecf(FS_SERV, tmpstr); | ||
| 184 | |||
| 185 | /* calculate fingerprint */ | ||
| 186 | if (X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len)) { | ||
| 187 | char shorttmpstr[3] = "XX"; | ||
| 188 | int j; | ||
| 189 | for (j=0; j<(int)fingerprint_len; j++) { | ||
| 190 | if (j) | ||
| 191 | strncat(new_fingerprint, ":", TMPSTRSIZE); | ||
| 192 | snprintf(shorttmpstr, 3, "%02X", fingerprint_bin[j]); | ||
| 193 | strncat(new_fingerprint, shorttmpstr, TMPSTRSIZE); | ||
| 194 | } | ||
| 195 | snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] from server: %s", new_fingerprint); | ||
| 196 | writecf(FS_SERV, tmpstr); | ||
| 197 | } | ||
| 198 | |||
| 199 | // we don't need the peercert anymore | ||
| 200 | X509_free(peercert); | ||
| 201 | |||
| 202 | fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r"); | ||
| 203 | if (fingerprint_file) { | ||
| 204 | fgets(old_fingerprint, TMPSTRSIZE, fingerprint_file); | ||
| 205 | fclose(fingerprint_file); | ||
| 206 | |||
| 207 | /* verify fingerprint matches stored version */ | ||
| 208 | if (!strncmp(new_fingerprint, old_fingerprint, TMPSTRSIZE)) | ||
| 209 | return 0; | ||
| 210 | else { | ||
| 211 | snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] from %s: %s", getstroption(CF_FINGERPRINT), old_fingerprint); | ||
| 212 | writecf(FS_ERR, tmpstr); | ||
| 213 | writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?"); | ||
| 214 | return 1; | ||
| 215 | } | ||
| 216 | } else { | ||
| 217 | /* FIXME: there might be other errors than missing file */ | ||
| 218 | fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w"); | ||
| 219 | if (!fingerprint_file) { | ||
| 220 | snprintf (tmpstr, TMPSTRSIZE, "Can't write fingerprint file, %s.", strerror(errno)); | ||
| 221 | writecf(FS_ERR, tmpstr); | ||
| 222 | } else { | ||
| 223 | fputs(new_fingerprint, fingerprint_file); | ||
| 224 | fclose(fingerprint_file); | ||
| 225 | writecf(FS_SERV, "Stored fingerprint."); | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | } | ||
| 230 | } | ||
| 166 | } | 231 | } |
| 167 | } | 232 | } |
| 168 | 233 | ||
| @@ -236,7 +301,7 @@ X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) | |||
| 236 | int vc_verify_callback(int ok, X509_STORE_CTX *store) | 301 | int vc_verify_callback(int ok, X509_STORE_CTX *store) |
| 237 | { | 302 | { |
| 238 | if(!ok) { | 303 | if(!ok) { |
| 239 | snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR] %s", | 304 | snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR ] %s", |
| 240 | X509_verify_cert_error_string(store->error)); | 305 | X509_verify_cert_error_string(store->error)); |
| 241 | writecf(FS_ERR, tmpstr); | 306 | writecf(FS_ERR, tmpstr); |
| 242 | } | 307 | } |
| @@ -30,7 +30,7 @@ typedef struct servermessage servermessage; | |||
| 30 | /* configuration types and variable numbers */ | 30 | /* configuration types and variable numbers */ |
| 31 | typedef enum { CO_NIL, CO_STR, CO_INT } conftype; | 31 | typedef enum { CO_NIL, CO_STR, CO_INT } conftype; |
| 32 | typedef enum { CF_NIL, CF_NICK, CF_FROM, CF_SERVERHOST, CF_SERVERPORT, | 32 | typedef enum { CF_NIL, CF_NICK, CF_FROM, CF_SERVERHOST, CF_SERVERPORT, |
| 33 | CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_FORMFILE, CF_LOGINSCRIPT, | 33 | CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_FORMFILE, CF_LOGINSCRIPT, CF_FINGERPRINT, |
| 34 | CF_USESSL, CF_VERIFYSSL, CF_USECERT, CF_PRIVHEIGHT, CF_PRIVCOLLAPS, CF_HSCROLL, CF_CHANNEL, CF_USETIME, | 34 | CF_USESSL, CF_VERIFYSSL, CF_USECERT, CF_PRIVHEIGHT, CF_PRIVCOLLAPS, CF_HSCROLL, CF_CHANNEL, CF_USETIME, |
| 35 | CF_USETOPIC, CF_SCROLLBPRIV, CF_SCROLLBACK, CF_SCROLLBPRIVT, CF_SCROLLBACKT, | 35 | CF_USETOPIC, CF_SCROLLBPRIV, CF_SCROLLBACK, CF_SCROLLBPRIVT, CF_SCROLLBACKT, |
| 36 | CF_ENCODING, CF_BELLPRIV, CF_CASEFIRST, CF_AUTORECONN, CF_KEEPALIVE } confopt; | 36 | CF_ENCODING, CF_BELLPRIV, CF_CASEFIRST, CF_AUTORECONN, CF_KEEPALIVE } confopt; |
