OpenSSL no longer requires thread locking callbacks. REMOVED FROM WEBCIT-NG
[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-2021 by the citadel.org team
6 //
7 // This program is open source software.  It runs great on the
8 // Linux operating system (and probably elsewhere).  You can use,
9 // copy, and run it under the terms of the GNU General Public
10 // License version 3.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16
17 #include "webcit.h"
18
19 SSL_CTX *ssl_ctx;               // SSL context
20 char *ssl_cipher_list = DEFAULT_SSL_CIPHER_LIST;
21
22
23 // Generate a private key for SSL
24 void generate_key(char *keyfilename) {
25         int ret = 0;
26         RSA *rsa = NULL;
27         BIGNUM *bne = NULL;
28         int bits = 2048;
29         unsigned long e = RSA_F4;
30         FILE *fp;
31
32         if (access(keyfilename, R_OK) == 0) {
33                 return;
34         }
35
36         syslog(LOG_INFO, "crypto: generating RSA key pair");
37
38         // generate rsa key
39         bne = BN_new();
40         ret = BN_set_word(bne, e);
41         if (ret != 1) {
42                 goto free_all;
43         }
44
45         rsa = RSA_new();
46         ret = RSA_generate_key_ex(rsa, bits, bne, NULL);
47         if (ret != 1) {
48                 goto free_all;
49         }
50         // write the key file
51         fp = fopen(keyfilename, "w");
52         if (fp != NULL) {
53                 chmod(keyfilename, 0600);
54                 if (PEM_write_RSAPrivateKey(fp,         // the file */
55                                             rsa,        // the key */
56                                             NULL,       // no enc */
57                                             NULL,       // no passphrase
58                                             0,          // no passphrase
59                                             NULL,       // no callback
60                                             NULL        // no callbk
61                 ) != 1) {
62                         syslog(LOG_ERR, "crypto: cannot write key: %s", ERR_reason_error_string(ERR_get_error()));
63                         unlink(keyfilename);
64                 }
65                 fclose(fp);
66         }
67         // 4. free
68       free_all:
69         RSA_free(rsa);
70         BN_free(bne);
71 }
72
73
74 // Initialize ssl engine, load certs and initialize openssl internals
75 void init_ssl(void) {
76         const SSL_METHOD *ssl_method;
77         RSA *rsa = NULL;
78         X509_REQ *req = NULL;
79         X509 *cer = NULL;
80         EVP_PKEY *pk = NULL;
81         EVP_PKEY *req_pkey = NULL;
82         X509_NAME *name = NULL;
83         FILE *fp;
84         char buf[SIZ];
85         int rv = 0;
86
87         // Initialize SSL transport layer
88         SSL_library_init();
89         SSL_load_error_strings();
90         ssl_method = SSLv23_server_method();
91         if (!(ssl_ctx = SSL_CTX_new(ssl_method))) {
92                 syslog(LOG_WARNING, "SSL_CTX_new failed: %s", ERR_reason_error_string(ERR_get_error()));
93                 return;
94         }
95
96         syslog(LOG_INFO, "Requesting cipher list: %s", ssl_cipher_list);
97         if (!(SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher_list))) {
98                 syslog(LOG_WARNING, "SSL_CTX_set_cipher_list failed: %s", ERR_reason_error_string(ERR_get_error()));
99                 return;
100         }
101
102         // Get our certificates in order.
103         // First, create the key/cert directory if it's not there already...
104         mkdir(CTDL_CRYPTO_DIR, 0700);
105
106         // If we still don't have a private key, generate one.
107         generate_key(CTDL_KEY_PATH);
108
109         // If there is no certificate file on disk, we will be generating a self-signed certificate
110         // in the next step.  Therefore, if we have neither a CSR nor a certificate, generate
111         // the CSR in this step so that the next step may commence.
112         if ((access(CTDL_CER_PATH, R_OK) != 0) && (access(CTDL_CSR_PATH, R_OK) != 0)) {
113                 syslog(LOG_INFO, "Generating a certificate signing request.");
114
115                 // Read our key from the file.  No, we don't just keep this
116                 // in memory from the above key-generation function, because
117                 // there is the possibility that the key was already on disk
118                 // and we didn't just generate it now.
119                 fp = fopen(CTDL_KEY_PATH, "r");
120                 if (fp) {
121                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
122                         fclose(fp);
123                 }
124
125                 if (rsa) {
126                         // Create a public key from the private key
127                         if (pk = EVP_PKEY_new(), pk != NULL) {
128                                 EVP_PKEY_assign_RSA(pk, rsa);
129                                 if (req = X509_REQ_new(), req != NULL) {
130                                         const char *env;
131                                         // Set the public key
132                                         X509_REQ_set_pubkey(req, pk);
133                                         X509_REQ_set_version(req, 0L);
134                                         name = X509_REQ_get_subject_name(req);
135                                         X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *) "Citadel Server", -1, -1, 0);
136                                         X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, (unsigned char *) "Default Certificate PLEASE CHANGE", -1, -1, 0);
137                                         X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *) "*", -1, -1, 0);
138                                         X509_REQ_set_subject_name(req, name);
139
140                                         // Sign the CSR
141                                         if (!X509_REQ_sign(req, pk, EVP_md5())) {
142                                                 syslog(LOG_WARNING, "X509_REQ_sign(): error");
143                                         }
144                                         else {
145                                                 // Write it to disk
146                                                 fp = fopen(CTDL_CSR_PATH, "w");
147                                                 if (fp != NULL) {
148                                                         chmod(CTDL_CSR_PATH, 0600);
149                                                         PEM_write_X509_REQ(fp, req);
150                                                         fclose(fp);
151                                                 }
152                                                 else {
153                                                         syslog(LOG_WARNING, "Cannot write key: %s", CTDL_CSR_PATH);
154                                                         exit(1);
155                                                 }
156                                         }
157                                         X509_REQ_free(req);
158                                 }
159                         }
160                         RSA_free(rsa);
161                 }
162                 else {
163                         syslog(LOG_WARNING, "Unable to read private key.");
164                 }
165         }
166
167         // Generate a self-signed certificate if we don't have one.
168         if (access(CTDL_CER_PATH, R_OK) != 0) {
169                 syslog(LOG_INFO, "Generating a self-signed certificate.");
170
171                 // Same deal as before: always read the key from disk because
172                 // it may or may not have just been generated.
173                 fp = fopen(CTDL_KEY_PATH, "r");
174                 if (fp) {
175                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
176                         fclose(fp);
177                 }
178
179                 // This also holds true for the CSR
180                 req = NULL;
181                 cer = NULL;
182                 pk = NULL;
183                 if (rsa) {
184                         if (pk = EVP_PKEY_new(), pk != NULL) {
185                                 EVP_PKEY_assign_RSA(pk, rsa);
186                         }
187
188                         fp = fopen(CTDL_CSR_PATH, "r");
189                         if (fp) {
190                                 req = PEM_read_X509_REQ(fp, NULL, NULL, NULL);
191                                 fclose(fp);
192                         }
193
194                         if (req) {
195                                 if (cer = X509_new(), cer != NULL) {
196                                         ASN1_INTEGER_set(X509_get_serialNumber(cer), 0);
197                                         X509_set_issuer_name(cer, X509_REQ_get_subject_name(req));
198                                         X509_set_subject_name(cer, X509_REQ_get_subject_name(req));
199                                         X509_gmtime_adj(X509_get_notBefore(cer), 0);
200                                         X509_gmtime_adj(X509_get_notAfter(cer), (long) 60 * 60 * 24 * SIGN_DAYS);
201                                         req_pkey = X509_REQ_get_pubkey(req);
202                                         X509_set_pubkey(cer, req_pkey);
203                                         EVP_PKEY_free(req_pkey);
204
205                                         // Sign the cert
206                                         if (!X509_sign(cer, pk, EVP_md5())) {
207                                                 syslog(LOG_WARNING, "X509_sign(): error");
208                                         }
209                                         else {  // Write it to disk
210                                                 fp = fopen(CTDL_CER_PATH, "w");
211                                                 if (fp != NULL) {
212                                                         chmod(CTDL_CER_PATH, 0600);
213                                                         PEM_write_X509(fp, cer);
214                                                         fclose(fp);
215                                                 }
216                                                 else {
217                                                         syslog(LOG_WARNING, "Cannot write key: %s", CTDL_CER_PATH);
218                                                         exit(1);
219                                                 }
220                                         }
221                                         X509_free(cer);
222                                 }
223                         }
224                         RSA_free(rsa);
225                 }
226         }
227
228         // Now try to bind to the key and certificate.
229         // Note that we use SSL_CTX_use_certificate_chain_file() which allows
230         // the certificate file to contain intermediate certificates.
231         SSL_CTX_use_certificate_chain_file(ssl_ctx, CTDL_CER_PATH);
232         SSL_CTX_use_PrivateKey_file(ssl_ctx, CTDL_KEY_PATH, SSL_FILETYPE_PEM);
233         if (!SSL_CTX_check_private_key(ssl_ctx)) {
234                 syslog(LOG_WARNING, "Cannot install certificate: %s", ERR_reason_error_string(ERR_get_error()));
235         }
236
237 }
238
239
240 // starts SSL/TLS encryption for the current session.
241 void starttls(struct client_handle *ch) {
242         int retval, bits, alg_bits;
243
244         if (!ssl_ctx) {
245                 return;
246         }
247         if (!(ch->ssl_handle = SSL_new(ssl_ctx))) {
248                 syslog(LOG_WARNING, "SSL_new failed: %s", ERR_reason_error_string(ERR_get_error()));
249                 return;
250         }
251         if (!(SSL_set_fd(ch->ssl_handle, ch->sock))) {
252                 syslog(LOG_WARNING, "SSL_set_fd failed: %s", ERR_reason_error_string(ERR_get_error()));
253                 SSL_free(ch->ssl_handle);
254                 return;
255         }
256         retval = SSL_accept(ch->ssl_handle);
257         if (retval < 1) {
258                 long errval;
259                 const char *ssl_error_reason = NULL;
260
261                 errval = SSL_get_error(ch->ssl_handle, retval);
262                 ssl_error_reason = ERR_reason_error_string(ERR_get_error());
263                 if (ssl_error_reason == NULL) {
264                         syslog(LOG_WARNING, "SSL_accept failed: errval=%ld, retval=%d %s", errval, retval, strerror(errval));
265                 }
266                 else {
267                         syslog(LOG_WARNING, "SSL_accept failed: %s\n", ssl_error_reason);
268                 }
269                 sleep(1);
270                 retval = SSL_accept(ch->ssl_handle);
271         }
272         if (retval < 1) {
273                 long errval;
274                 const char *ssl_error_reason = NULL;
275
276                 errval = SSL_get_error(ch->ssl_handle, retval);
277                 ssl_error_reason = ERR_reason_error_string(ERR_get_error());
278                 if (ssl_error_reason == NULL) {
279                         syslog(LOG_WARNING, "SSL_accept failed: errval=%ld, retval=%d (%s)", errval, retval, strerror(errval));
280                 }
281                 else {
282                         syslog(LOG_WARNING, "SSL_accept failed: %s", ssl_error_reason);
283                 }
284                 SSL_free(ch->ssl_handle);
285                 ch->ssl_handle = NULL;
286                 return;
287         }
288         else {
289                 syslog(LOG_INFO, "SSL_accept success");
290         }
291         bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(ch->ssl_handle), &alg_bits);
292         syslog(LOG_INFO, "SSL/TLS using %s on %s (%d of %d bits)",
293                SSL_CIPHER_get_name(SSL_get_current_cipher(ch->ssl_handle)),
294                SSL_CIPHER_get_version(SSL_get_current_cipher(ch->ssl_handle)), bits, alg_bits);
295
296         syslog(LOG_INFO, "SSL started");
297 }
298
299
300 // shuts down the TLS connection
301 void endtls(struct client_handle *ch) {
302         syslog(LOG_INFO, "Ending SSL/TLS");
303         if (ch->ssl_handle != NULL) {
304                 SSL_shutdown(ch->ssl_handle);
305                 SSL_get_SSL_CTX(ch->ssl_handle);
306                 SSL_free(ch->ssl_handle);
307         }
308         ch->ssl_handle = NULL;
309 }
310
311
312 // Send binary data to the client encrypted.
313 int client_write_ssl(struct client_handle *ch, char *buf, int nbytes) {
314         int retval;
315         int nremain;
316         char junk[1];
317
318         if (ch->ssl_handle == NULL)
319                 return (-1);
320
321         nremain = nbytes;
322         while (nremain > 0) {
323                 if (SSL_want_write(ch->ssl_handle)) {
324                         if ((SSL_read(ch->ssl_handle, junk, 0)) < 1) {
325                                 syslog(LOG_WARNING, "SSL_read in client_write: %s", ERR_reason_error_string(ERR_get_error()));
326                         }
327                 }
328                 retval = SSL_write(ch->ssl_handle, &buf[nbytes - nremain], nremain);
329                 if (retval < 1) {
330                         long errval;
331
332                         errval = SSL_get_error(ch->ssl_handle, retval);
333                         if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
334                                 sleep(1);
335                                 continue;
336                         }
337                         syslog(LOG_WARNING, "SSL_write got error %ld, ret %d", errval, retval);
338                         if (retval == -1) {
339                                 syslog(LOG_WARNING, "errno is %d", errno);
340                                 endtls(ch);
341                         }
342                         return -1;
343                 }
344                 nremain -= retval;
345         }
346         return 0;
347 }
348
349
350 // read data from the encrypted layer
351 int client_read_ssl(struct client_handle *ch, char *buf, int nbytes) {
352         int bytes_read = 0;
353         int rlen = 0;
354         char junk[1];
355
356         if (ch->ssl_handle == NULL)
357                 return (-1);
358
359         while (bytes_read < nbytes) {
360                 if (SSL_want_read(ch->ssl_handle)) {
361                         if ((SSL_write(ch->ssl_handle, junk, 0)) < 1) {
362                                 syslog(LOG_WARNING, "SSL_write in client_read");
363                         }
364                 }
365                 rlen = SSL_read(ch->ssl_handle, &buf[bytes_read], nbytes - bytes_read);
366                 if (rlen < 1) {
367                         long errval;
368                         errval = SSL_get_error(ch->ssl_handle, rlen);
369                         if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
370                                 sleep(1);
371                                 continue;
372                         }
373                         syslog(LOG_WARNING, "SSL_read error %ld", errval);
374                         endtls(ch);
375                         return (-1);
376                 }
377                 bytes_read += rlen;
378         }
379         return (bytes_read);
380 }