* Got HTTPS to work with Mozilla (by twiddling stuff that I still don't
[citadel.git] / webcit / crypto.c
1 /* $Id$ */
2
3 #ifdef HAVE_OPENSSL
4
5
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <pthread.h>
12
13 #include <sys/time.h>
14 #include "webcit.h"
15 #include "webserver.h"
16
17 #define CTDL_CRYPTO_DIR         WEBCITDIR "/keys"
18 #define CTDL_KEY_PATH           CTDL_CRYPTO_DIR "/citadel.key"
19 #define CTDL_CSR_PATH           CTDL_CRYPTO_DIR "/citadel.csr"
20 #define CTDL_CER_PATH           CTDL_CRYPTO_DIR "/citadel.cer"
21 #define SIGN_DAYS               365
22
23
24 /* Shared Diffie-Hellman parameters */
25 #define DH_P            "1A74527AEE4EE2568E85D4FB2E65E18C9394B9C80C42507D7A6A0DBE9A9A54B05A9A96800C34C7AA5297095B69C88901EEFD127F969DCA26A54C0E0B5C5473EBAEB00957D2633ECAE3835775425DE66C0DE6D024DBB17445E06E6B0C78415E589B8814F08531D02FD43778451E7685541079CFFB79EF0D26EFEEBBB69D1E80383"
26 #define DH_G            "2"
27 #define DH_L            1024
28
29 SSL_CTX *ssl_ctx;               /* SSL context */
30 pthread_mutex_t **SSLCritters;  /* Things needing locking */
31
32 pthread_key_t ThreadSSL;        /* Per-thread SSL context */
33
34 static unsigned long id_callback(void)
35 {
36         return (unsigned long) pthread_self();
37 }
38
39  /*
40   * Set up the cert things on the server side. We do need both the
41   * private key (in key_file) and the cert (in cert_file).
42   * Both files may be identical.
43   *
44   * This function is taken from OpenSSL apps/s_cb.c
45   */
46
47 static int ctdl_install_certificate(SSL_CTX * ctx,
48                           const char *cert_file, const char *key_file)
49 {
50         if (cert_file != NULL) {
51                 if (SSL_CTX_use_certificate_file(ctx, cert_file,
52                                                  SSL_FILETYPE_PEM) <= 0) {
53                         lprintf(3, "unable to get certificate from '%s'",
54                                 cert_file);
55                         return (0);
56                 }
57                 if (key_file == NULL)
58                         key_file = cert_file;
59                 if (SSL_CTX_use_PrivateKey_file(ctx, key_file,
60                                                 SSL_FILETYPE_PEM) <= 0) {
61                         lprintf(3, "unable to get private key from '%s'",
62                                 key_file);
63                         return (0);
64                 }
65                 /* Now we know that a key and cert have been set against
66                  * the SSL context */
67                 if (!SSL_CTX_check_private_key(ctx)) {
68                         lprintf(3,
69                                 "Private key does not match the certificate public key");
70                         return (0);
71                 }
72         }
73         return (1);
74 }
75
76
77 void init_ssl(void)
78 {
79         SSL_METHOD *ssl_method;
80         DH *dh;
81         RSA *rsa=NULL;
82         X509_REQ *req = NULL;
83         X509 *cer = NULL;
84         EVP_PKEY *pk = NULL;
85         EVP_PKEY *req_pkey = NULL;
86         X509_NAME *name = NULL;
87         FILE *fp;
88
89         if (!access("/var/run/egd-pool", F_OK))
90                 RAND_egd("/var/run/egd-pool");
91
92         if (!RAND_status()) {
93                 lprintf(3,
94                         "PRNG not adequately seeded, won't do SSL/TLS\n");
95                 return;
96         }
97         SSLCritters =
98             malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t *));
99         if (!SSLCritters) {
100                 lprintf(1, "citserver: can't allocate memory!!\n");
101                 /* Nothing's been initialized, just die */
102                 exit(1);
103         } else {
104                 int a;
105
106                 for (a = 0; a < CRYPTO_num_locks(); a++) {
107                         SSLCritters[a] = malloc(sizeof(pthread_mutex_t));
108                         if (!SSLCritters[a]) {
109                                 lprintf(1,
110                                         "citserver: can't allocate memory!!\n");
111                                 /* Nothing's been initialized, just die */
112                                 exit(1);
113                         }
114                         pthread_mutex_init(SSLCritters[a], NULL);
115                 }
116         }
117
118         /*
119          * Initialize SSL transport layer
120          */
121         SSL_library_init();
122         OpenSSL_add_all_algorithms();
123         SSL_load_error_strings();
124         ssl_method = SSLv2_server_method();
125         if (!(ssl_ctx = SSL_CTX_new(ssl_method))) {
126                 lprintf(3, "SSL_CTX_new failed: %s\n",
127                         ERR_reason_error_string(ERR_get_error()));
128                 return;
129         }
130
131         CRYPTO_set_locking_callback(ssl_lock);
132         CRYPTO_set_id_callback(id_callback);
133
134         /* Load DH parameters into the context */
135         dh = DH_new();
136         if (!dh) {
137                 lprintf(3, "init_ssl() can't allocate a DH object: %s\n",
138                         ERR_reason_error_string(ERR_get_error()));
139                 SSL_CTX_free(ssl_ctx);
140                 ssl_ctx = NULL;
141                 return;
142         }
143         if (!(BN_hex2bn(&(dh->p), DH_P))) {
144                 lprintf(3, "init_ssl() can't assign DH_P: %s\n",
145                         ERR_reason_error_string(ERR_get_error()));
146                 SSL_CTX_free(ssl_ctx);
147                 ssl_ctx = NULL;
148                 return;
149         }
150         if (!(BN_hex2bn(&(dh->g), DH_G))) {
151                 lprintf(3, "init_ssl() can't assign DH_G: %s\n",
152                         ERR_reason_error_string(ERR_get_error()));
153                 SSL_CTX_free(ssl_ctx);
154                 ssl_ctx = NULL;
155                 return;
156         }
157         dh->length = DH_L;
158         SSL_CTX_set_tmp_dh(ssl_ctx, dh);
159         DH_free(dh);
160
161         /* Get our certificates in order.
162          * First, create the key/cert directory if it's not there already...
163          */
164         mkdir(CTDL_CRYPTO_DIR, 0700);
165
166         /*
167          * Generate a key pair if we don't have one.
168          */
169         if (access(CTDL_KEY_PATH, R_OK) != 0) {
170                 lprintf(5, "Generating RSA key pair.\n");
171                 rsa = RSA_generate_key(1024,    /* modulus size */
172                                         65537,  /* exponent */
173                                         NULL,   /* no callback */
174                                         NULL);  /* no callback */
175                 if (rsa == NULL) {
176                         lprintf(3, "Key generation failed: %s\n",
177                                 ERR_reason_error_string(ERR_get_error()));
178                 }
179                 if (rsa != NULL) {
180                         fp = fopen(CTDL_KEY_PATH, "w");
181                         if (fp != NULL) {
182                                 chmod(CTDL_KEY_PATH, 0600);
183                                 if (PEM_write_RSAPrivateKey(fp, /* the file */
184                                                         rsa,    /* the key */
185                                                         NULL,   /* no enc */
186                                                         NULL,   /* no passphr */
187                                                         0,      /* no passphr */
188                                                         NULL,   /* no callbk */
189                                                         NULL    /* no callbk */
190                                 ) != 1) {
191                                         lprintf(3, "Cannot write key: %s\n",
192                                                 ERR_reason_error_string(ERR_get_error()));
193                                         unlink(CTDL_KEY_PATH);
194                                 }
195                                 fclose(fp);
196                         }
197                         RSA_free(rsa);
198                 }
199         }
200
201         /*
202          * Generate a CSR if we don't have one.
203          */
204         if (access(CTDL_CSR_PATH, R_OK) != 0) {
205                 lprintf(5, "Generating a certificate signing request.\n");
206
207                 /*
208                  * Read our key from the file.  No, we don't just keep this
209                  * in memory from the above key-generation function, because
210                  * there is the possibility that the key was already on disk
211                  * and we didn't just generate it now.
212                  */
213                 fp = fopen(CTDL_KEY_PATH, "r");
214                 if (fp) {
215                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
216                         fclose(fp);
217                 }
218
219                 if (rsa) {
220
221                         /* Create a public key from the private key */
222                         if (pk=EVP_PKEY_new(), pk != NULL) {
223                                 EVP_PKEY_assign_RSA(pk, rsa);
224                                 if (req = X509_REQ_new(), req != NULL) {
225
226                                         /* Set the public key */
227                                         X509_REQ_set_pubkey(req, pk);
228                                         X509_REQ_set_version(req, 0L);
229
230                                         name = X509_REQ_get_subject_name(req);
231
232                                         /* Tell it who we are */
233
234                                         /*
235                                         X509_NAME_add_entry_by_txt(name, "C",
236                                                 MBSTRING_ASC, "US", -1, -1, 0);
237
238                                         X509_NAME_add_entry_by_txt(name, "ST",
239                                                 MBSTRING_ASC, "New York", -1, -1, 0);
240
241                                         X509_NAME_add_entry_by_txt(name, "L",
242                                                 MBSTRING_ASC, "Mount Kisco", -1, -1, 0);
243                                         */
244
245                                         X509_NAME_add_entry_by_txt(name, "O",
246                                                 MBSTRING_ASC, "FIXME.FIXME.org", -1, -1, 0);
247
248                                         X509_NAME_add_entry_by_txt(name, "OU",
249                                                 MBSTRING_ASC, "Citadel server", -1, -1, 0);
250
251                                         X509_NAME_add_entry_by_txt(name, "CN",
252                                                 MBSTRING_ASC, "FIXME.FIXME.org", -1, -1, 0);
253                                 
254                                         X509_REQ_set_subject_name(req, name);
255
256                                         /* Sign the CSR */
257                                         if (!X509_REQ_sign(req, pk, EVP_md5())) {
258                                                 lprintf(3, "X509_REQ_sign(): error\n");
259                                         }
260                                         else {
261                                                 /* Write it to disk. */ 
262                                                 fp = fopen(CTDL_CSR_PATH, "w");
263                                                 if (fp != NULL) {
264                                                         chmod(CTDL_CSR_PATH, 0600);
265                                                         PEM_write_X509_REQ(fp, req);
266                                                         fclose(fp);
267                                                 }
268                                         }
269
270                                         X509_REQ_free(req);
271                                 }
272                         }
273
274                         RSA_free(rsa);
275                 }
276
277                 else {
278                         lprintf(3, "Unable to read private key.\n");
279                 }
280         }
281
282
283
284         /*
285          * Generate a self-signed certificate if we don't have one.
286          */
287         if (access(CTDL_CER_PATH, R_OK) != 0) {
288                 lprintf(5, "Generating a self-signed certificate.\n");
289
290                 /* Same deal as before: always read the key from disk because
291                  * it may or may not have just been generated.
292                  */
293                 fp = fopen(CTDL_KEY_PATH, "r");
294                 if (fp) {
295                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
296                         fclose(fp);
297                 }
298
299                 /* This also holds true for the CSR. */
300                 req = NULL;
301                 cer = NULL;
302                 pk = NULL;
303                 if (rsa) {
304                         if (pk=EVP_PKEY_new(), pk != NULL) {
305                                 EVP_PKEY_assign_RSA(pk, rsa);
306                         }
307
308                         fp = fopen(CTDL_CSR_PATH, "r");
309                         if (fp) {
310                                 req = PEM_read_X509_REQ(fp, NULL, NULL, NULL);
311                                 fclose(fp);
312                         }
313
314                         if (req) {
315                                 if (cer = X509_new(), cer != NULL) {
316
317                                         X509_set_issuer_name(cer, req->req_info->subject);
318                                         X509_set_subject_name(cer, req->req_info->subject);
319                                         X509_gmtime_adj(X509_get_notBefore(cer),0);
320                                         X509_gmtime_adj(X509_get_notAfter(cer),(long)60*60*24*SIGN_DAYS);
321                                         req_pkey = X509_REQ_get_pubkey(req);
322                                         X509_set_pubkey(cer, req_pkey);
323                                         EVP_PKEY_free(req_pkey);
324                                         
325                                         /* Sign the cert */
326                                         if (!X509_sign(cer, pk, EVP_md5())) {
327                                                 lprintf(3, "X509_sign(): error\n");
328                                         }
329                                         else {
330                                                 /* Write it to disk. */ 
331                                                 fp = fopen(CTDL_CER_PATH, "w");
332                                                 if (fp != NULL) {
333                                                         chmod(CTDL_CER_PATH, 0600);
334                                                         PEM_write_X509(fp, cer);
335                                                         fclose(fp);
336                                                 }
337                                         }
338                                         X509_free(cer);
339                                 }
340                         }
341
342                         RSA_free(rsa);
343                 }
344         }
345
346
347         /*
348          * Now try to bind to the key and certificate.
349          */
350         if (ctdl_install_certificate(ssl_ctx,
351                         CTDL_CER_PATH,
352                         CTDL_KEY_PATH) != 1)
353         {
354                 lprintf(3, "Cannot install certificate: %s\n",
355                                 ERR_reason_error_string(ERR_get_error()));
356         }
357
358 }
359
360
361 /*
362  * starttls() starts SSL/TLS encryption for the current session.
363  */
364 int starttls(int sock) {
365         int retval, bits, alg_bits;
366         SSL *newssl;
367
368         pthread_setspecific(ThreadSSL, NULL);
369
370         if (!ssl_ctx) {
371                 return(1);
372         }
373         if (!(newssl = SSL_new(ssl_ctx))) {
374                 lprintf(3, "SSL_new failed: %s\n",
375                                 ERR_reason_error_string(ERR_get_error()));
376                 return(2);
377         }
378         if (!(SSL_set_fd(newssl, sock))) {
379                 lprintf(3, "SSL_set_fd failed: %s\n",
380                         ERR_reason_error_string(ERR_get_error()));
381                 SSL_free(newssl);
382                 return(3);
383         }
384         retval = SSL_accept(newssl);
385         if (retval < 1) {
386                 /*
387                  * Can't notify the client of an error here; they will
388                  * discover the problem at the SSL layer and should
389                  * revert to unencrypted communications.
390                  */
391                 long errval;
392
393                 errval = SSL_get_error(newssl, retval);
394                 lprintf(3, "SSL_accept failed: %s\n",
395                         ERR_reason_error_string(ERR_get_error()));
396                 SSL_free(newssl);
397                 newssl = NULL;
398                 return(4);
399         }
400         BIO_set_close(newssl->rbio, BIO_NOCLOSE);
401         bits =
402             SSL_CIPHER_get_bits(SSL_get_current_cipher(newssl),
403                                 &alg_bits);
404         lprintf(5, "SSL/TLS using %s on %s (%d of %d bits)\n",
405                 SSL_CIPHER_get_name(SSL_get_current_cipher(newssl)),
406                 SSL_CIPHER_get_version(SSL_get_current_cipher(newssl)),
407                 bits, alg_bits);
408
409         pthread_setspecific(ThreadSSL, newssl);
410         return(0);
411 }
412
413
414
415 /*
416  * endtls() shuts down the TLS connection
417  *
418  * WARNING:  This may make your session vulnerable to a known plaintext
419  * attack in the current implmentation.
420  */
421 void endtls(void)
422 {
423         lprintf(5, "Ending SSL/TLS\n");
424         SSL_shutdown(THREADSSL);
425         SSL_free(THREADSSL);
426         pthread_setspecific(ThreadSSL, NULL);
427 }
428
429
430 /*
431  * ssl_lock() callback for OpenSSL mutex locks
432  */
433 void ssl_lock(int mode, int n, const char *file, int line)
434 {
435         if (mode & CRYPTO_LOCK)
436                 pthread_mutex_lock(SSLCritters[n]);
437         else
438                 pthread_mutex_unlock(SSLCritters[n]);
439 }
440
441 /*
442  * client_write_ssl() Send binary data to the client encrypted.
443  */
444 void client_write_ssl(char *buf, int nbytes)
445 {
446         int retval;
447         int nremain;
448         char junk[1];
449
450         nremain = nbytes;
451
452         while (nremain > 0) {
453                 if (SSL_want_write(THREADSSL)) {
454                         if ((SSL_read(THREADSSL, junk, 0)) < 1) {
455                                 lprintf(9, "SSL_read in client_write: %s\n", ERR_reason_error_string(ERR_get_error()));
456                         }
457                 }
458                 retval =
459                     SSL_write(THREADSSL, &buf[nbytes - nremain], nremain);
460                 if (retval < 1) {
461                         long errval;
462
463                         errval = SSL_get_error(THREADSSL, retval);
464                         if (errval == SSL_ERROR_WANT_READ ||
465                             errval == SSL_ERROR_WANT_WRITE) {
466                                 sleep(1);
467                                 continue;
468                         }
469                         lprintf(9, "SSL_write got error %ld, ret %d\n", errval, retval);
470                         if (retval == -1)
471                                 lprintf(9, "errno is %d\n", errno);
472                         endtls();
473                         client_write(&buf[nbytes - nremain], nremain);
474                         return;
475                 }
476                 nremain -= retval;
477         }
478 }
479
480
481 /*
482  * client_read_ssl() - read data from the encrypted layer.
483  */
484 int client_read_ssl(char *buf, int bytes, int timeout)
485 {
486 #if 0
487         fd_set rfds;
488         struct timeval tv;
489         int retval;
490         int s;
491 #endif
492         int len, rlen;
493         char junk[1];
494
495         len = 0;
496         while (len < bytes) {
497 #if 0
498                 /*
499                  * This code is disabled because we don't need it when
500                  * using blocking reads (which we are). -IO
501                  */
502                 FD_ZERO(&rfds);
503                 s = BIO_get_fd(THREADSSL->rbio, NULL);
504                 FD_SET(s, &rfds);
505                 tv.tv_sec = timeout;
506                 tv.tv_usec = 0;
507
508                 retval = select(s + 1, &rfds, NULL, NULL, &tv);
509
510                 if (FD_ISSET(s, &rfds) == 0) {
511                         return (0);
512                 }
513
514 #endif
515                 if (SSL_want_read(THREADSSL)) {
516                         if ((SSL_write(THREADSSL, junk, 0)) < 1) {
517                                 lprintf(9, "SSL_write in client_read: %s\n", ERR_reason_error_string(ERR_get_error()));
518                         }
519                 }
520                 rlen = SSL_read(THREADSSL, &buf[len], bytes - len);
521                 if (rlen < 1) {
522                         long errval;
523
524                         errval = SSL_get_error(THREADSSL, rlen);
525                         if (errval == SSL_ERROR_WANT_READ ||
526                             errval == SSL_ERROR_WANT_WRITE) {
527                                 sleep(1);
528                                 continue;
529                         }
530                         lprintf(9, "SSL_read got error %ld\n", errval);
531                         endtls();
532                         return (client_read_to
533                                 (WC->http_sock, &buf[len], bytes - len, timeout));
534                 }
535                 len += rlen;
536         }
537         return (1);
538 }
539
540
541 #endif                          /* HAVE_OPENSSL */