* Brought over the SSL/TLS stuff from Citadel. I think it's complete but
[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         "./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               3650    /* Ten years */
22
23
24 /* Shared Diffie-Hellman parameters */
25 #define DH_P            "1A74527AEE4EE2568E85D4FB2E65E18C9394B9C80C42507D7A6A0DBE9A9A54B05A9A96800C34C7AA5297095B69C88901EEFD127F969DCA26A54C0E0B5C5473EBAEB00957D2633ECAE3835775425DE66C0DE6D024DBB17445E06E6B0C78415E589B8814F08531D02FD43778451E7685541079CFFB79EF0D26EFEEBBB69D1E80383"
26 #define DH_G            "2"
27 #define DH_L            1024
28 #define CIT_CIPHERS     "ALL:RC4+RSA:+SSLv2:@STRENGTH"  /* see ciphers(1) */
29
30 SSL_CTX *ssl_ctx;               /* SSL context */
31 pthread_mutex_t **SSLCritters;  /* Things needing locking */
32
33 static unsigned long id_callback(void)
34 {
35         return (unsigned long) pthread_self();
36 }
37
38  /*
39   * Set up the cert things on the server side. We do need both the
40   * private key (in key_file) and the cert (in cert_file).
41   * Both files may be identical.
42   *
43   * This function is taken from OpenSSL apps/s_cb.c
44   */
45
46 static int ctdl_install_certificate(SSL_CTX * ctx,
47                           const char *cert_file, const char *key_file)
48 {
49         if (cert_file != NULL) {
50                 if (SSL_CTX_use_certificate_file(ctx, cert_file,
51                                                  SSL_FILETYPE_PEM) <= 0) {
52                         lprintf(3, "unable to get certificate from '%s'",
53                                 cert_file);
54                         return (0);
55                 }
56                 if (key_file == NULL)
57                         key_file = cert_file;
58                 if (SSL_CTX_use_PrivateKey_file(ctx, key_file,
59                                                 SSL_FILETYPE_PEM) <= 0) {
60                         lprintf(3, "unable to get private key from '%s'",
61                                 key_file);
62                         return (0);
63                 }
64                 /* Now we know that a key and cert have been set against
65                  * the SSL context */
66                 if (!SSL_CTX_check_private_key(ctx)) {
67                         lprintf(3,
68                                 "Private key does not match the certificate public key");
69                         return (0);
70                 }
71         }
72         return (1);
73 }
74
75
76 void init_ssl(void)
77 {
78         SSL_METHOD *ssl_method;
79         DH *dh;
80         RSA *rsa=NULL;
81         X509_REQ *req = NULL;
82         X509 *cer = NULL;
83         EVP_PKEY *pk = NULL;
84         EVP_PKEY *req_pkey = NULL;
85         X509_NAME *name = NULL;
86         FILE *fp;
87
88         if (!access("/var/run/egd-pool", F_OK))
89                 RAND_egd("/var/run/egd-pool");
90
91         if (!RAND_status()) {
92                 lprintf(3,
93                         "PRNG not adequately seeded, won't do SSL/TLS\n");
94                 return;
95         }
96         SSLCritters =
97             malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t *));
98         if (!SSLCritters) {
99                 lprintf(1, "citserver: can't allocate memory!!\n");
100                 /* Nothing's been initialized, just die */
101                 exit(1);
102         } else {
103                 int a;
104
105                 for (a = 0; a < CRYPTO_num_locks(); a++) {
106                         SSLCritters[a] = malloc(sizeof(pthread_mutex_t));
107                         if (!SSLCritters[a]) {
108                                 lprintf(1,
109                                         "citserver: can't allocate memory!!\n");
110                                 /* Nothing's been initialized, just die */
111                                 exit(1);
112                         }
113                         pthread_mutex_init(SSLCritters[a], NULL);
114                 }
115         }
116
117         /*
118          * Initialize SSL transport layer
119          */
120         SSL_library_init();
121         SSL_load_error_strings();
122         ssl_method = SSLv23_server_method();
123         if (!(ssl_ctx = SSL_CTX_new(ssl_method))) {
124                 lprintf(3, "SSL_CTX_new failed: %s\n",
125                         ERR_reason_error_string(ERR_get_error()));
126                 return;
127         }
128         if (!(SSL_CTX_set_cipher_list(ssl_ctx, CIT_CIPHERS))) {
129                 lprintf(3, "SSL: No ciphers available\n");
130                 SSL_CTX_free(ssl_ctx);
131                 ssl_ctx = NULL;
132                 return;
133         }
134 #if 0
135 #if SSLEAY_VERSION_NUMBER >= 0x00906000L
136         SSL_CTX_set_mode(ssl_ctx, SSL_CTX_get_mode(ssl_ctx) |
137                          SSL_MODE_AUTO_RETRY);
138 #endif
139 #endif
140
141         CRYPTO_set_locking_callback(ssl_lock);
142         CRYPTO_set_id_callback(id_callback);
143
144         /* Load DH parameters into the context */
145         dh = DH_new();
146         if (!dh) {
147                 lprintf(3, "init_ssl() can't allocate a DH object: %s\n",
148                         ERR_reason_error_string(ERR_get_error()));
149                 SSL_CTX_free(ssl_ctx);
150                 ssl_ctx = NULL;
151                 return;
152         }
153         if (!(BN_hex2bn(&(dh->p), DH_P))) {
154                 lprintf(3, "init_ssl() can't assign DH_P: %s\n",
155                         ERR_reason_error_string(ERR_get_error()));
156                 SSL_CTX_free(ssl_ctx);
157                 ssl_ctx = NULL;
158                 return;
159         }
160         if (!(BN_hex2bn(&(dh->g), DH_G))) {
161                 lprintf(3, "init_ssl() can't assign DH_G: %s\n",
162                         ERR_reason_error_string(ERR_get_error()));
163                 SSL_CTX_free(ssl_ctx);
164                 ssl_ctx = NULL;
165                 return;
166         }
167         dh->length = DH_L;
168         SSL_CTX_set_tmp_dh(ssl_ctx, dh);
169         DH_free(dh);
170
171         /* Get our certificates in order.
172          * First, create the key/cert directory if it's not there already...
173          */
174         mkdir(CTDL_CRYPTO_DIR, 0700);
175
176         /*
177          * Generate a key pair if we don't have one.
178          */
179         if (access(CTDL_KEY_PATH, R_OK) != 0) {
180                 lprintf(5, "Generating RSA key pair.\n");
181                 rsa = RSA_generate_key(1024,    /* modulus size */
182                                         65537,  /* exponent */
183                                         NULL,   /* no callback */
184                                         NULL);  /* no callback */
185                 if (rsa == NULL) {
186                         lprintf(3, "Key generation failed: %s\n",
187                                 ERR_reason_error_string(ERR_get_error()));
188                 }
189                 if (rsa != NULL) {
190                         fp = fopen(CTDL_KEY_PATH, "w");
191                         if (fp != NULL) {
192                                 chmod(CTDL_KEY_PATH, 0600);
193                                 if (PEM_write_RSAPrivateKey(fp, /* the file */
194                                                         rsa,    /* the key */
195                                                         NULL,   /* no enc */
196                                                         NULL,   /* no passphr */
197                                                         0,      /* no passphr */
198                                                         NULL,   /* no callbk */
199                                                         NULL    /* no callbk */
200                                 ) != 1) {
201                                         lprintf(3, "Cannot write key: %s\n",
202                                                 ERR_reason_error_string(ERR_get_error()));
203                                         unlink(CTDL_KEY_PATH);
204                                 }
205                                 fclose(fp);
206                         }
207                         RSA_free(rsa);
208                 }
209         }
210
211         /*
212          * Generate a CSR if we don't have one.
213          */
214         if (access(CTDL_CSR_PATH, R_OK) != 0) {
215                 lprintf(5, "Generating a certificate signing request.\n");
216
217                 /*
218                  * Read our key from the file.  No, we don't just keep this
219                  * in memory from the above key-generation function, because
220                  * there is the possibility that the key was already on disk
221                  * and we didn't just generate it now.
222                  */
223                 fp = fopen(CTDL_KEY_PATH, "r");
224                 if (fp) {
225                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
226                         fclose(fp);
227                 }
228
229                 if (rsa) {
230
231                         /* Create a public key from the private key */
232                         if (pk=EVP_PKEY_new(), pk != NULL) {
233                                 EVP_PKEY_assign_RSA(pk, rsa);
234                                 if (req = X509_REQ_new(), req != NULL) {
235
236                                         /* Set the public key */
237                                         X509_REQ_set_pubkey(req, pk);
238                                         X509_REQ_set_version(req, 0L);
239
240                                         name = X509_REQ_get_subject_name(req);
241
242                                         /* Tell it who we are */
243
244                                         /*
245                                         X509_NAME_add_entry_by_txt(name, "C",
246                                                 MBSTRING_ASC, "US", -1, -1, 0);
247
248                                         X509_NAME_add_entry_by_txt(name, "ST",
249                                                 MBSTRING_ASC, "New York", -1, -1, 0);
250
251                                         X509_NAME_add_entry_by_txt(name, "L",
252                                                 MBSTRING_ASC, "Mount Kisco", -1, -1, 0);
253                                         */
254
255                                         X509_NAME_add_entry_by_txt(name, "O",
256                                                 MBSTRING_ASC, "FIXME.FIXME.org", -1, -1, 0);
257
258                                         X509_NAME_add_entry_by_txt(name, "OU",
259                                                 MBSTRING_ASC, "Citadel server", -1, -1, 0);
260
261                                         X509_NAME_add_entry_by_txt(name, "CN",
262                                                 MBSTRING_ASC, "FIXME.FIXME.org", -1, -1, 0);
263                                 
264                                         X509_REQ_set_subject_name(req, name);
265
266                                         /* Sign the CSR */
267                                         if (!X509_REQ_sign(req, pk, EVP_md5())) {
268                                                 lprintf(3, "X509_REQ_sign(): error\n");
269                                         }
270                                         else {
271                                                 /* Write it to disk. */ 
272                                                 fp = fopen(CTDL_CSR_PATH, "w");
273                                                 if (fp != NULL) {
274                                                         chmod(CTDL_CSR_PATH, 0600);
275                                                         PEM_write_X509_REQ(fp, req);
276                                                         fclose(fp);
277                                                 }
278                                         }
279
280                                         X509_REQ_free(req);
281                                 }
282                         }
283
284                         RSA_free(rsa);
285                 }
286
287                 else {
288                         lprintf(3, "Unable to read private key.\n");
289                 }
290         }
291
292
293
294         /*
295          * Generate a self-signed certificate if we don't have one.
296          */
297         if (access(CTDL_CER_PATH, R_OK) != 0) {
298                 lprintf(5, "Generating a self-signed certificate.\n");
299
300                 /* Same deal as before: always read the key from disk because
301                  * it may or may not have just been generated.
302                  */
303                 fp = fopen(CTDL_KEY_PATH, "r");
304                 if (fp) {
305                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
306                         fclose(fp);
307                 }
308
309                 /* This also holds true for the CSR. */
310                 req = NULL;
311                 cer = NULL;
312                 pk = NULL;
313                 if (rsa) {
314                         if (pk=EVP_PKEY_new(), pk != NULL) {
315                                 EVP_PKEY_assign_RSA(pk, rsa);
316                         }
317
318                         fp = fopen(CTDL_CSR_PATH, "r");
319                         if (fp) {
320                                 req = PEM_read_X509_REQ(fp, NULL, NULL, NULL);
321                                 fclose(fp);
322                         }
323
324                         if (req) {
325                                 if (cer = X509_new(), cer != NULL) {
326
327                                         X509_set_issuer_name(cer, req->req_info->subject);
328                                         X509_set_subject_name(cer, req->req_info->subject);
329                                         X509_gmtime_adj(X509_get_notBefore(cer),0);
330                                         X509_gmtime_adj(X509_get_notAfter(cer),(long)60*60*24*SIGN_DAYS);
331                                         req_pkey = X509_REQ_get_pubkey(req);
332                                         X509_set_pubkey(cer, req_pkey);
333                                         EVP_PKEY_free(req_pkey);
334                                         
335                                         /* Sign the cert */
336                                         if (!X509_sign(cer, pk, EVP_md5())) {
337                                                 lprintf(3, "X509_sign(): error\n");
338                                         }
339                                         else {
340                                                 /* Write it to disk. */ 
341                                                 fp = fopen(CTDL_CER_PATH, "w");
342                                                 if (fp != NULL) {
343                                                         chmod(CTDL_CER_PATH, 0600);
344                                                         PEM_write_X509(fp, cer);
345                                                         fclose(fp);
346                                                 }
347                                         }
348                                         X509_free(cer);
349                                 }
350                         }
351
352                         RSA_free(rsa);
353                 }
354         }
355
356
357         /*
358          * Now try to bind to the key and certificate.
359          */
360         if (ctdl_install_certificate(ssl_ctx,
361                         CTDL_CER_PATH,
362                         CTDL_KEY_PATH) != 1)
363         {
364                 lprintf(3, "Cannot install certificate: %s\n",
365                                 ERR_reason_error_string(ERR_get_error()));
366         }
367
368 }
369
370
371 /*
372  * starttls() starts SSL/TLS encryption for the current session.
373  */
374 int starttls(void) {
375
376         int retval, bits, alg_bits;
377
378         if (!ssl_ctx) {
379                 return(1);
380         }
381         if (!(WC->ssl = SSL_new(ssl_ctx))) {
382                 lprintf(3, "SSL_new failed: %s\n",
383                                 ERR_reason_error_string(ERR_get_error()));
384                 return(2);
385         }
386         if (!(SSL_set_fd(WC->ssl, WC->http_sock))) {
387                 lprintf(3, "SSL_set_fd failed: %s\n",
388                         ERR_reason_error_string(ERR_get_error()));
389                 SSL_free(WC->ssl);
390                 WC->ssl = NULL;
391                 return(3);
392         }
393         retval = SSL_accept(WC->ssl);
394         if (retval < 1) {
395                 /*
396                  * Can't notify the client of an error here; they will
397                  * discover the problem at the SSL layer and should
398                  * revert to unencrypted communications.
399                  */
400                 long errval;
401
402                 errval = SSL_get_error(WC->ssl, retval);
403                 lprintf(3, "SSL_accept failed: %s\n",
404                         ERR_reason_error_string(ERR_get_error()));
405                 SSL_free(WC->ssl);
406                 WC->ssl = NULL;
407                 return(4);
408         }
409         BIO_set_close(WC->ssl->rbio, BIO_NOCLOSE);
410         bits =
411             SSL_CIPHER_get_bits(SSL_get_current_cipher(WC->ssl),
412                                 &alg_bits);
413         lprintf(5, "SSL/TLS using %s on %s (%d of %d bits)\n",
414                 SSL_CIPHER_get_name(SSL_get_current_cipher(WC->ssl)),
415                 SSL_CIPHER_get_version(SSL_get_current_cipher(WC->ssl)),
416                 bits, alg_bits);
417         return(0);
418 }
419
420
421
422 /*
423  * endtls() shuts down the TLS connection
424  *
425  * WARNING:  This may make your session vulnerable to a known plaintext
426  * attack in the current implmentation.
427  */
428 void endtls(void)
429 {
430         lprintf(5, "Ending SSL/TLS\n");
431         SSL_shutdown(WC->ssl);
432         SSL_free(WC->ssl);
433         WC->ssl = NULL;
434 }
435
436
437 /*
438  * ssl_lock() callback for OpenSSL mutex locks
439  */
440 void ssl_lock(int mode, int n, const char *file, int line)
441 {
442         if (mode & CRYPTO_LOCK)
443                 pthread_mutex_lock(SSLCritters[n]);
444         else
445                 pthread_mutex_unlock(SSLCritters[n]);
446 }
447
448 #endif                          /* HAVE_OPENSSL */