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