summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2016-04-15 16:27:42 +0200
committerDirk Engling <erdgeist@erdgeist.org>2016-04-15 16:27:42 +0200
commitc5c4ee4d6a9aa5554ad29be79c4ee3e6bd79c70f (patch)
tree3adc212952389dec26c03f2579317eade7875155
parent3ff11bc9ec47ea24e578444ffc9985884f32038b (diff)
Make fingerprint pinning an option
-rwxr-xr-xvchat-config.h1
-rwxr-xr-xvchat-ssl.c210
-rwxr-xr-xvchat.h2
3 files changed, 111 insertions, 102 deletions
diff --git a/vchat-config.h b/vchat-config.h
index 9e10999..f7123d7 100755
--- a/vchat-config.h
+++ b/vchat-config.h
@@ -39,6 +39,7 @@ static volatile configoption configoptions[] = {
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_FINGERPRINT, CO_STR, "fingerprint","~/.vchat/fingerprint", NULL, { NULL } },
42 {CF_PINFINGER, CO_INT, "pinfinger", (char *) 0, (char *)-1, { NULL } },
42 {CF_ENCODING, CO_STR, "encoding", NULL, NULL, { .pstr = &encoding }}, 43 {CF_ENCODING, CO_STR, "encoding", NULL, NULL, { .pstr = &encoding }},
43 {CF_USESSL, CO_INT, "usessl", (char *) 1, (char *)-1, { NULL } }, 44 {CF_USESSL, CO_INT, "usessl", (char *) 1, (char *)-1, { NULL } },
44 {CF_IGNSSL, CO_INT, "ignssl", (char *) 0, (char *)-1, { NULL } }, 45 {CF_IGNSSL, CO_INT, "ignssl", (char *) 0, (char *)-1, { NULL } },
diff --git a/vchat-ssl.c b/vchat-ssl.c
index ef5b96e..b344d10 100755
--- a/vchat-ssl.c
+++ b/vchat-ssl.c
@@ -154,8 +154,21 @@ static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store )
154 154
155int vc_connect_ssl( BIO **conn, vc_x509store_t *vc_store ) 155int vc_connect_ssl( BIO **conn, vc_x509store_t *vc_store )
156{ 156{
157 BIO *ssl_conn = NULL;
158 SSL_CTX * ctx = vc_create_sslctx(vc_store); 157 SSL_CTX * ctx = vc_create_sslctx(vc_store);
158 X509 *peercert = NULL;
159 BIO *ssl_conn = NULL;
160 const SSL *sslp = NULL;
161 const SSL_CIPHER * cipher = NULL;
162
163 /* To display and check server fingerprint */
164 char fingerprint[EVP_MAX_MD_SIZE*4];
165 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
166 unsigned int fingerprint_len;
167
168 FILE *fingerprint_file = NULL;
169 char * fp = fingerprint;
170
171 long result;
159 172
160 if( !ctx ) 173 if( !ctx )
161 return 1; 174 return 1;
@@ -163,112 +176,107 @@ int vc_connect_ssl( BIO **conn, vc_x509store_t *vc_store )
163 ssl_conn = BIO_new_ssl(ctx, 1); 176 ssl_conn = BIO_new_ssl(ctx, 1);
164 SSL_CTX_free(ctx); 177 SSL_CTX_free(ctx);
165 178
166 if( ssl_conn ) { 179 if( !ssl_conn )
167 BIO_push( ssl_conn, *conn ); 180 goto ssl_error;
168 *conn = ssl_conn; 181
169 fflush(stdout); 182 BIO_push( ssl_conn, *conn );
170 183 *conn = ssl_conn;
171 if( BIO_do_handshake( *conn ) > 0 ) { 184 fflush(stdout);
172 /* Show information about cipher used */ 185
173 const SSL *sslp = NULL; 186 if( BIO_do_handshake( *conn ) <= 0 )
174 const SSL_CIPHER * cipher = NULL; 187 goto ssl_error;
175 188
176 /* Get cipher object */ 189 /* Show information about cipher used */
177 BIO_get_ssl(ssl_conn, &sslp); 190 /* Get cipher object */
178 if (sslp) 191 BIO_get_ssl(ssl_conn, &sslp);
179 cipher = SSL_get_current_cipher(sslp); 192 if (sslp)
180 if (cipher) { 193 cipher = SSL_get_current_cipher(sslp);
181 char cipher_desc[TMPSTRSIZE]; 194 if (cipher) {
182 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE)); 195 char cipher_desc[TMPSTRSIZE];
183 writecf(FS_SERV, tmpstr); 196 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE));
184 } else { 197 writecf(FS_SERV, tmpstr);
185 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!"); 198 } else {
186 writecf(FS_ERR, tmpstr); 199 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!");
187 } 200 writecf(FS_ERR, tmpstr);
201 }
188 202
189 /* Accept being connected, _if_ verification passed */ 203 /* Accept being connected, _if_ verification passed */
190 if (sslp) { 204 if (!sslp)
191 long result = SSL_get_verify_result(sslp); 205 goto ssl_error;
192#if 1 == 1 206
193 if (result == X509_V_OK) { 207 peercert = SSL_get_peer_certificate(sslp);
208 if (!peercert)
209 goto ssl_error;
210
211 /* show basic information about peer cert */
212 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0));
213 writecf(FS_SERV, tmpstr);
214 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0));
215 writecf(FS_SERV, tmpstr);
216
217 /* calculate fingerprint */
218 if (!X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len))
219 goto ssl_error;
220
221 assert ( ( fingerprint_len > 1 ) && (fingerprint_len <= EVP_MAX_MD_SIZE ));
222 for (j=0; j<(int)fingerprint_len; j++)
223 fp += sprintf(nf, "%02X:", fingerprint_bin[j]);
224 assert ( fp > fingerprint );
225 fp[-1] = 0;
226 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] from server: %s", fingerprint);
227 writecf(FS_SERV, tmpstr);
228
229 /* we don't need the peercert anymore */
230 X509_free(peercert);
231
232 /* If verify of x509 chain was requested, do the check here */
233 result = SSL_get_verify_result(sslp);
234 if (result != X509_V_OK && !getintoption(CF_IGNSSL) )
235 goto ssl_error;
236
237 if (result != X509_V_OK)
238 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!");
239
240 /* verify fingerprint */
241 if (getintoption(CF_PIN_FINGERPRINT)) {
242
243 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r");
244 if (fingerprint_file) {
245
246 /* Read fingerprint from file */
247 char old_fingerprint[EVP_MAX_MD_SIZE*4];
248 char * r = fgets(old_fingerprint, sizeof(old_fingerprint), fingerprint_file);
249 fclose(fingerprint_file);
250
251 if (r) {
252 /* chomp */
253 char *nl = strchr(r, '\n');
254 if (nl) *nl = 0;
255
256 /* verify fingerprint matches stored version */
257 if (!strcmp(fingerprint, old_fingerprint))
194 return 0; 258 return 0;
195 } else if (getintoption(CF_IGNSSL)) {
196 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!");
197 return 0;
198 }
199#else
200 /* show & verify fingerprint */
201 if ((result == X509_V_OK) || getintoption(CF_IGNSSL)) {
202 X509 *peercert = SSL_get_peer_certificate(sslp);
203
204 /* FIXME: this IS bad code */
205 char new_fingerprint[TMPSTRSIZE];
206 char old_fingerprint[TMPSTRSIZE];
207 FILE *fingerprint_file = NULL;
208
209 unsigned int fingerprint_len;
210 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
211
212 /* show basic information about peer cert */
213 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0));
214 writecf(FS_SERV, tmpstr);
215 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0));
216 writecf(FS_SERV, tmpstr);
217
218 /* calculate fingerprint */
219 if (X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len)) {
220 int j;
221 assert ( ( fingerprint_len > 1 ) && (fingerprint_len * 3 < TMPSTRSIZE ));
222 char * nf = new_fingerprint;
223 for (j=0; j<(int)fingerprint_len; j++)
224 nf += snprintf(nf, 4, "%02X:", fingerprint_bin[j]);
225 assert ( nf > new_fingerprint );
226 nf[-1] = 0;
227 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] from server: %s", new_fingerprint);
228 writecf(FS_SERV, tmpstr);
229 }
230
231 // we don't need the peercert anymore
232 X509_free(peercert);
233
234 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r");
235 if (fingerprint_file) {
236 char * r = fgets(old_fingerprint, TMPSTRSIZE, fingerprint_file);
237 fclose(fingerprint_file);
238
239 if (r) {
240 // chomp
241 char *nl = strchr(r, '\n');
242 if (nl) *nl = 0;
243
244 /* verify fingerprint matches stored version */
245 if (!strcmp(new_fingerprint, old_fingerprint))
246 return 0;
247 }
248
249 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] from %s: %s", getstroption(CF_FINGERPRINT), r ? old_fingerprint : "<FILE READ ERROR>" );
250 writecf(FS_ERR, tmpstr);
251 writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?");
252 return 1;
253 } else {
254 /* FIXME: there might be other errors than missing file */
255 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w");
256 if (!fingerprint_file) {
257 snprintf (tmpstr, TMPSTRSIZE, "Can't write fingerprint file, %s.", strerror(errno));
258 writecf(FS_ERR, tmpstr);
259 } else {
260 fputs(new_fingerprint, fingerprint_file);
261 fclose(fingerprint_file);
262 writecf(FS_SERV, "Stored fingerprint.");
263 return 0;
264 }
265 }
266 }
267#endif
268 } 259 }
260
261 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] from %s: %s", getstroption(CF_FINGERPRINT), r ? old_fingerprint : "<FILE READ ERROR>" );
262 writecf(FS_ERR, tmpstr);
263 writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?");
264 return 1;
265 }
266
267 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w");
268 if (!fingerprint_file) {
269 snprintf (tmpstr, TMPSTRSIZE, "[WARNING] Can't write fingerprint file, %s.", strerror(errno));
270 writecf(FS_ERR, tmpstr);
271 } else {
272 fputs(fingerprint, fingerprint_file);
273 fclose(fingerprint_file);
274 writecf(FS_SERV, "Stored fingerprint.");
269 } 275 }
276 return 0;
270 } 277 }
271 278
279ssl_error:
272 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s", ERR_error_string (ERR_get_error (), NULL)); 280 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s", ERR_error_string (ERR_get_error (), NULL));
273 writecf(FS_ERR, tmpstr); 281 writecf(FS_ERR, tmpstr);
274 282
diff --git a/vchat.h b/vchat.h
index 654dc6d..4e33190 100755
--- a/vchat.h
+++ b/vchat.h
@@ -31,7 +31,7 @@ typedef struct servermessage servermessage;
31typedef enum { CO_NIL, CO_STR, CO_INT } conftype; 31typedef enum { CO_NIL, CO_STR, CO_INT } conftype;
32typedef enum { CF_NIL, CF_NICK, CF_FROM, CF_SERVERHOST, CF_SERVERPORT, 32typedef enum { CF_NIL, CF_NICK, CF_FROM, CF_SERVERHOST, CF_SERVERPORT,
33CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_FORMFILE, 33CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_FORMFILE,
34CF_LOGINSCRIPT, CF_FINGERPRINT, CF_USESSL, CF_IGNSSL, CF_VERIFYSSL, CF_USECERT, 34CF_LOGINSCRIPT, CF_FINGERPRINT, CF_PINFINGER, CF_USESSL, CF_IGNSSL, CF_VERIFYSSL, CF_USECERT,
35CF_PRIVHEIGHT, CF_PRIVCOLLAPS, CF_HSCROLL, CF_CHANNEL, CF_USETIME, CF_USETOPIC, 35CF_PRIVHEIGHT, CF_PRIVCOLLAPS, CF_HSCROLL, CF_CHANNEL, CF_USETIME, CF_USETOPIC,
36CF_SCROLLBPRIV, CF_SCROLLBACK, CF_SCROLLBPRIVT, CF_SCROLLBACKT, CF_ENCODING, 36CF_SCROLLBPRIV, CF_SCROLLBACK, CF_SCROLLBPRIVT, CF_SCROLLBACKT, CF_ENCODING,
37CF_BELLPRIV, CF_CASEFIRST, CF_AUTORECONN, CF_KEEPALIVE } confopt; 37CF_BELLPRIV, CF_CASEFIRST, CF_AUTORECONN, CF_KEEPALIVE } confopt;