summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xMakefile26
-rw-r--r--vchat-connection.c1
-rwxr-xr-xvchat-tls.c651
3 files changed, 426 insertions, 252 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;
181
182 server_conn = BIO_new_socket( serverfd, 1 );
187 183
188 server_conn = BIO_new_socket( serverfd, 1 ); 184 /* To display and check server fingerprint */
185 char fingerprint[EVP_MAX_MD_SIZE*4];
186 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
187 unsigned int fingerprint_len;
189 188
190 /* To display and check server fingerprint */ 189 FILE *fingerprint_file = NULL;
191 char fingerprint[EVP_MAX_MD_SIZE*4]; 190 char * fp = fingerprint;
192 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
193 unsigned int fingerprint_len;
194 191
195 FILE *fingerprint_file = NULL; 192 long result, j;
196 char * fp = fingerprint;
197 193
198 long result, j; 194 if( !ctx )
195 goto all_errors;
199 196
200 if( !ctx ) 197 ssl_conn = BIO_new_ssl(ctx, 1);
201 goto all_errors; 198 SSL_CTX_free(ctx);
202 199
203 ssl_conn = BIO_new_ssl(ctx, 1); 200 if( !ssl_conn )
204 SSL_CTX_free(ctx); 201 goto ssl_error;
205 202
206 if( !ssl_conn ) 203 BIO_push( ssl_conn, server_conn );
207 goto ssl_error; 204 server_conn = ssl_conn;
205 fflush(stdout);
208 206
209 BIO_push( ssl_conn, server_conn ); 207 if( BIO_do_handshake( server_conn ) <= 0 )
210 server_conn = ssl_conn; 208 goto ssl_error;
211 fflush(stdout);
212 209
213 if( BIO_do_handshake( server_conn ) <= 0 ) 210 /* Show information about cipher used */
214 goto ssl_error; 211 /* Get cipher object */
212 BIO_get_ssl(ssl_conn, &sslp);
213 if (!sslp)
214 goto ssl_error;
215
216 cipher = SSL_get_current_cipher(sslp);
217 if (cipher) {
218 char cipher_desc[TMPSTRSIZE];
219 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE));
220 writecf(FS_SERV, tmpstr);
221 } else {
222 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!");
223 writecf(FS_ERR, tmpstr);
224 }
215 225
216 /* Show information about cipher used */ 226 /* Accept being connected, _if_ verification passed */
217 /* Get cipher object */ 227 peercert = SSL_get_peer_certificate(sslp);
218 BIO_get_ssl(ssl_conn, &sslp); 228 if (!peercert)
219 if (!sslp) 229 goto ssl_error;
220 goto ssl_error;
221 230
222 cipher = SSL_get_current_cipher(sslp); 231 /* show basic information about peer cert */
223 if (cipher) { 232 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0));
224 char cipher_desc[TMPSTRSIZE]; 233 writecf(FS_SERV, tmpstr);
225 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE)); 234 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0));
226 writecf(FS_SERV, tmpstr); 235 writecf(FS_SERV, tmpstr);
227 } else {
228 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!");
229 writecf(FS_ERR, tmpstr);
230 }
231 236
232 /* Accept being connected, _if_ verification passed */ 237 /* calculate fingerprint */
233 peercert = SSL_get_peer_certificate(sslp); 238 if (!X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len))
234 if (!peercert) 239 goto ssl_error;
235 goto ssl_error;
236 240
237 /* show basic information about peer cert */ 241 assert ( ( fingerprint_len > 1 ) && (fingerprint_len <= EVP_MAX_MD_SIZE ));
238 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0)); 242 for (j=0; j<(int)fingerprint_len; j++)
239 writecf(FS_SERV, tmpstr); 243 fp += sprintf(fp, "%02X:", fingerprint_bin[j]);
240 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0)); 244 assert ( fp > fingerprint );
241 writecf(FS_SERV, tmpstr); 245 fp[-1] = 0;
246 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from server)", fingerprint);
247 writecf(FS_SERV, tmpstr);
242 248
243 /* calculate fingerprint */ 249 /* we don't need the peercert anymore */
244 if (!X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len)) 250 X509_free(peercert);
245 goto ssl_error;
246 251
247 assert ( ( fingerprint_len > 1 ) && (fingerprint_len <= EVP_MAX_MD_SIZE )); 252 /* verify fingerprint */
248 for (j=0; j<(int)fingerprint_len; j++) 253 if (getintoption(CF_PINFINGER)) {
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 254
255 /* we don't need the peercert anymore */ 255 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r");
256 X509_free(peercert); 256 if (fingerprint_file) {
257 257
258 /* verify fingerprint */ 258 /* Read fingerprint from file */
259 if (getintoption(CF_PINFINGER)) { 259 char old_fingerprint[EVP_MAX_MD_SIZE*4];
260 char * r = fgets(old_fingerprint, sizeof(old_fingerprint), fingerprint_file);
261 fclose(fingerprint_file);
260 262
261 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r"); 263 if (r) {
262 if (fingerprint_file) { 264 /* chomp */
265 char *nl = strchr(r, '\n');
266 if (nl) *nl = 0;
263 267
264 /* Read fingerprint from file */ 268 /* verify fingerprint matches stored version */
265 char old_fingerprint[EVP_MAX_MD_SIZE*4]; 269 if (!strcmp(fingerprint, old_fingerprint))
266 char * r = fgets(old_fingerprint, sizeof(old_fingerprint), fingerprint_file); 270 return 0;
267 fclose(fingerprint_file); 271 }
268 272
269 if (r) { 273 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from %s)", r ? old_fingerprint : "<FILE READ ERROR>", getstroption(CF_FINGERPRINT));
270 /* chomp */ 274 writecf(FS_ERR, tmpstr);
271 char *nl = strchr(r, '\n'); 275 writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?");
272 if (nl) *nl = 0; 276 return 1;
277 }
273 278
274 /* verify fingerprint matches stored version */ 279 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w");
275 if (!strcmp(fingerprint, old_fingerprint)) 280 if (!fingerprint_file) {
276 return 0; 281 snprintf (tmpstr, TMPSTRSIZE, "[WARNING] Can't write fingerprint file, %s.", strerror(errno));
277 } 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 }
278 290
279 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from %s)", r ? old_fingerprint : "<FILE READ ERROR>", getstroption(CF_FINGERPRINT)); 291 /* If verify of x509 chain was requested, do the check here */
280 writecf(FS_ERR, tmpstr); 292 if (X509_V_OK == SSL_get_verify_result(sslp))
281 writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?"); 293 return 0;
282 return 1; 294
295 if (getintoption(CF_IGNSSL)) {
296 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!");
297 return 0;
283 } 298 }
284 299
285 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w"); 300ssl_error:
286 if (!fingerprint_file) { 301 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s", ERR_error_string (ERR_get_error (), NULL));
287 snprintf (tmpstr, TMPSTRSIZE, "[WARNING] Can't write fingerprint file, %s.", strerror(errno)); 302 writecf(FS_ERR, tmpstr);
288 writecf(FS_ERR, tmpstr); 303all_errors:
289 } else { 304 BIO_free_all( server_conn );
290 fputs(fingerprint, fingerprint_file); 305 server_conn = NULL;
291 fclose(fingerprint_file); 306 return 1;
292 writecf(FS_SERV, "Stored fingerprint."); 307}
308
309#define VC_STORE_ERR_EXIT(s) do { \
310 fprintf(stderr, "[E] SSL_STORE: %s\n", ERR_error_string (ERR_get_error (), NULL)); \
311 if(s) X509_STORE_free(s); \
312 return(0); \
313} while(0)
314
315X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) {
316 X509_STORE *store = NULL;
317 X509_LOOKUP *lookup = NULL;
318
319 store = X509_STORE_new();
320
321 X509_STORE_set_verify_cb_func(store, vc_verify_callback);
322
323 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) )
324 VC_STORE_ERR_EXIT(store);
325
326 if (!vc_store->cafile) {
327 if( !(vc_store->flags & VC_X509S_USE_CAFILE) )
328 X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT);
329 } else if( !X509_LOOKUP_load_file(lookup, vc_store->cafile,
330 X509_FILETYPE_PEM) )
331 VC_STORE_ERR_EXIT(store);
332
333 if (vc_store->crlfile) {
334 if( !X509_load_crl_file(lookup, vc_store->crlfile,
335 X509_FILETYPE_PEM) )
336 VC_STORE_ERR_EXIT(store);
337
338 X509_STORE_set_flags( store,
339 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL );
293 } 340 }
294 return 0;
295 }
296 341
297 /* If verify of x509 chain was requested, do the check here */ 342 if ( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) )
298 result = SSL_get_verify_result(sslp); 343 VC_STORE_ERR_EXIT(store);
299 344
300 if (result == X509_V_OK) 345 if ( !vc_store->capath ) {
301 return 0; 346 if( !(vc_store->flags & VC_X509S_USE_CAPATH) )
347 X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT);
348 } else if( !X509_LOOKUP_add_dir(lookup, vc_store->capath,
349 X509_FILETYPE_PEM) )
350 VC_STORE_ERR_EXIT(store);
351
352 return(store);
353}
354
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}
302 367
303 if (getintoption(CF_IGNSSL)) { 368ssize_t vc_tls_receivemessage(void *buf, size_t size) {
304 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!"); 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;
305 return 0; 374 return 0;
306 } 375}
307 376
308ssl_error: 377void vc_tls_cleanup() {
309 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s", ERR_error_string (ERR_get_error (), NULL)); 378 BIO_free_all( server_conn );
310 writecf(FS_ERR, tmpstr); 379 server_conn = NULL;
311all_errors:
312 BIO_free_all( server_conn );
313 server_conn = NULL;
314 return 1;
315} 380}
381#endif
316 382
317#define VC_STORE_ERR_EXIT(s) do { \ 383#ifdef TLS_LIB_MBEDTLS
318 fprintf(stderr, "[E] SSL_STORE: %s\n", ERR_error_string (ERR_get_error (), NULL)); \
319 if(s) X509_STORE_free(s); \
320 return(0); \
321 } while(0)
322 384
323X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) 385#include <mbedtls/net_sockets.h>
324{ 386#include <mbedtls/ssl.h>
325 X509_STORE *store = NULL; 387#include <mbedtls/entropy.h>
326 X509_LOOKUP *lookup = NULL; 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"
327 393
328 store = X509_STORE_new(); 394#include <sys/socket.h>
329 395
330 X509_STORE_set_verify_cb_func(store, vc_verify_callback); 396const char *DRBG_PERS = "mbed TLS vchat client";
331 397
332 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) ) 398typedef struct {
333 VC_STORE_ERR_EXIT(store); 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;
334 408
335 if (!vc_store->cafile) { 409void vchat_tls_get_version_external()
336 if( !(vc_store->flags & VC_X509S_USE_CAFILE) ) 410{
337 X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT); 411 snprintf(tmpstr, sizeof(tmpstr), "%s", MBEDTLS_VERSION_STRING_FULL);
338 } else if( !X509_LOOKUP_load_file(lookup, vc_store->cafile, 412 vchat_tls_version_external = strdup(tmpstr);
339 X509_FILETYPE_PEM) ) 413}
340 VC_STORE_ERR_EXIT(store);
341 414
342 if (vc_store->crlfile) { 415static int static_tcp_recv(void *ctx, unsigned char *buf, size_t len ) {
343 if( !X509_load_crl_file(lookup, vc_store->crlfile, 416 return recv((int)(intptr_t)ctx, buf, len, 0);
344 X509_FILETYPE_PEM) ) 417}
345 VC_STORE_ERR_EXIT(store); 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}
346 421
347 X509_STORE_set_flags( store, 422void vc_init_x509store(vc_x509store_t *store)
348 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); 423{
349 } 424 static int sslinit;
425 if (!sslinit++) {
426 mbedtls_entropy_init(&_mbedtls_state._entropy);
427 mbedtls_ctr_drbg_init(&_mbedtls_state._ctr_drbg);
350 428
351 if ( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) ) 429 mbedtls_ctr_drbg_seed(&_mbedtls_state._ctr_drbg, mbedtls_entropy_func, &_mbedtls_state._entropy,
352 VC_STORE_ERR_EXIT(store); 430 (const unsigned char *) DRBG_PERS, sizeof (DRBG_PERS));
431 }
432 memset(store, 0, sizeof(vc_x509store_t));
353 433
354 if ( !vc_store->capath ) { 434 /* We want to make verifying the peer the default */
355 if( !(vc_store->flags & VC_X509S_USE_CAPATH) ) 435 store->flags |= VC_X509S_SSL_VERIFY_PEER;
356 X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT); 436}
357 } else if( !X509_LOOKUP_add_dir(lookup, vc_store->capath,
358 X509_FILETYPE_PEM) )
359 VC_STORE_ERR_EXIT(store);
360 437
361 return(store); 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);
362} 442}
363 443
364int vc_verify_callback(int ok, X509_STORE_CTX *store) 444int vc_tls_connect( int serverfd, vc_x509store_t *vc_store )
365{ 445{
366 if(!ok) { 446 /* Some aliases for shorter references */
367 snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR ] %s", 447 mbedstate *s = &_mbedtls_state;
368 X509_verify_cert_error_string(X509_STORE_CTX_get_error(store))); 448 mbedtls_ssl_config *conf = &_mbedtls_state._conf;
369 writecf(FS_ERR, tmpstr); 449 mbedtls_ssl_context *ssl = &_mbedtls_state._ssl;
370 } 450 int ret;
371 return (ok | getintoption(CF_IGNSSL)); 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