summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xMakefile26
-rw-r--r--vchat-connection.c1
-rwxr-xr-xvchat-tls.c699
3 files changed, 450 insertions, 276 deletions
diff --git a/Makefile b/Makefile
index 3eb2efa..281910d 100755
--- a/Makefile
+++ b/Makefile
@@ -6,18 +6,35 @@
6# configuration # 6# configuration #
7############################################## 7##############################################
8 8
9OBJS = vchat-client.o vchat-ui.o vchat-protocol.o vchat-user.o vchat-commands.o vchat-tls.o vchat-connection.o
10
11LIBS = -lncurses
12LIBS += -lreadline
13
9CFLAGS = -Wall -Os 14CFLAGS = -Wall -Os
10#CFLAGS = -Wall -g -ggdb
11 15
12## use this line when you've got an readline before 4.(x|2) 16## use this line when you've got an readline before 4.(x|2)
13#CFLAGS += -DOLDREADLINE 17#CFLAGS += -DOLDREADLINE
14
15CFLAGS += $(OLDREADLINE) 18CFLAGS += $(OLDREADLINE)
16 19
20##### Enable this for using the OpenSSL library
21CFLAGS += -DTLS_LIB_OPENSSL -I"/usr/local/opt/openssl@1.1/include"
22LIBS += -lssl -lcrypto
23
24##### Enable this for using the mbedTLS library
25#CFLAGS += -DTLS_LIB_MBEDTLS
26#LIBS += -lmbedx509 -lmbedtls -lmbedcrypto
27
17## you might need one or more of these: 28## you might need one or more of these:
29#CFLAGS+= -Wextra -Wall -g -ggdb
30#CFLAGS+= -arch x86_64 -Wno-deprecated-declarations
31#CFLAGS+= -arch i386 -Wno-deprecated-declarations
18#CFLAGS += -I/usr/local/ssl/include -L/usr/local/ssl/lib 32#CFLAGS += -I/usr/local/ssl/include -L/usr/local/ssl/lib
19#CFLAGS += -I/usr/local/include -L/usr/local/lib 33#CFLAGS += -I/usr/local/include -L/usr/local/lib
20#CFLAGS += -I/usr/pkg/include -L/usr/pkg/lib 34#CFLAGS += -I/usr/pkg/include -L/usr/pkg/lib
35#LDFLAGS += -L"/usr/local/opt/openssl@1.1/lib"
36#CFLAGS += -I../readline-6.3
37#LIBS += ../readline-6.3/libreadline.a
21 38
22## enable dietlibc 39## enable dietlibc
23#CC = diet cc 40#CC = diet cc
@@ -26,14 +43,9 @@ CFLAGS += $(OLDREADLINE)
26## enable debug code 43## enable debug code
27#CFLAGS += -DDEBUG 44#CFLAGS += -DDEBUG
28 45
29#LDFLAGS = -L"/usr/local/opt/openssl@1.1/lib"
30
31## the install prefix best is /usr/local 46## the install prefix best is /usr/local
32PREFIX=/usr/local 47PREFIX=/usr/local
33 48
34LIBS = -lssl -lcrypto -lncurses -lreadline
35OBJS = vchat-client.o vchat-ui.o vchat-protocol.o vchat-user.o vchat-commands.o vchat-tls.o vchat-connection.o
36
37 49
38############################################## 50##############################################
39# general targets # 51# general targets #
diff --git a/vchat-connection.c b/vchat-connection.c
index c0648c8..5ab4dd4 100644
--- a/vchat-connection.c
+++ b/vchat-connection.c
@@ -135,6 +135,7 @@ vc_connect (const char *server, const char *port)
135 close(serverfd); 135 close(serverfd);
136 serverfd = -1; 136 serverfd = -1;
137 errno = EIO; 137 errno = EIO;
138 vc_tls_cleanup();
138 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port ); 139 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port );
139 writechan (tmpstr); 140 writechan (tmpstr);
140 return -1; 141 return -1;
diff --git a/vchat-tls.c b/vchat-tls.c
index 205f0e0..4b555fd 100755
--- a/vchat-tls.c
+++ b/vchat-tls.c
@@ -28,53 +28,48 @@
28const char *vchat_tls_version = "vchat-tls.c $Id$"; 28const char *vchat_tls_version = "vchat-tls.c $Id$";
29const char *vchat_tls_version_external = "Unknown implementation; version unknown"; 29const char *vchat_tls_version_external = "Unknown implementation; version unknown";
30 30
31void vc_cleanup_x509store(vc_x509store_t *store) 31/* Helpers to work with vc_x509store_t used by all tls libs */
32{ 32void vc_cleanup_x509store(vc_x509store_t *store) {
33 free(store->cafile); 33 free(store->cafile);
34 free(store->capath); 34 free(store->capath);
35 free(store->crlfile); 35 free(store->crlfile);
36 free(store->certfile); 36 free(store->certfile);
37 free(store->keyfile); 37 free(store->keyfile);
38 memset(store, 0, sizeof(vc_x509store_t)); 38 memset(store, 0, sizeof(vc_x509store_t));
39} 39}
40 40
41void vc_x509store_setflags(vc_x509store_t *store, int flags) { store->flags |= flags; } 41void vc_x509store_setflags(vc_x509store_t *store, int flags) { store->flags |= flags; }
42void vc_x509store_clearflags(vc_x509store_t *store, int flags) { store->flags &= ~flags; } 42void vc_x509store_clearflags(vc_x509store_t *store, int flags) { store->flags &= ~flags; }
43void vc_x509store_set_pkeycb(vc_x509store_t *store, vc_askpass_cb_t callback) { store->askpass_callback = callback; } 43void vc_x509store_set_pkeycb(vc_x509store_t *store, vc_askpass_cb_t callback) { store->askpass_callback = callback; }
44 44
45void vc_x509store_setcafile(vc_x509store_t *store, char *file) 45void vc_x509store_setcafile(vc_x509store_t *store, char *file) {
46{ 46 free(store->cafile);
47 free(store->cafile); 47 store->cafile = ( file ? strdup(file) : 0 );
48 store->cafile = ( file ? strdup(file) : 0 ); 48 store->flags |= VC_X509S_USE_CAFILE;
49 store->flags |= VC_X509S_USE_CAFILE;
50} 49}
51 50
52void vc_x509store_setcapath(vc_x509store_t *store, char *path) 51void vc_x509store_setcapath(vc_x509store_t *store, char *path) {
53{ 52 free(store->capath);
54 free(store->capath); 53 store->capath = ( path ? strdup(path) : 0 );
55 store->capath = ( path ? strdup(path) : 0 );
56} 54}
57 55
58void vc_x509store_setcrlfile(vc_x509store_t *store, char *file) 56void vc_x509store_setcrlfile(vc_x509store_t *store, char *file) {
59{ 57 free(store->crlfile);
60 free(store->crlfile); 58 store->crlfile = ( file ? strdup(file) : 0 );
61 store->crlfile = ( file ? strdup(file) : 0 );
62} 59}
63 60
64void vc_x509store_setkeyfile(vc_x509store_t *store, char *file) 61void vc_x509store_setkeyfile(vc_x509store_t *store, char *file) {
65{ 62 free(store->keyfile);
66 free(store->keyfile); 63 store->keyfile = ( file ? strdup(file) : 0 );
67 store->keyfile = ( file ? strdup(file) : 0 );
68} 64}
69 65
70void vc_x509store_setcertfile(vc_x509store_t *store, char *file) 66void vc_x509store_setcertfile(vc_x509store_t *store, char *file) {
71{ 67 free(store->certfile);
72 free(store->certfile); 68 store->certfile = ( file ? strdup(file) : 0 );
73 store->certfile = ( file ? strdup(file) : 0 ); 69 store->flags |= VC_X509S_USE_CERTIFICATE;
74 store->flags |= VC_X509S_USE_CERTIFICATE;
75} 70}
76 71
77//// OPENSSL SPECIFIC 72#ifdef TLS_LIB_OPENSSL
78 73
79#include <openssl/err.h> 74#include <openssl/err.h>
80#include <openssl/ssl.h> 75#include <openssl/ssl.h>
@@ -86,22 +81,21 @@ void vc_x509store_setcertfile(vc_x509store_t *store, char *file)
86 81
87void vchat_tls_get_version_external() 82void vchat_tls_get_version_external()
88{ 83{
89 snprintf(tmpstr, sizeof(tmpstr), "OpenSSL %s with %s", SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS)); 84 snprintf(tmpstr, sizeof(tmpstr), "OpenSSL %s with %s", SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS));
90 vchat_tls_version_external = strdup(tmpstr); 85 vchat_tls_version_external = strdup(tmpstr);
91} 86}
92 87
93/* Helpers to work with vc_x509store_t used by all tls libs */
94void vc_init_x509store(vc_x509store_t *store) 88void vc_init_x509store(vc_x509store_t *store)
95{ 89{
96 static int sslinit; 90 static int sslinit;
97 if (!sslinit++) { 91 if (!sslinit++) {
98 SSL_library_init (); 92 SSL_library_init ();
99 SSL_load_error_strings(); 93 SSL_load_error_strings();
100 } 94 }
101 memset(store, 0, sizeof(vc_x509store_t)); 95 memset(store, 0, sizeof(vc_x509store_t));
102 96
103 /* We want to make verifying the peer the default */ 97 /* We want to make verifying the peer the default */
104 store->flags |= VC_X509S_SSL_VERIFY_PEER; 98 store->flags |= VC_X509S_SSL_VERIFY_PEER;
105} 99}
106 100
107/* connection BIO for openssl */ 101/* connection BIO for openssl */
@@ -113,278 +107,445 @@ static X509_STORE * vc_x509store_create(vc_x509store_t *);
113 107
114static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store ) 108static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store )
115{ 109{
116 int flags = 0; 110 int flags = 0;
117 111
118 /* Explicitly use TLSv1 (or maybe later) */ 112 /* Explicitly use TLSv1 (or maybe later) */
119 SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); 113 SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
120 X509_STORE *store = vc_x509store_create(vc_store); 114 X509_STORE *store = vc_x509store_create(vc_store);
121 115
122 if (!ctx || !store) { 116 if (!ctx || !store) {
123 snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: %s",ERR_error_string (ERR_get_error (), NULL)); 117 snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: %s",ERR_error_string (ERR_get_error (), NULL));
124 writecf(FS_ERR, tmpstr); 118 writecf(FS_ERR, tmpstr);
125 if (store) 119 if (store)
126 X509_STORE_free(store); 120 X509_STORE_free(store);
127 if (ctx) 121 if (ctx)
128 SSL_CTX_free(ctx); 122 SSL_CTX_free(ctx);
129 return NULL; 123 return NULL;
130 } 124 }
131 125
132 SSL_CTX_set_cert_store(ctx, store); 126 SSL_CTX_set_cert_store(ctx, store);
133 127
134 /* Disable some insecure protocols explicitly */ 128 /* Disable some insecure protocols explicitly */
135 SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); 129 SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
136 if (getstroption(CF_CIPHERSUITE)) 130 if (getstroption(CF_CIPHERSUITE))
137 SSL_CTX_set_cipher_list(ctx, getstroption(CF_CIPHERSUITE)); 131 SSL_CTX_set_cipher_list(ctx, getstroption(CF_CIPHERSUITE));
138 else 132 else
139 SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA"); 133 SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA");
140 134
141 SSL_CTX_set_verify_depth (ctx, getintoption(CF_VERIFYSSL)); 135 SSL_CTX_set_verify_depth (ctx, getintoption(CF_VERIFYSSL));
142 136
143 if( !(vc_store->flags & VC_X509S_SSL_VERIFY_MASK) ) { 137 if( !(vc_store->flags & VC_X509S_SSL_VERIFY_MASK) ) {
144 writecf(FS_DBG, tmpstr); 138 writecf(FS_DBG, tmpstr);
145 flags = SSL_VERIFY_NONE; 139 flags = SSL_VERIFY_NONE;
146 } else { 140 } else {
147 if(vc_store->flags & VC_X509S_SSL_VERIFY_PEER) 141 if(vc_store->flags & VC_X509S_SSL_VERIFY_PEER)
148 flags |= SSL_VERIFY_PEER; 142 flags |= SSL_VERIFY_PEER;
149 if(vc_store->flags & VC_X509S_SSL_VERIFY_FAIL_IF_NO_PEER_CERT) 143 if(vc_store->flags & VC_X509S_SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
150 flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; 144 flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
151 if(vc_store->flags & VC_X509S_SSL_VERIFY_CLIENT_ONCE) 145 if(vc_store->flags & VC_X509S_SSL_VERIFY_CLIENT_ONCE)
152 flags |= SSL_VERIFY_CLIENT_ONCE; 146 flags |= SSL_VERIFY_CLIENT_ONCE;
153 } 147 }
154 148
155 SSL_CTX_set_verify(ctx, flags, vc_verify_callback); 149 SSL_CTX_set_verify(ctx, flags, vc_verify_callback);
156 150
157 if(vc_store->flags & VC_X509S_USE_CERTIFICATE) { 151 if(vc_store->flags & VC_X509S_USE_CERTIFICATE) {
158 int r = 0; 152 int r = 0;
159 if(vc_store->certfile) 153 if(vc_store->certfile)
160 SSL_CTX_use_certificate_chain_file(ctx, vc_store->certfile); 154 SSL_CTX_use_certificate_chain_file(ctx, vc_store->certfile);
161 155
162 SSL_CTX_set_default_passwd_cb(ctx, vc_store->askpass_callback); 156 SSL_CTX_set_default_passwd_cb(ctx, vc_store->askpass_callback);
163 157
164 if(vc_store->keyfile) 158 if(vc_store->keyfile)
165 r=SSL_CTX_use_PrivateKey_file(ctx, vc_store->keyfile, 159 r=SSL_CTX_use_PrivateKey_file(ctx, vc_store->keyfile,
166 SSL_FILETYPE_PEM); 160 SSL_FILETYPE_PEM);
167 161
168 if( r!=1 || !SSL_CTX_check_private_key(ctx)) { 162 if( r!=1 || !SSL_CTX_check_private_key(ctx)) {
169 snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: Load private key failed"); 163 snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: Load private key failed");
170 writecf(FS_ERR, tmpstr); 164 writecf(FS_ERR, tmpstr);
171 SSL_CTX_free(ctx); 165 SSL_CTX_free(ctx);
172 return NULL; 166 return NULL;
173 } 167 }
174 } 168 }
175 169
176 SSL_CTX_set_app_data(ctx, vc_store); 170 SSL_CTX_set_app_data(ctx, vc_store);
177 return(ctx); 171 return(ctx);
178} 172}
179 173
180int vc_tls_connect( int serverfd, vc_x509store_t *vc_store ) 174int vc_tls_connect( int serverfd, vc_x509store_t *vc_store )
181{ 175{
182 SSL_CTX * ctx = vc_create_sslctx(vc_store); 176 SSL_CTX * ctx = vc_create_sslctx(vc_store);
183 X509 *peercert = NULL; 177 X509 *peercert = NULL;
184 BIO *ssl_conn = NULL; 178 BIO *ssl_conn = NULL;
185 const SSL *sslp = NULL; 179 const SSL *sslp = NULL;
186 const SSL_CIPHER * cipher = NULL; 180 const SSL_CIPHER * cipher = NULL;
187
188 server_conn = BIO_new_socket( serverfd, 1 );
189 181
190 /* To display and check server fingerprint */ 182 server_conn = BIO_new_socket( serverfd, 1 );
191 char fingerprint[EVP_MAX_MD_SIZE*4];
192 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
193 unsigned int fingerprint_len;
194 183
195 FILE *fingerprint_file = NULL; 184 /* To display and check server fingerprint */
196 char * fp = fingerprint; 185 char fingerprint[EVP_MAX_MD_SIZE*4];
186 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
187 unsigned int fingerprint_len;
197 188
198 long result, j; 189 FILE *fingerprint_file = NULL;
190 char * fp = fingerprint;
199 191
200 if( !ctx ) 192 long result, j;
201 goto all_errors;
202 193
203 ssl_conn = BIO_new_ssl(ctx, 1); 194 if( !ctx )
204 SSL_CTX_free(ctx); 195 goto all_errors;
205 196
206 if( !ssl_conn ) 197 ssl_conn = BIO_new_ssl(ctx, 1);
207 goto ssl_error; 198 SSL_CTX_free(ctx);
208 199
209 BIO_push( ssl_conn, server_conn ); 200 if( !ssl_conn )
210 server_conn = ssl_conn; 201 goto ssl_error;
211 fflush(stdout);
212 202
213 if( BIO_do_handshake( server_conn ) <= 0 ) 203 BIO_push( ssl_conn, server_conn );
214 goto ssl_error; 204 server_conn = ssl_conn;
205 fflush(stdout);
215 206
216 /* Show information about cipher used */ 207 if( BIO_do_handshake( server_conn ) <= 0 )
217 /* Get cipher object */ 208 goto ssl_error;
218 BIO_get_ssl(ssl_conn, &sslp);
219 if (!sslp)
220 goto ssl_error;
221 209
222 cipher = SSL_get_current_cipher(sslp); 210 /* Show information about cipher used */
223 if (cipher) { 211 /* Get cipher object */
224 char cipher_desc[TMPSTRSIZE]; 212 BIO_get_ssl(ssl_conn, &sslp);
225 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE)); 213 if (!sslp)
226 writecf(FS_SERV, tmpstr); 214 goto ssl_error;
227 } else {
228 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!");
229 writecf(FS_ERR, tmpstr);
230 }
231
232 /* Accept being connected, _if_ verification passed */
233 peercert = SSL_get_peer_certificate(sslp);
234 if (!peercert)
235 goto ssl_error;
236
237 /* show basic information about peer cert */
238 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0));
239 writecf(FS_SERV, tmpstr);
240 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0));
241 writecf(FS_SERV, tmpstr);
242
243 /* calculate fingerprint */
244 if (!X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len))
245 goto ssl_error;
246
247 assert ( ( fingerprint_len > 1 ) && (fingerprint_len <= EVP_MAX_MD_SIZE ));
248 for (j=0; j<(int)fingerprint_len; j++)
249 fp += sprintf(fp, "%02X:", fingerprint_bin[j]);
250 assert ( fp > fingerprint );
251 fp[-1] = 0;
252 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from server)", fingerprint);
253 writecf(FS_SERV, tmpstr);
254
255 /* we don't need the peercert anymore */
256 X509_free(peercert);
257
258 /* verify fingerprint */
259 if (getintoption(CF_PINFINGER)) {
260
261 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r");
262 if (fingerprint_file) {
263
264 /* Read fingerprint from file */
265 char old_fingerprint[EVP_MAX_MD_SIZE*4];
266 char * r = fgets(old_fingerprint, sizeof(old_fingerprint), fingerprint_file);
267 fclose(fingerprint_file);
268
269 if (r) {
270 /* chomp */
271 char *nl = strchr(r, '\n');
272 if (nl) *nl = 0;
273
274 /* verify fingerprint matches stored version */
275 if (!strcmp(fingerprint, old_fingerprint))
276 return 0;
277 }
278
279 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from %s)", r ? old_fingerprint : "<FILE READ ERROR>", getstroption(CF_FINGERPRINT));
280 writecf(FS_ERR, tmpstr);
281 writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?");
282 return 1;
283 }
284 215
285 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w"); 216 cipher = SSL_get_current_cipher(sslp);
286 if (!fingerprint_file) { 217 if (cipher) {
287 snprintf (tmpstr, TMPSTRSIZE, "[WARNING] Can't write fingerprint file, %s.", strerror(errno)); 218 char cipher_desc[TMPSTRSIZE];
288 writecf(FS_ERR, tmpstr); 219 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE));
220 writecf(FS_SERV, tmpstr);
289 } else { 221 } else {
290 fputs(fingerprint, fingerprint_file); 222 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!");
291 fclose(fingerprint_file); 223 writecf(FS_ERR, tmpstr);
292 writecf(FS_SERV, "Stored fingerprint.");
293 } 224 }
294 return 0;
295 }
296 225
297 /* If verify of x509 chain was requested, do the check here */ 226 /* Accept being connected, _if_ verification passed */
298 result = SSL_get_verify_result(sslp); 227 peercert = SSL_get_peer_certificate(sslp);
228 if (!peercert)
229 goto ssl_error;
299 230
300 if (result == X509_V_OK) 231 /* show basic information about peer cert */
301 return 0; 232 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0));
233 writecf(FS_SERV, tmpstr);
234 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0));
235 writecf(FS_SERV, tmpstr);
302 236
303 if (getintoption(CF_IGNSSL)) { 237 /* calculate fingerprint */
304 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!"); 238 if (!X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len))
305 return 0; 239 goto ssl_error;
306 } 240
241 assert ( ( fingerprint_len > 1 ) && (fingerprint_len <= EVP_MAX_MD_SIZE ));
242 for (j=0; j<(int)fingerprint_len; j++)
243 fp += sprintf(fp, "%02X:", fingerprint_bin[j]);
244 assert ( fp > fingerprint );
245 fp[-1] = 0;
246 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from server)", fingerprint);
247 writecf(FS_SERV, tmpstr);
248
249 /* we don't need the peercert anymore */
250 X509_free(peercert);
251
252 /* verify fingerprint */
253 if (getintoption(CF_PINFINGER)) {
254
255 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r");
256 if (fingerprint_file) {
257
258 /* Read fingerprint from file */
259 char old_fingerprint[EVP_MAX_MD_SIZE*4];
260 char * r = fgets(old_fingerprint, sizeof(old_fingerprint), fingerprint_file);
261 fclose(fingerprint_file);
262
263 if (r) {
264 /* chomp */
265 char *nl = strchr(r, '\n');
266 if (nl) *nl = 0;
267
268 /* verify fingerprint matches stored version */
269 if (!strcmp(fingerprint, old_fingerprint))
270 return 0;
271 }
272
273 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from %s)", r ? old_fingerprint : "<FILE READ ERROR>", getstroption(CF_FINGERPRINT));
274 writecf(FS_ERR, tmpstr);
275 writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?");
276 return 1;
277 }
278
279 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w");
280 if (!fingerprint_file) {
281 snprintf (tmpstr, TMPSTRSIZE, "[WARNING] Can't write fingerprint file, %s.", strerror(errno));
282 writecf(FS_ERR, tmpstr);
283 } else {
284 fputs(fingerprint, fingerprint_file);
285 fclose(fingerprint_file);
286 writecf(FS_SERV, "Stored fingerprint.");
287 }
288 return 0;
289 }
290
291 /* If verify of x509 chain was requested, do the check here */
292 if (X509_V_OK == SSL_get_verify_result(sslp))
293 return 0;
294
295 if (getintoption(CF_IGNSSL)) {
296 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!");
297 return 0;
298 }
307 299
308ssl_error: 300ssl_error:
309 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s", ERR_error_string (ERR_get_error (), NULL)); 301 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s", ERR_error_string (ERR_get_error (), NULL));
310 writecf(FS_ERR, tmpstr); 302 writecf(FS_ERR, tmpstr);
311all_errors: 303all_errors:
312 BIO_free_all( server_conn ); 304 BIO_free_all( server_conn );
313 server_conn = NULL; 305 server_conn = NULL;
314 return 1; 306 return 1;
315} 307}
316 308
317#define VC_STORE_ERR_EXIT(s) do { \ 309#define VC_STORE_ERR_EXIT(s) do { \
318 fprintf(stderr, "[E] SSL_STORE: %s\n", ERR_error_string (ERR_get_error (), NULL)); \ 310 fprintf(stderr, "[E] SSL_STORE: %s\n", ERR_error_string (ERR_get_error (), NULL)); \
319 if(s) X509_STORE_free(s); \ 311 if(s) X509_STORE_free(s); \
320 return(0); \ 312 return(0); \
321 } while(0) 313} while(0)
322 314
323X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) 315X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) {
324{ 316 X509_STORE *store = NULL;
325 X509_STORE *store = NULL; 317 X509_LOOKUP *lookup = NULL;
326 X509_LOOKUP *lookup = NULL;
327 318
328 store = X509_STORE_new(); 319 store = X509_STORE_new();
329 320
330 X509_STORE_set_verify_cb_func(store, vc_verify_callback); 321 X509_STORE_set_verify_cb_func(store, vc_verify_callback);
331 322
332 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) ) 323 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) )
333 VC_STORE_ERR_EXIT(store); 324 VC_STORE_ERR_EXIT(store);
334 325
335 if (!vc_store->cafile) { 326 if (!vc_store->cafile) {
336 if( !(vc_store->flags & VC_X509S_USE_CAFILE) ) 327 if( !(vc_store->flags & VC_X509S_USE_CAFILE) )
337 X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT); 328 X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT);
338 } else if( !X509_LOOKUP_load_file(lookup, vc_store->cafile, 329 } else if( !X509_LOOKUP_load_file(lookup, vc_store->cafile,
339 X509_FILETYPE_PEM) ) 330 X509_FILETYPE_PEM) )
340 VC_STORE_ERR_EXIT(store); 331 VC_STORE_ERR_EXIT(store);
341 332
342 if (vc_store->crlfile) { 333 if (vc_store->crlfile) {
343 if( !X509_load_crl_file(lookup, vc_store->crlfile, 334 if( !X509_load_crl_file(lookup, vc_store->crlfile,
344 X509_FILETYPE_PEM) ) 335 X509_FILETYPE_PEM) )
345 VC_STORE_ERR_EXIT(store); 336 VC_STORE_ERR_EXIT(store);
346 337
347 X509_STORE_set_flags( store, 338 X509_STORE_set_flags( store,
348 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); 339 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL );
349 } 340 }
350 341
351 if ( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) ) 342 if ( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) )
352 VC_STORE_ERR_EXIT(store); 343 VC_STORE_ERR_EXIT(store);
353 344
354 if ( !vc_store->capath ) { 345 if ( !vc_store->capath ) {
355 if( !(vc_store->flags & VC_X509S_USE_CAPATH) ) 346 if( !(vc_store->flags & VC_X509S_USE_CAPATH) )
356 X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT); 347 X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT);
357 } else if( !X509_LOOKUP_add_dir(lookup, vc_store->capath, 348 } else if( !X509_LOOKUP_add_dir(lookup, vc_store->capath,
358 X509_FILETYPE_PEM) ) 349 X509_FILETYPE_PEM) )
359 VC_STORE_ERR_EXIT(store); 350 VC_STORE_ERR_EXIT(store);
360 351
361 return(store); 352 return(store);
362} 353}
363 354
364int vc_verify_callback(int ok, X509_STORE_CTX *store) 355int vc_verify_callback(int ok, X509_STORE_CTX *store) {
356 if(!ok) {
357 snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR ] %s",
358 X509_verify_cert_error_string(X509_STORE_CTX_get_error(store)));
359 writecf(FS_ERR, tmpstr);
360 }
361 return (ok | getintoption(CF_IGNSSL));
362}
363
364ssize_t vc_tls_sendmessage(const void *buf, size_t size) {
365 return BIO_write(server_conn, buf, size);
366}
367
368ssize_t vc_tls_receivemessage(void *buf, size_t size) {
369 ssize_t received = (ssize_t)BIO_read (server_conn, buf, size);
370 if (received != 0)
371 return received;
372 if (BIO_should_retry(server_conn))
373 return -2;
374 return 0;
375}
376
377void vc_tls_cleanup() {
378 BIO_free_all( server_conn );
379 server_conn = NULL;
380}
381#endif
382
383#ifdef TLS_LIB_MBEDTLS
384
385#include <mbedtls/net_sockets.h>
386#include <mbedtls/ssl.h>
387#include <mbedtls/entropy.h>
388#include <mbedtls/ctr_drbg.h>
389#include <mbedtls/x509.h>
390#include <mbedtls/pk.h>
391#include <mbedtls/debug.h>
392#include "mbedtls/error.h"
393
394#include <sys/socket.h>
395
396const char *DRBG_PERS = "mbed TLS vchat client";
397
398typedef struct {
399 mbedtls_entropy_context _entropy;
400 mbedtls_ctr_drbg_context _ctr_drbg;
401 mbedtls_x509_crt _cacert;
402 mbedtls_x509_crt _cert;
403 mbedtls_pk_context _key;
404 mbedtls_ssl_context _ssl;
405 mbedtls_ssl_config _conf;
406} mbedstate;
407static mbedstate _mbedtls_state;
408
409void vchat_tls_get_version_external()
410{
411 snprintf(tmpstr, sizeof(tmpstr), "%s", MBEDTLS_VERSION_STRING_FULL);
412 vchat_tls_version_external = strdup(tmpstr);
413}
414
415static int static_tcp_recv(void *ctx, unsigned char *buf, size_t len ) {
416 return recv((int)(intptr_t)ctx, buf, len, 0);
417}
418static int static_tcp_send(void *ctx, const unsigned char *buf, size_t len ) {
419 return send((int)(intptr_t)ctx, buf, len, 0);
420}
421
422void vc_init_x509store(vc_x509store_t *store)
365{ 423{
366 if(!ok) { 424 static int sslinit;
367 snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR ] %s", 425 if (!sslinit++) {
368 X509_verify_cert_error_string(X509_STORE_CTX_get_error(store))); 426 mbedtls_entropy_init(&_mbedtls_state._entropy);
369 writecf(FS_ERR, tmpstr); 427 mbedtls_ctr_drbg_init(&_mbedtls_state._ctr_drbg);
370 } 428
371 return (ok | getintoption(CF_IGNSSL)); 429 mbedtls_ctr_drbg_seed(&_mbedtls_state._ctr_drbg, mbedtls_entropy_func, &_mbedtls_state._entropy,
430 (const unsigned char *) DRBG_PERS, sizeof (DRBG_PERS));
431 }
432 memset(store, 0, sizeof(vc_x509store_t));
433
434 /* We want to make verifying the peer the default */
435 store->flags |= VC_X509S_SSL_VERIFY_PEER;
436}
437
438static void vc_tls_report_error(int error, char *message) {
439 size_t used = snprintf(tmpstr, sizeof(tmpstr), message);
440 mbedtls_strerror(error, tmpstr + used, sizeof(tmpstr) - used);
441 writecf(FS_ERR, tmpstr);
442}
443
444int vc_tls_connect( int serverfd, vc_x509store_t *vc_store )
445{
446 /* Some aliases for shorter references */
447 mbedstate *s = &_mbedtls_state;
448 mbedtls_ssl_config *conf = &_mbedtls_state._conf;
449 mbedtls_ssl_context *ssl = &_mbedtls_state._ssl;
450 int ret;
451
452 mbedtls_x509_crt_init(&s->_cacert);
453 mbedtls_x509_crt_init(&s->_cert);
454 mbedtls_pk_init(&s->_key);
455
456 mbedtls_ssl_config_init(conf);
457 mbedtls_ssl_config_defaults(conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
458 /* TODO: Always verify peer */
459 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
460 mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, &s->_ctr_drbg);
461
462 /* mbedtls_ssl_conf_ciphersuites( */
463
464 /* Read in all certs */
465 if (vc_store->cafile) {
466 mbedtls_x509_crt_parse_file(&s->_cacert, vc_store->cafile);
467 mbedtls_ssl_conf_ca_chain(conf, &s->_cacert, NULL);
468 }
469
470 mbedtls_x509_crt_parse_file(&s->_cert, vc_store->certfile);
471 char *password = NULL;
472 char password_buf[1024];
473 while (1) {
474#if MBEDTLS_SSL_MAJOR_VERSION_3 < 3
475 ret = mbedtls_pk_parse_keyfile(&s->_key, vc_store->keyfile, password);
476#else
477 // ret = fprintf(stderr, "ERROR: %d\n", mbedtls_pk_parse_keyfile(&s->_key, vc_store->keyfile, password, mbedtls_ctr_drbg_random, &s->_ctr_drbg));
478 ret = mbedtls_pk_parse_keyfile(&s->_key, vc_store->keyfile, password, mbedtls_ctr_drbg_random, &s->_ctr_drbg);
479#endif
480 if (!ret)
481 break;
482 if (ret != MBEDTLS_ERR_PK_PASSWORD_REQUIRED && ret != MBEDTLS_ERR_PK_PASSWORD_MISMATCH) {
483 vc_tls_report_error(ret, "CREATE CTX: Loading key failed, mbedtls reports: ");
484 return -1;
485 }
486 if (ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH)
487 vc_tls_report_error(ret, "Wrong passphrase, mbedtls reports: ");
488 vc_store->askpass_callback(password_buf, sizeof(password_buf), 0, NULL);
489 password = password_buf;
490 }
491 memset_s(password_buf, sizeof(password_buf), 0, sizeof(password_buf));
492
493#if 0
494 /* pk member made private in mbedtls 3 */
495 if (mbedtls_pk_check_pair(&(s->_cert.pk), &s->_key)) {
496 fprintf(stderr, "KEYPAIR MISSMATCH\n");
497 }
498#endif
499 mbedtls_ssl_conf_own_cert(conf, &s->_cert, &s->_key);
500
501 /* Config constructed, pass to ssl */
502 /* Init ssl and config structs and configure ssl ctx */
503 mbedtls_ssl_init(ssl);
504 mbedtls_ssl_setup(ssl, conf);
505 /* TODO: mbedtls_ssl_set_hostname(&ssl, SERVER_NAME) */
506
507 mbedtls_ssl_set_bio(ssl, (void*)(intptr_t)serverfd, static_tcp_send, static_tcp_recv, NULL );
508
509 while ((ret = mbedtls_ssl_handshake(ssl)) != 0) {
510 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
511 vc_tls_report_error(ret, "TLS handshake failed, mbedtls reports: ");
512 return -1;
513 }
514 }
515
516 mbedtls_ssl_get_verify_result(ssl);
517
518 return 0;
372} 519}
373 520
374ssize_t vc_tls_sendmessage(const void *buf, size_t size) { 521ssize_t vc_tls_sendmessage(const void *buf, size_t size) {
375 return BIO_write(server_conn, buf, size); 522 return mbedtls_ssl_write( &_mbedtls_state._ssl, buf, size);
376} 523}
377 524
378ssize_t vc_tls_receivemessage(void *buf, size_t size) { 525ssize_t vc_tls_receivemessage(void *buf, size_t size) {
379 ssize_t received = (ssize_t)BIO_read (server_conn, buf, size); 526 ssize_t received = (ssize_t)mbedtls_ssl_read (&_mbedtls_state._ssl, buf, size);
380 if (received != 0) 527 switch (received) {
381 return received; 528 case MBEDTLS_ERR_SSL_WANT_READ:
382 if (BIO_should_retry(server_conn)) 529 case MBEDTLS_ERR_SSL_WANT_WRITE:
383 return -2; 530 return -2;
384 return 0; 531 case MBEDTLS_ERR_SSL_CONN_EOF:
532 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
533 case 0:
534 return 0;
535 default:
536 if (received > 0)
537 return received;
538 return -1;
539 }
385} 540}
386 541
387void vc_tls_cleanup() { 542void vc_tls_cleanup() {
388 BIO_free_all( server_conn ); 543 mbedtls_x509_crt_free(&_mbedtls_state._cacert);
389 server_conn = NULL; 544 mbedtls_x509_crt_free(&_mbedtls_state._cert);
545 mbedtls_pk_free(&_mbedtls_state._key);
546 mbedtls_ssl_free(&_mbedtls_state._ssl );
547 mbedtls_ssl_config_free(&_mbedtls_state._conf );
548 mbedtls_ctr_drbg_free(&_mbedtls_state._ctr_drbg );
390} 549}
550
551#endif