removed some debugs
[citadel.git] / citadel / modules / crypto / serv_crypto.c
1 // Copyright (c) 1987-2022 by the citadel.org team
2 //
3 // This program is open source software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License version 3.
5 //
6 // This program is distributed in the hope that it will be useful,
7 // but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9 // GNU General Public License for more details.
10
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include "sysdep.h"
16
17 #ifdef HAVE_OPENSSL
18 #include <openssl/ssl.h>
19 #include <openssl/err.h>
20 #include <openssl/rand.h>
21 #endif
22
23 #include <time.h>
24
25 #ifdef HAVE_PTHREAD_H
26 #include <pthread.h>
27 #endif
28
29 #ifdef HAVE_SYS_SELECT_H
30 #include <sys/select.h>
31 #endif
32
33 #include <stdio.h>
34 #include <libcitadel.h>
35 #include "server.h"
36 #include "serv_crypto.h"
37 #include "sysdep_decls.h"
38 #include "citadel.h"
39 #include "config.h"
40 #include "ctdl_module.h"
41
42 #ifdef HAVE_OPENSSL
43
44 SSL_CTX *ssl_ctx = NULL;                // This SSL context is used for all sessions.
45 char *ssl_cipher_list = CIT_CIPHERS;
46
47 // If a private key does not exist, generate one now.
48 void generate_key(char *keyfilename) {
49         int ret = 0;
50         RSA *rsa = NULL;
51         BIGNUM *bne = NULL;
52         int bits = 2048;
53         unsigned long e = RSA_F4;
54         FILE *fp;
55
56         if (access(keyfilename, R_OK) == 0) {   // Already have one.
57                 syslog(LOG_INFO, "crypto: %s exists and is readable", keyfilename);
58                 return;
59         }
60
61         syslog(LOG_INFO, "crypto: generating RSA key pair");
62  
63         // generate rsa key
64         bne = BN_new();
65         ret = BN_set_word(bne,e);
66         if (ret != 1) {
67                 goto free_all;
68         }
69  
70         rsa = RSA_new();
71         ret = RSA_generate_key_ex(rsa, bits, bne, NULL);
72         if (ret != 1) {
73                 goto free_all;
74         }
75
76         // write the key file
77         fp = fopen(keyfilename, "w");
78         if (fp != NULL) {
79                 chmod(keyfilename, 0600);
80                 if (PEM_write_RSAPrivateKey(fp, // the file
81                                         rsa,    // the key
82                                         NULL,   // no enc
83                                         NULL,   // no passphrase
84                                         0,      // no passphrase
85                                         NULL,   // no callback
86                                         NULL    // no callback
87                 ) != 1) {
88                         syslog(LOG_ERR, "crypto: cannot write key: %s", ERR_reason_error_string(ERR_get_error()));
89                         unlink(keyfilename);
90                 }
91                 fclose(fp);
92         }
93
94         // free the memory we used
95 free_all:
96         RSA_free(rsa);
97         BN_free(bne);
98 }
99
100
101 // If a certificate does not exist, generate a self-signed one now.
102 void generate_certificate(char *keyfilename, char *certfilename) {
103         RSA *private_key = NULL;
104         EVP_PKEY *public_key = NULL;
105         X509_REQ *certificate_signing_request = NULL;
106         X509_NAME *name = NULL;
107         X509 *certificate = NULL;
108         FILE *fp;
109
110         if (access(certfilename, R_OK) == 0) {                  // already have one.
111                 syslog(LOG_INFO, "crypto: %s exists and is readable", certfilename);
112                 return;
113         }
114
115         syslog(LOG_INFO, "crypto: generating a self-signed certificate");
116
117         // Read in our private key.
118         fp = fopen(keyfilename, "r");
119         if (fp) {
120                 private_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
121                 fclose(fp);
122         }
123
124         if (!private_key) {
125                 syslog(LOG_ERR, "crypto: cannot read the private key");
126                 return;
127         }
128
129         // Create a public key from the private key
130         public_key = EVP_PKEY_new();
131         if (!public_key) {
132                 syslog(LOG_ERR, "crypto: cannot allocate public key");
133                 RSA_free(private_key);
134                 return;
135         }
136         EVP_PKEY_assign_RSA(public_key, private_key);
137
138         // Create a certificate signing request
139         certificate_signing_request = X509_REQ_new();
140         if (!certificate_signing_request) {
141                 syslog(LOG_ERR, "crypto: cannot allocate certificate signing request");
142                 RSA_free(private_key);
143                 EVP_PKEY_free(public_key);
144                 return;
145         }
146
147         // Assign the public key to the certificate signing request
148         X509_REQ_set_pubkey(certificate_signing_request, public_key);
149         X509_REQ_set_version(certificate_signing_request, 0L);
150
151         // Tell it who we are
152         name = X509_REQ_get_subject_name(certificate_signing_request);
153         X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned const char *)"ZZ", -1, -1, 0);
154         X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, (unsigned const char *)"The World", -1, -1, 0);
155         X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, (unsigned const char *)"My Location", -1, -1, 0);
156         X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned const char *)"Generic certificate", -1, -1, 0);
157         X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, (unsigned const char *)"Citadel server", -1, -1, 0);
158         X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned const char *)"*", -1, -1, 0);
159         X509_REQ_set_subject_name(certificate_signing_request, name);
160
161         // Sign the CSR
162         if (!X509_REQ_sign(certificate_signing_request, public_key, EVP_md5())) {
163                 syslog(LOG_ERR, "crypto: X509_REQ_sign(): error");
164                 X509_REQ_free(certificate_signing_request);
165                 RSA_free(private_key);
166                 EVP_PKEY_free(public_key);
167                 return;
168         }
169
170         // Generate the self-signed certificate
171         certificate = X509_new();
172         if (!certificate) {
173                 syslog(LOG_ERR, "crypto: cannot allocate X.509 certificate");
174                 X509_REQ_free(certificate_signing_request);
175                 RSA_free(private_key);
176                 EVP_PKEY_free(public_key);
177                 return;
178         }
179
180         ASN1_INTEGER_set(X509_get_serialNumber(certificate), 0);
181         X509_set_issuer_name(certificate, X509_REQ_get_subject_name(certificate_signing_request));
182         X509_set_subject_name(certificate, X509_REQ_get_subject_name(certificate_signing_request));
183         X509_gmtime_adj(X509_get_notBefore(certificate), 0);
184         X509_gmtime_adj(X509_get_notAfter(certificate), (long)60*60*24*SIGN_DAYS);
185         X509_set_pubkey(certificate, public_key);
186         X509_REQ_free(certificate_signing_request);             // We're done with the CSR; free it
187
188         // Finally, sign the certificate with our private key.
189         if (!X509_sign(certificate, public_key, EVP_md5())) {
190                 syslog(LOG_ERR, "crypto: X509_sign() error");
191                 X509_free(certificate);
192                 RSA_free(private_key);
193                 EVP_PKEY_free(public_key);
194                 return;
195         }
196
197         // Write the certificate to disk
198         fp = fopen(certfilename, "w");
199         if (fp != NULL) {
200                 chmod(certfilename, 0600);
201                 PEM_write_X509(fp, certificate);
202                 fclose(fp);
203         }
204         else {
205                 syslog(LOG_ERR, "crypto: %s: %m", certfilename);
206         }
207
208         X509_free(certificate);
209         EVP_PKEY_free(public_key);
210         // do not RSA_free(private_key); because it was freed by EVP_PKEY_free() above
211 }
212
213
214 // Set the private key and certificate chain for the global SSL Context.
215 // This is called during initialization, and can be called again later if the certificate changes.
216 void bind_to_key_and_certificate(void) {
217
218         SSL_CTX *old_ctx = NULL;
219         SSL_CTX *new_ctx = NULL;
220
221         const SSL_METHOD *method = SSLv23_server_method();
222         if (!method) {
223                 syslog(LOG_ERR, "crypto: SSLv23_server_method() failed: %s", ERR_reason_error_string(ERR_get_error()));
224                 return;
225         }
226
227         new_ctx = SSL_CTX_new(method);
228         if (!new_ctx) {
229                 syslog(LOG_ERR, "crypto: SSL_CTX_new failed: %s", ERR_reason_error_string(ERR_get_error()));
230                 return;
231         }
232
233         if (!(SSL_CTX_set_cipher_list(new_ctx, ssl_cipher_list))) {
234                 syslog(LOG_ERR, "crypto: SSL_CTX_set_cipher_list failed: %s", ERR_reason_error_string(ERR_get_error()));
235                 return;
236         }
237
238         syslog(LOG_DEBUG, "crypto: using certificate chain %s", file_crpt_file_cer);
239         if (!SSL_CTX_use_certificate_chain_file(new_ctx, file_crpt_file_cer)) {
240                 syslog(LOG_ERR, "crypto: SSL_CTX_use_certificate_chain_file failed: %s", ERR_reason_error_string(ERR_get_error()));
241                 return;
242         }
243
244         syslog(LOG_DEBUG, "crypto: using private key %s", file_crpt_file_key);
245         if (!SSL_CTX_use_PrivateKey_file(new_ctx, file_crpt_file_key, SSL_FILETYPE_PEM)) {
246                 syslog(LOG_ERR, "crypto: SSL_CTX_use_PrivateKey_file failed: %s", ERR_reason_error_string(ERR_get_error()));
247                 return;
248         }
249
250         old_ctx = ssl_ctx;
251         ssl_ctx = new_ctx;              // All future binds will use the new certificate
252
253         if (old_ctx != NULL) {
254                 sleep(1);               // Hopefully wait until all in-progress binds to the old certificate have completed
255                 SSL_CTX_free(old_ctx);
256         }
257 }
258
259
260 // Check the modification time of the key and certificate files.  Reload if either one changed.
261 void update_key_and_cert_if_needed(void) {
262         static time_t previous_mtime = 0;
263         struct stat keystat;
264         struct stat certstat;
265
266         if (stat(file_crpt_file_key, &keystat) != 0) {
267                 syslog(LOG_ERR, "%s: %s", file_crpt_file_key, strerror(errno));
268                 return;
269         }
270         if (stat(file_crpt_file_cer, &certstat) != 0) {
271                 syslog(LOG_ERR, "%s: %s", file_crpt_file_cer, strerror(errno));
272                 return;
273         }
274
275         if ((keystat.st_mtime + certstat.st_mtime) != previous_mtime) {
276                 begin_critical_section(S_OPENSSL);
277                 bind_to_key_and_certificate();
278                 end_critical_section(S_OPENSSL);
279                 previous_mtime = keystat.st_mtime + certstat.st_mtime;
280         }
281 }
282
283
284 // Initialize the TLS subsystem.
285 void init_ssl(void) {
286
287         // Initialize the OpenSSL library
288         SSL_library_init();
289         SSL_load_error_strings();
290
291         // Load (or generate) a key and certificate
292         mkdir(ctdl_key_dir, 0700);                                      // If the keys directory does not exist, create it
293         generate_key(file_crpt_file_key);                               // If a private key does not exist, create it
294         generate_certificate(file_crpt_file_key, file_crpt_file_cer);   // If a certificate does not exist, create it
295         bind_to_key_and_certificate();                                  // Load key and cert from disk, and bind to them.
296
297         // Register some Citadel protocol commands for dealing with encrypted sessions
298         CtdlRegisterProtoHook(cmd_stls, "STLS", "Start TLS session");
299         CtdlRegisterProtoHook(cmd_gtls, "GTLS", "Get TLS session status");
300         CtdlRegisterSessionHook(endtls, EVT_STOP, PRIO_STOP + 10);
301 }
302
303
304 // client_write_ssl() Send binary data to the client encrypted.
305 void client_write_ssl(const char *buf, int nbytes) {
306         int retval;
307         int nremain;
308         char junk[1];
309
310         nremain = nbytes;
311
312         while (nremain > 0) {
313                 if (SSL_want_write(CC->ssl)) {
314                         if ((SSL_read(CC->ssl, junk, 0)) < 1) {
315                                 syslog(LOG_DEBUG, "crypto: SSL_read in client_write: %s", ERR_reason_error_string(ERR_get_error()));
316                         }
317                 }
318                 retval =
319                     SSL_write(CC->ssl, &buf[nbytes - nremain], nremain);
320                 if (retval < 1) {
321                         long errval;
322
323                         errval = SSL_get_error(CC->ssl, retval);
324                         if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
325                                 sleep(1);
326                                 continue;
327                         }
328                         syslog(LOG_DEBUG, "crypto: SSL_write got error %ld, ret %d", errval, retval);
329                         if (retval == -1) {
330                                 syslog(LOG_DEBUG, "crypto: errno is %d", errno);
331                         }
332                         endtls();
333                         client_write(&buf[nbytes - nremain], nremain);
334                         return;
335                 }
336                 nremain -= retval;
337         }
338 }
339
340
341 // read data from the encrypted layer.
342 int client_read_sslbuffer(StrBuf *buf, int timeout) {
343         char sbuf[16384];       // OpenSSL communicates in 16k blocks, so let's speak its native tongue.
344         int rlen;
345         char junk[1];
346         SSL *pssl = CC->ssl;
347
348         if (pssl == NULL) return(-1);
349
350         while (1) {
351                 if (SSL_want_read(pssl)) {
352                         if ((SSL_write(pssl, junk, 0)) < 1) {
353                                 syslog(LOG_DEBUG, "crypto: SSL_write in client_read");
354                         }
355                 }
356                 rlen = SSL_read(pssl, sbuf, sizeof(sbuf));
357                 if (rlen < 1) {
358                         long errval;
359
360                         errval = SSL_get_error(pssl, rlen);
361                         if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
362                                 sleep(1);
363                                 continue;
364                         }
365                         syslog(LOG_DEBUG, "crypto: SSL_read got error %ld", errval);
366                         endtls();
367                         return (-1);
368                 }
369                 StrBufAppendBufPlain(buf, sbuf, rlen, 0);
370                 return rlen;
371         }
372         return (0);
373 }
374
375
376 int client_readline_sslbuffer(StrBuf *Line, StrBuf *IOBuf, const char **Pos, int timeout) {
377         const char *pos = NULL;
378         const char *pLF;
379         int len, rlen;
380         int nSuccessLess = 0;
381         const char *pch = NULL;
382         
383         if ((Line == NULL) || (Pos == NULL) || (IOBuf == NULL)) {
384                 if (Pos != NULL) {
385                         *Pos = NULL;
386                 }
387                 return -1;
388         }
389
390         pos = *Pos;
391         if ((StrLength(IOBuf) > 0) && (pos != NULL) && (pos < ChrPtr(IOBuf) + StrLength(IOBuf))) {
392                 pch = pos;
393                 pch = strchr(pch, '\n');
394                 
395                 if (pch == NULL) {
396                         StrBufAppendBufPlain(Line, pos, StrLength(IOBuf) - (pos - ChrPtr(IOBuf)), 0);
397                         FlushStrBuf(IOBuf);
398                         *Pos = NULL;
399                 }
400                 else {
401                         int n = 0;
402                         if ((pch > ChrPtr(IOBuf)) && (*(pch - 1) == '\r')) {
403                                 n = 1;
404                         }
405                         StrBufAppendBufPlain(Line, pos, (pch - pos - n), 0);
406
407                         if (StrLength(IOBuf) <= (pch - ChrPtr(IOBuf) + 1)) {
408                                 FlushStrBuf(IOBuf);
409                                 *Pos = NULL;
410                         }
411                         else {
412                                 *Pos = pch + 1;
413                         }
414                         return StrLength(Line);
415                 }
416         }
417
418         pLF = NULL;
419         while ((nSuccessLess < timeout) && (pLF == NULL) && (CC->ssl != NULL)) {
420
421                 rlen = client_read_sslbuffer(IOBuf, timeout);
422                 if (rlen < 1) {
423                         return -1;
424                 }
425                 else if (rlen > 0) {
426                         pLF = strchr(ChrPtr(IOBuf), '\n');
427                 }
428         }
429         *Pos = NULL;
430         if (pLF != NULL) {
431                 pos = ChrPtr(IOBuf);
432                 len = pLF - pos;
433                 if (len > 0 && (*(pLF - 1) == '\r') )
434                         len --;
435                 StrBufAppendBufPlain(Line, pos, len, 0);
436                 if (pLF + 1 >= ChrPtr(IOBuf) + StrLength(IOBuf)) {
437                         FlushStrBuf(IOBuf);
438                 }
439                 else  {
440                         *Pos = pLF + 1;
441                 }
442                 return StrLength(Line);
443         }
444         return -1;
445 }
446
447
448 int client_read_sslblob(StrBuf *Target, long bytes, int timeout) {
449         long baselen;
450         long RemainRead;
451         int retval = 0;
452
453         baselen = StrLength(Target);
454
455         if (StrLength(CC->RecvBuf.Buf) > 0) {
456                 long RemainLen;
457                 long TotalLen;
458                 const char *pchs;
459
460                 if (CC->RecvBuf.ReadWritePointer == NULL) {
461                         CC->RecvBuf.ReadWritePointer = ChrPtr(CC->RecvBuf.Buf);
462                 }
463                 pchs = ChrPtr(CC->RecvBuf.Buf);
464                 TotalLen = StrLength(CC->RecvBuf.Buf);
465                 RemainLen = TotalLen - (pchs - CC->RecvBuf.ReadWritePointer);
466                 if (RemainLen > bytes) {
467                         RemainLen = bytes;
468                 }
469                 if (RemainLen > 0) {
470                         StrBufAppendBufPlain(Target, CC->RecvBuf.ReadWritePointer, RemainLen, 0);
471                         CC->RecvBuf.ReadWritePointer += RemainLen;
472                 }
473                 if ((ChrPtr(CC->RecvBuf.Buf) + StrLength(CC->RecvBuf.Buf)) <= CC->RecvBuf.ReadWritePointer) {
474                         CC->RecvBuf.ReadWritePointer = NULL;
475                         FlushStrBuf(CC->RecvBuf.Buf);
476                 }
477         }
478
479         if (StrLength(Target) >= bytes + baselen) {
480                 return 1;
481         }
482
483         CC->RecvBuf.ReadWritePointer = NULL;
484
485         while ((StrLength(Target) < bytes + baselen) && (retval >= 0)) {
486                 retval = client_read_sslbuffer(CC->RecvBuf.Buf, timeout);
487                 if (retval >= 0) {
488                         RemainRead = bytes - (StrLength (Target) - baselen);
489                         if (RemainRead < StrLength(CC->RecvBuf.Buf)) {
490                                 StrBufAppendBufPlain(
491                                         Target, 
492                                         ChrPtr(CC->RecvBuf.Buf), 
493                                         RemainRead, 0);
494                                 CC->RecvBuf.ReadWritePointer = ChrPtr(CC->RecvBuf.Buf) + RemainRead;
495                                 break;
496                         }
497                         StrBufAppendBuf(Target, CC->RecvBuf.Buf, 0);
498                         FlushStrBuf(CC->RecvBuf.Buf);
499                 }
500                 else {
501                         FlushStrBuf(CC->RecvBuf.Buf);
502                         return -1;
503         
504                 }
505         }
506         return 1;
507 }
508
509
510 // CtdlStartTLS() starts TLS encryption for the current session.  It
511 // must be supplied with pre-generated strings for responses of "ok," "no
512 // support for TLS," and "error" so that we can use this in any protocol.
513 void CtdlStartTLS(char *ok_response, char *nosup_response, char *error_response) {
514         int retval, bits, alg_bits;
515
516         if (CC->redirect_ssl) {
517                 syslog(LOG_ERR, "crypto: attempt to begin SSL on an already encrypted connection");
518                 if (error_response != NULL) {
519                         cprintf("%s", error_response);
520                 }
521                 return;
522         }
523
524         if (!ssl_ctx) {
525                 syslog(LOG_ERR, "crypto: SSL failed: context has not been initialized");
526                 if (nosup_response != NULL) {
527                         cprintf("%s", nosup_response);
528                 }
529                 return;
530         }
531
532         update_key_and_cert_if_needed();                // did someone update the key or cert?  if so, re-bind them
533
534         if (!(CC->ssl = SSL_new(ssl_ctx))) {
535                 syslog(LOG_ERR, "crypto: SSL_new failed: %s", ERR_reason_error_string(ERR_get_error()));
536                 if (error_response != NULL) {
537                         cprintf("%s", error_response);
538                 }
539                 return;
540         }
541         if (!(SSL_set_fd(CC->ssl, CC->client_socket))) {
542                 syslog(LOG_ERR, "crypto: SSL_set_fd failed: %s", ERR_reason_error_string(ERR_get_error()));
543                 SSL_free(CC->ssl);
544                 CC->ssl = NULL;
545                 if (error_response != NULL) {
546                         cprintf("%s", error_response);
547                 }
548                 return;
549         }
550         if (ok_response != NULL) {
551                 cprintf("%s", ok_response);
552         }
553         retval = SSL_accept(CC->ssl);
554         if (retval < 1) {
555                 // Can't notify the client of an error here; they will
556                 // discover the problem at the SSL layer and should
557                 // revert to unencrypted communications.
558                 syslog(LOG_ERR, "crypto: SSL_accept failed: %s", ERR_reason_error_string(ERR_get_error()));
559                 SSL_free(CC->ssl);
560                 CC->ssl = NULL;
561                 return;
562         }
563         bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(CC->ssl), &alg_bits);
564         syslog(LOG_INFO, "crypto: TLS using %s on %s (%d of %d bits)",
565                 SSL_CIPHER_get_name(SSL_get_current_cipher(CC->ssl)),
566                 SSL_CIPHER_get_version(SSL_get_current_cipher(CC->ssl)),
567                 bits, alg_bits
568         );
569         CC->redirect_ssl = 1;
570 }
571
572
573 // cmd_stls() starts TLS encryption for the current session
574 void cmd_stls(char *params) {
575         char ok_response[SIZ];
576         char nosup_response[SIZ];
577         char error_response[SIZ];
578
579         unbuffer_output();
580
581         sprintf(ok_response, "%d Begin TLS negotiation now\n", CIT_OK);
582         sprintf(nosup_response, "%d TLS not supported here\n", ERROR + CMD_NOT_SUPPORTED);
583         sprintf(error_response, "%d TLS negotiation error\n", ERROR + INTERNAL_ERROR);
584
585         CtdlStartTLS(ok_response, nosup_response, error_response);
586 }
587
588
589 // cmd_gtls() returns status info about the TLS connection
590 void cmd_gtls(char *params) {
591         int bits, alg_bits;
592
593         if (!CC->ssl || !CC->redirect_ssl) {
594                 cprintf("%d Session is not encrypted.\n", ERROR);
595                 return;
596         }
597         bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(CC->ssl), &alg_bits);
598         cprintf("%d %s|%s|%d|%d\n", CIT_OK,
599                 SSL_CIPHER_get_version(SSL_get_current_cipher(CC->ssl)),
600                 SSL_CIPHER_get_name(SSL_get_current_cipher(CC->ssl)),
601                 alg_bits, bits);
602 }
603
604
605 // endtls() shuts down the TLS connection
606 void endtls(void) {
607         if (!CC->ssl) {
608                 CC->redirect_ssl = 0;
609                 return;
610         }
611
612         syslog(LOG_INFO, "crypto: ending TLS on this session");
613         SSL_shutdown(CC->ssl);
614         SSL_free(CC->ssl);
615         CC->ssl = NULL;
616         CC->redirect_ssl = 0;
617 }
618
619 #endif  // HAVE_OPENSSL