silenced a silly little compiler warning
[citadel.git] / webcit-ng / ssl.c
1 /*
2  * Functions in this module handle SSL encryption when WebCit is running
3  * as an HTTPS server.
4  *
5  * Copyright (c) 1996-2016 by the citadel.org team
6  *
7  * This program is open source software.  You can redistribute it and/or
8  * modify it under the terms of the GNU General Public License, version 3.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include "webcit.h"
17
18 SSL_CTX *ssl_ctx;               /* SSL context */
19 pthread_mutex_t **SSLCritters;  /* Things needing locking */
20 char *ssl_cipher_list = DEFAULT_SSL_CIPHER_LIST;
21 void ssl_lock(int mode, int n, const char *file, int line);
22
23
24 /*
25  * OpenSSL wants a callback function to identify the currently running thread.
26  * Since we are a pthreads program, we convert the output of pthread_self() to a long.
27  */
28 static unsigned long id_callback(void)
29 {
30         return (unsigned long) pthread_self();
31 }
32
33
34 /*
35  * OpenSSL wants a callback function to set and clear various types of locks.
36  * Since we are a pthreads program, we use mutexes.
37  */
38 void ssl_lock(int mode, int n, const char *file, int line)
39 {
40         if (mode & CRYPTO_LOCK) {
41                 pthread_mutex_lock(SSLCritters[n]);
42         }
43         else {
44                 pthread_mutex_unlock(SSLCritters[n]);
45         }
46 }
47
48
49 /*
50  * Initialize ssl engine, load certs and initialize openssl internals
51  */
52 void init_ssl(void)
53 {
54         const SSL_METHOD *ssl_method;
55         RSA *rsa=NULL;
56         X509_REQ *req = NULL;
57         X509 *cer = NULL;
58         EVP_PKEY *pk = NULL;
59         EVP_PKEY *req_pkey = NULL;
60         X509_NAME *name = NULL;
61         FILE *fp;
62         char buf[SIZ];
63         int rv = 0;
64
65         if (!access("/var/run/egd-pool", F_OK)) {
66                 RAND_egd("/var/run/egd-pool");
67         }
68
69         if (!RAND_status()) {
70                 syslog(LOG_WARNING, "PRNG not adequately seeded, won't do SSL/TLS");
71                 return;
72         }
73
74         SSLCritters = malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t *));
75         if (!SSLCritters) {
76                 syslog(LOG_ERR, "citserver: can't allocate memory!!");
77                 exit(1);
78         } else {
79                 int a;
80
81                 for (a = 0; a < CRYPTO_num_locks(); a++) {
82                         SSLCritters[a] = malloc(sizeof(pthread_mutex_t));
83                         if (!SSLCritters[a]) {
84                                 syslog(LOG_INFO, "citserver: can't allocate memory!!");
85                                 exit(1);
86                         }
87                         pthread_mutex_init(SSLCritters[a], NULL);
88                 }
89         }
90
91         /*
92          * Initialize SSL transport layer
93          */
94         SSL_library_init();
95         SSL_load_error_strings();
96         ssl_method = SSLv23_server_method();
97         if (!(ssl_ctx = SSL_CTX_new(ssl_method))) {
98                 syslog(LOG_WARNING, "SSL_CTX_new failed: %s", ERR_reason_error_string(ERR_get_error()));
99                 return;
100         }
101
102         syslog(LOG_INFO, "Requesting cipher list: %s", ssl_cipher_list);
103         if (!(SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher_list))) {
104                 syslog(LOG_WARNING, "SSL_CTX_set_cipher_list failed: %s", ERR_reason_error_string(ERR_get_error()));
105                 return;
106         }
107
108         CRYPTO_set_locking_callback(ssl_lock);
109         CRYPTO_set_id_callback(id_callback);
110
111         /*
112          * Get our certificates in order.
113          * First, create the key/cert directory if it's not there already...
114          */
115         mkdir(CTDL_CRYPTO_DIR, 0700);
116
117         /*
118          * If we still don't have a private key, generate one.
119          */
120         if (access(CTDL_KEY_PATH, R_OK) != 0) {
121                 syslog(LOG_INFO, "Generating RSA key pair.\n");
122                 rsa = RSA_generate_key(2048,    /* modulus size */
123                                         65537,  /* exponent */
124                                         NULL,   /* no callback */
125                                         NULL    /* no callback */
126                 );
127                 if (rsa == NULL) {
128                         syslog(LOG_WARNING, "Key generation failed: %s", ERR_reason_error_string(ERR_get_error()));
129                 }
130                 if (rsa != NULL) {
131                         fp = fopen(CTDL_KEY_PATH, "w");
132                         if (fp != NULL) {
133                                 chmod(CTDL_KEY_PATH, 0600);
134                                 if (PEM_write_RSAPrivateKey(fp, /* the file */
135                                                         rsa,    /* the key */
136                                                         NULL,   /* no enc */
137                                                         NULL,   /* no passphr */
138                                                         0,      /* no passphr */
139                                                         NULL,   /* no callbk */
140                                                         NULL    /* no callbk */
141                                 ) != 1) {
142                                         syslog(LOG_WARNING, "Cannot write key: %s", ERR_reason_error_string(ERR_get_error()));
143                                         unlink(CTDL_KEY_PATH);
144                                 }
145                                 fclose(fp);
146                         }
147                         else {
148                                 syslog(LOG_WARNING, "Cannot write key: %s", CTDL_KEY_PATH);
149                                 exit(1);
150                         }
151                         RSA_free(rsa);
152                 }
153         }
154
155         /*
156          * If there is no certificate file on disk, we will be generating a self-signed certificate
157          * in the next step.  Therefore, if we have neither a CSR nor a certificate, generate
158          * the CSR in this step so that the next step may commence.
159          */
160         if ( (access(CTDL_CER_PATH, R_OK) != 0) && (access(CTDL_CSR_PATH, R_OK) != 0) ) {
161                 syslog(LOG_INFO, "Generating a certificate signing request.");
162
163                 /*
164                  * Read our key from the file.  No, we don't just keep this
165                  * in memory from the above key-generation function, because
166                  * there is the possibility that the key was already on disk
167                  * and we didn't just generate it now.
168                  */
169                 fp = fopen(CTDL_KEY_PATH, "r");
170                 if (fp) {
171                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
172                         fclose(fp);
173                 }
174
175                 if (rsa) {
176
177                         /* Create a public key from the private key */
178                         if (pk=EVP_PKEY_new(), pk != NULL) {
179                                 EVP_PKEY_assign_RSA(pk, rsa);
180                                 if (req = X509_REQ_new(), req != NULL) {
181                                         const char *env;
182                                         /* Set the public key */
183                                         X509_REQ_set_pubkey(req, pk);
184                                         X509_REQ_set_version(req, 0L);
185                                         name = X509_REQ_get_subject_name(req);
186                                         X509_NAME_add_entry_by_txt(
187                                                 name, "O", MBSTRING_ASC,
188                                                 (unsigned char*)"Citadel Server",
189                                                 -1, -1, 0
190                                         );
191                                         X509_NAME_add_entry_by_txt(
192                                                 name, "OU", MBSTRING_ASC,
193                                                 (unsigned char*)"Default Certificate PLEASE CHANGE",
194                                                 -1, -1, 0
195                                         );
196                                         X509_NAME_add_entry_by_txt(
197                                                 name, "CN",
198                                                 MBSTRING_ASC, 
199                                                 (unsigned char*)"*",
200                                                 -1, -1, 0
201                                         );
202                                 
203                                         X509_REQ_set_subject_name(req, name);
204
205                                         /* Sign the CSR */
206                                         if (!X509_REQ_sign(req, pk, EVP_md5())) {
207                                                 syslog(LOG_WARNING, "X509_REQ_sign(): error");
208                                         }
209                                         else {
210                                                 /* Write it to disk. */ 
211                                                 fp = fopen(CTDL_CSR_PATH, "w");
212                                                 if (fp != NULL) {
213                                                         chmod(CTDL_CSR_PATH, 0600);
214                                                         PEM_write_X509_REQ(fp, req);
215                                                         fclose(fp);
216                                                 }
217                                                 else {
218                                                         syslog(LOG_WARNING, "Cannot write key: %s", CTDL_CSR_PATH);
219                                                         exit(1);
220                                                 }
221                                         }
222
223                                         X509_REQ_free(req);
224                                 }
225                         }
226
227                         RSA_free(rsa);
228                 }
229
230                 else {
231                         syslog(LOG_WARNING, "Unable to read private key.");
232                 }
233         }
234
235
236         /*
237          * Generate a self-signed certificate if we don't have one.
238          */
239         if (access(CTDL_CER_PATH, R_OK) != 0) {
240                 syslog(LOG_INFO, "Generating a self-signed certificate.");
241
242                 /* Same deal as before: always read the key from disk because
243                  * it may or may not have just been generated.
244                  */
245                 fp = fopen(CTDL_KEY_PATH, "r");
246                 if (fp) {
247                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
248                         fclose(fp);
249                 }
250
251                 /* This also holds true for the CSR. */
252                 req = NULL;
253                 cer = NULL;
254                 pk = NULL;
255                 if (rsa) {
256                         if (pk=EVP_PKEY_new(), pk != NULL) {
257                                 EVP_PKEY_assign_RSA(pk, rsa);
258                         }
259
260                         fp = fopen(CTDL_CSR_PATH, "r");
261                         if (fp) {
262                                 req = PEM_read_X509_REQ(fp, NULL, NULL, NULL);
263                                 fclose(fp);
264                         }
265
266                         if (req) {
267                                 if (cer = X509_new(), cer != NULL) {
268
269                                         ASN1_INTEGER_set(X509_get_serialNumber(cer), 0);
270                                         X509_set_issuer_name(cer, req->req_info->subject);
271                                         X509_set_subject_name(cer, req->req_info->subject);
272                                         X509_gmtime_adj(X509_get_notBefore(cer), 0);
273                                         X509_gmtime_adj(X509_get_notAfter(cer),(long)60*60*24*SIGN_DAYS);
274
275                                         req_pkey = X509_REQ_get_pubkey(req);
276                                         X509_set_pubkey(cer, req_pkey);
277                                         EVP_PKEY_free(req_pkey);
278                                         
279                                         /* Sign the cert */
280                                         if (!X509_sign(cer, pk, EVP_md5())) {
281                                                 syslog(LOG_WARNING, "X509_sign(): error");
282                                         }
283                                         else {
284                                                 /* Write it to disk. */ 
285                                                 fp = fopen(CTDL_CER_PATH, "w");
286                                                 if (fp != NULL) {
287                                                         chmod(CTDL_CER_PATH, 0600);
288                                                         PEM_write_X509(fp, cer);
289                                                         fclose(fp);
290                                                 }
291                                                 else {
292                                                         syslog(LOG_WARNING, "Cannot write key: %s", CTDL_CER_PATH);
293                                                         exit(1);
294                                                 }
295                                         }
296                                         X509_free(cer);
297                                 }
298                         }
299
300                         RSA_free(rsa);
301                 }
302         }
303
304         /*
305          * Now try to bind to the key and certificate.
306          * Note that we use SSL_CTX_use_certificate_chain_file() which allows
307          * the certificate file to contain intermediate certificates.
308          */
309         SSL_CTX_use_certificate_chain_file(ssl_ctx, CTDL_CER_PATH);
310         SSL_CTX_use_PrivateKey_file(ssl_ctx, CTDL_KEY_PATH, SSL_FILETYPE_PEM);
311         if ( !SSL_CTX_check_private_key(ssl_ctx) ) {
312                 syslog(LOG_WARNING, "Cannot install certificate: %s", ERR_reason_error_string(ERR_get_error()));
313         }
314         
315 }
316
317
318 /*
319  * starts SSL/TLS encryption for the current session.
320  */
321 void starttls(struct client_handle *ch) {
322         int retval, bits, alg_bits;
323
324         if (!ssl_ctx) {
325                 return;
326         }
327         if (!(ch->ssl_handle = SSL_new(ssl_ctx))) {
328                 syslog(LOG_WARNING, "SSL_new failed: %s", ERR_reason_error_string(ERR_get_error()));
329                 return;
330         }
331         if (!(SSL_set_fd(ch->ssl_handle, ch->sock))) {
332                 syslog(LOG_WARNING, "SSL_set_fd failed: %s", ERR_reason_error_string(ERR_get_error()));
333                 SSL_free(ch->ssl_handle);
334                 return;
335         }
336         retval = SSL_accept(ch->ssl_handle);
337         if (retval < 1) {
338                 long errval;
339                 const char *ssl_error_reason = NULL;
340
341                 errval = SSL_get_error(ch->ssl_handle, retval);
342                 ssl_error_reason = ERR_reason_error_string(ERR_get_error());
343                 if (ssl_error_reason == NULL) {
344                         syslog(LOG_WARNING, "SSL_accept failed: errval=%ld, retval=%d %s", errval, retval, strerror(errval));
345                 }
346                 else {
347                         syslog(LOG_WARNING, "SSL_accept failed: %s\n", ssl_error_reason);
348                 }
349                 sleep(1);
350                 retval = SSL_accept(ch->ssl_handle);
351         }
352         if (retval < 1) {
353                 long errval;
354                 const char *ssl_error_reason = NULL;
355
356                 errval = SSL_get_error(ch->ssl_handle, retval);
357                 ssl_error_reason = ERR_reason_error_string(ERR_get_error());
358                 if (ssl_error_reason == NULL) {
359                         syslog(LOG_WARNING, "SSL_accept failed: errval=%ld, retval=%d (%s)", errval, retval, strerror(errval));
360                 }
361                 else {
362                         syslog(LOG_WARNING, "SSL_accept failed: %s", ssl_error_reason);
363                 }
364                 SSL_free(ch->ssl_handle);
365                 ch->ssl_handle = NULL;
366                 return;
367         }
368         else {
369                 syslog(LOG_INFO, "SSL_accept success");
370         }
371         BIO_set_close(ch->ssl_handle->rbio, BIO_NOCLOSE);
372         bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ch->ssl_handle), &alg_bits);
373         syslog(LOG_INFO, "SSL/TLS using %s on %s (%d of %d bits)",
374                 SSL_CIPHER_get_name(SSL_get_current_cipher(ch->ssl_handle)),
375                 SSL_CIPHER_get_version(SSL_get_current_cipher(ch->ssl_handle)),
376                 bits, alg_bits);
377
378         syslog(LOG_INFO, "SSL started");
379 }
380
381
382 /*
383  * shuts down the TLS connection
384  */
385 void endtls(struct client_handle *ch)
386 {
387         syslog(LOG_INFO, "Ending SSL/TLS");
388         if (ch->ssl_handle != NULL) {
389                 SSL_shutdown(ch->ssl_handle);
390                 SSL_get_SSL_CTX(ch->ssl_handle);
391                 SSL_free(ch->ssl_handle);
392         }
393         ch->ssl_handle = NULL;
394 }
395
396
397 /*
398  * Send binary data to the client encrypted.
399  */
400 int client_write_ssl(struct client_handle *ch, char *buf, int nbytes)
401 {
402         int retval;
403         int nremain;
404         char junk[1];
405
406         if (ch->ssl_handle == NULL) return(-1);
407
408         nremain = nbytes;
409         while (nremain > 0) {
410                 if (SSL_want_write(ch->ssl_handle)) {
411                         if ((SSL_read(ch->ssl_handle, junk, 0)) < 1) {
412                                 syslog(LOG_WARNING, "SSL_read in client_write: %s", ERR_reason_error_string(ERR_get_error()));
413                         }
414                 }
415                 retval = SSL_write(ch->ssl_handle, &buf[nbytes - nremain], nremain);
416                 if (retval < 1) {
417                         long errval;
418
419                         errval = SSL_get_error(ch->ssl_handle, retval);
420                         if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
421                                 sleep(1);
422                                 continue;
423                         }
424                         syslog(LOG_WARNING, "SSL_write got error %ld, ret %d", errval, retval);
425                         if (retval == -1) {
426                                 syslog(LOG_WARNING, "errno is %d", errno);
427                                 endtls(ch);
428                         }
429                         return -1;
430                 }
431                 nremain -= retval;
432         }
433         return 0;
434 }
435
436
437 /*
438  * read data from the encrypted layer.
439  */
440 int client_read_ssl(struct client_handle *ch, char *buf, int nbytes)
441 {
442         int bytes_read = 0;
443         int rlen = 0;
444         char junk[1];
445
446         if (ch->ssl_handle == NULL) return(-1);
447
448         while (bytes_read < nbytes) {
449                 if (SSL_want_read(ch->ssl_handle)) {
450                         if ((SSL_write(ch->ssl_handle, junk, 0)) < 1) {
451                                 syslog(LOG_WARNING, "SSL_write in client_read");
452                         }
453                 }
454                 rlen = SSL_read(ch->ssl_handle, &buf[bytes_read], nbytes-bytes_read);
455                 if (rlen < 1) {
456                         long errval;
457
458                         errval = SSL_get_error(ch->ssl_handle, rlen);
459                         if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
460                                 sleep(1);
461                                 continue;
462                         }
463                         syslog(LOG_WARNING, "SSL_read error %ld", errval);
464                         endtls(ch);
465                         return (-1);
466                 }
467                 bytes_read += rlen;
468         }
469         return(bytes_read);
470 }