crypto.c

00001 /*
00002  * $Id: crypto.c 5147 2007-05-08 15:36:22Z ajc $
00003  */
00010 #include "config.h"
00011 #ifdef HAVE_OPENSSL
00012 
00013 #include "webcit.h"
00014 #include "webserver.h"
00017 #define CTDL_CRYPTO_DIR         "./keys" 
00018 #define CTDL_KEY_PATH           CTDL_CRYPTO_DIR "/citadel.key" 
00019 #define CTDL_CSR_PATH           CTDL_CRYPTO_DIR "/citadel.csr" 
00020 #define CTDL_CER_PATH           CTDL_CRYPTO_DIR "/citadel.cer" 
00021 #define SIGN_DAYS               365 
00023 SSL_CTX *ssl_ctx;               
00024 pthread_mutex_t **SSLCritters;  
00026 pthread_key_t ThreadSSL;        
00032 static unsigned long id_callback(void)
00033 {
00034         return (unsigned long) pthread_self();
00035 }
00036 
00041 void init_ssl(void)
00042 {
00043         SSL_METHOD *ssl_method;
00044         RSA *rsa=NULL;
00045         X509_REQ *req = NULL;
00046         X509 *cer = NULL;
00047         EVP_PKEY *pk = NULL;
00048         EVP_PKEY *req_pkey = NULL;
00049         X509_NAME *name = NULL;
00050         FILE *fp;
00051         char buf[SIZ];
00052 
00053         if (!access("/var/run/egd-pool", F_OK))
00054                 RAND_egd("/var/run/egd-pool");
00055 
00056         if (!RAND_status()) {
00057                 lprintf(3,
00058                         "PRNG not adequately seeded, won't do SSL/TLS\n");
00059                 return;
00060         }
00061         SSLCritters =
00062             malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t *));
00063         if (!SSLCritters) {
00064                 lprintf(1, "citserver: can't allocate memory!!\n");
00065                 /* Nothing's been initialized, just die */
00066                 exit(WC_EXIT_SSL);
00067         } else {
00068                 int a;
00069 
00070                 for (a = 0; a < CRYPTO_num_locks(); a++) {
00071                         SSLCritters[a] = malloc(sizeof(pthread_mutex_t));
00072                         if (!SSLCritters[a]) {
00073                                 lprintf(1,
00074                                         "citserver: can't allocate memory!!\n");
00076                                 exit(WC_EXIT_SSL);
00077                         }
00078                         pthread_mutex_init(SSLCritters[a], NULL);
00079                 }
00080         }
00081 
00085         SSL_library_init();
00086         SSL_load_error_strings();
00087         ssl_method = SSLv23_server_method();
00088         if (!(ssl_ctx = SSL_CTX_new(ssl_method))) {
00089                 lprintf(3, "SSL_CTX_new failed: %s\n",
00090                         ERR_reason_error_string(ERR_get_error()));
00091                 return;
00092         }
00093 
00094         CRYPTO_set_locking_callback(ssl_lock);
00095         CRYPTO_set_id_callback(id_callback);
00096 
00101         mkdir(CTDL_CRYPTO_DIR, 0700);
00102 
00111         if (!strcasecmp(ctdlhost, "uds")) {
00112                 sprintf(buf, "%s/keys/citadel.key", ctdlport);
00113                 symlink(buf, CTDL_KEY_PATH);
00114                 sprintf(buf, "%s/keys/citadel.csr", ctdlport);
00115                 symlink(buf, CTDL_CSR_PATH);
00116                 sprintf(buf, "%s/keys/citadel.cer", ctdlport);
00117                 symlink(buf, CTDL_CER_PATH);
00118         }
00119 
00123         if (access(CTDL_KEY_PATH, R_OK) != 0) {
00124                 lprintf(5, "Generating RSA key pair.\n");
00125                 rsa = RSA_generate_key(1024,    
00126                                         65537,  
00127                                         NULL,   
00128                                         NULL);  
00129                 if (rsa == NULL) {
00130                         lprintf(3, "Key generation failed: %s\n",
00131                                 ERR_reason_error_string(ERR_get_error()));
00132                 }
00133                 if (rsa != NULL) {
00134                         fp = fopen(CTDL_KEY_PATH, "w");
00135                         if (fp != NULL) {
00136                                 chmod(CTDL_KEY_PATH, 0600);
00137                                 if (PEM_write_RSAPrivateKey(fp, 
00138                                                         rsa,    
00139                                                         NULL,   
00140                                                         NULL,   
00141                                                         0,      
00142                                                         NULL,   
00143                                                         NULL    
00144                                 ) != 1) {
00145                                         lprintf(3, "Cannot write key: %s\n",
00146                                                 ERR_reason_error_string(ERR_get_error()));
00147                                         unlink(CTDL_KEY_PATH);
00148                                 }
00149                                 fclose(fp);
00150                         }
00151                         RSA_free(rsa);
00152                 }
00153         }
00154 
00158         if (access(CTDL_CSR_PATH, R_OK) != 0) {
00159                 lprintf(5, "Generating a certificate signing request.\n");
00160 
00167                 fp = fopen(CTDL_KEY_PATH, "r");
00168                 if (fp) {
00169                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
00170                         fclose(fp);
00171                 }
00172 
00173                 if (rsa) {
00174 
00176                         if (pk=EVP_PKEY_new(), pk != NULL) {
00177                                 EVP_PKEY_assign_RSA(pk, rsa);
00178                                 if (req = X509_REQ_new(), req != NULL) {
00179 
00181                                         X509_REQ_set_pubkey(req, pk);
00182                                         X509_REQ_set_version(req, 0L);
00183 
00184                                         name = X509_REQ_get_subject_name(req);
00185 
00188                                         /* \todo whats this?
00189                                         X509_NAME_add_entry_by_txt(name, "C",
00190                                                 MBSTRING_ASC, "US", -1, -1, 0);
00191 
00192                                         X509_NAME_add_entry_by_txt(name, "ST",
00193                                                 MBSTRING_ASC, "New York", -1, -1, 0);
00194 
00195                                         X509_NAME_add_entry_by_txt(name, "L",
00196                                                 MBSTRING_ASC, "Mount Kisco", -1, -1, 0);
00197                                         */
00198 
00199                                         X509_NAME_add_entry_by_txt(name, "O",
00200                                                 MBSTRING_ASC, "Organization name", -1, -1, 0);
00201 
00202                                         X509_NAME_add_entry_by_txt(name, "OU",
00203                                                 MBSTRING_ASC, "Citadel server", -1, -1, 0);
00204 
00205                                         X509_NAME_add_entry_by_txt(name, "CN",
00206                                                 MBSTRING_ASC, "*", -1, -1, 0);
00207                                 
00208                                         X509_REQ_set_subject_name(req, name);
00209 
00211                                         if (!X509_REQ_sign(req, pk, EVP_md5())) {
00212                                                 lprintf(3, "X509_REQ_sign(): error\n");
00213                                         }
00214                                         else {
00216                                                 fp = fopen(CTDL_CSR_PATH, "w");
00217                                                 if (fp != NULL) {
00218                                                         chmod(CTDL_CSR_PATH, 0600);
00219                                                         PEM_write_X509_REQ(fp, req);
00220                                                         fclose(fp);
00221                                                 }
00222                                         }
00223 
00224                                         X509_REQ_free(req);
00225                                 }
00226                         }
00227 
00228                         RSA_free(rsa);
00229                 }
00230 
00231                 else {
00232                         lprintf(3, "Unable to read private key.\n");
00233                 }
00234         }
00235 
00236 
00237 
00241         if (access(CTDL_CER_PATH, R_OK) != 0) {
00242                 lprintf(5, "Generating a self-signed certificate.\n");
00243 
00247                 fp = fopen(CTDL_KEY_PATH, "r");
00248                 if (fp) {
00249                         rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
00250                         fclose(fp);
00251                 }
00252 
00254                 req = NULL;
00255                 cer = NULL;
00256                 pk = NULL;
00257                 if (rsa) {
00258                         if (pk=EVP_PKEY_new(), pk != NULL) {
00259                                 EVP_PKEY_assign_RSA(pk, rsa);
00260                         }
00261 
00262                         fp = fopen(CTDL_CSR_PATH, "r");
00263                         if (fp) {
00264                                 req = PEM_read_X509_REQ(fp, NULL, NULL, NULL);
00265                                 fclose(fp);
00266                         }
00267 
00268                         if (req) {
00269                                 if (cer = X509_new(), cer != NULL) {
00270 
00271                                         ASN1_INTEGER_set(X509_get_serialNumber(cer), 0);
00272                                         X509_set_issuer_name(cer, req->req_info->subject);
00273                                         X509_set_subject_name(cer, req->req_info->subject);
00274                                         X509_gmtime_adj(X509_get_notBefore(cer), 0);
00275                                         X509_gmtime_adj(X509_get_notAfter(cer),(long)60*60*24*SIGN_DAYS);
00276 
00277                                         req_pkey = X509_REQ_get_pubkey(req);
00278                                         X509_set_pubkey(cer, req_pkey);
00279                                         EVP_PKEY_free(req_pkey);
00280                                         
00282                                         if (!X509_sign(cer, pk, EVP_md5())) {
00283                                                 lprintf(3, "X509_sign(): error\n");
00284                                         }
00285                                         else {
00287                                                 fp = fopen(CTDL_CER_PATH, "w");
00288                                                 if (fp != NULL) {
00289                                                         chmod(CTDL_CER_PATH, 0600);
00290                                                         PEM_write_X509(fp, cer);
00291                                                         fclose(fp);
00292                                                 }
00293                                         }
00294                                         X509_free(cer);
00295                                 }
00296                         }
00297 
00298                         RSA_free(rsa);
00299                 }
00300         }
00301 
00307         SSL_CTX_use_certificate_chain_file(ssl_ctx, CTDL_CER_PATH);
00308         SSL_CTX_use_PrivateKey_file(ssl_ctx, CTDL_KEY_PATH, SSL_FILETYPE_PEM);
00309         if ( !SSL_CTX_check_private_key(ssl_ctx) ) {
00310                 lprintf(3, "Cannot install certificate: %s\n",
00311                                 ERR_reason_error_string(ERR_get_error()));
00312         }
00313         
00314 }
00315 
00316 
00322 int starttls(int sock) {
00323         int retval, bits, alg_bits;
00324         SSL *newssl;
00325 
00326         pthread_setspecific(ThreadSSL, NULL);
00327 
00328         if (!ssl_ctx) {
00329                 return(1);
00330         }
00331         if (!(newssl = SSL_new(ssl_ctx))) {
00332                 lprintf(3, "SSL_new failed: %s\n",
00333                                 ERR_reason_error_string(ERR_get_error()));
00334                 return(2);
00335         }
00336         if (!(SSL_set_fd(newssl, sock))) {
00337                 lprintf(3, "SSL_set_fd failed: %s\n",
00338                         ERR_reason_error_string(ERR_get_error()));
00339                 SSL_free(newssl);
00340                 return(3);
00341         }
00342         retval = SSL_accept(newssl);
00343         if (retval < 1) {
00349                 long errval;
00350 
00351                 errval = SSL_get_error(newssl, retval);
00352                 lprintf(3, "SSL_accept failed: %s\n",
00353                         ERR_reason_error_string(ERR_get_error()));
00354                 SSL_free(newssl);
00355                 newssl = NULL;
00356                 return(4);
00357         }
00358         BIO_set_close(newssl->rbio, BIO_NOCLOSE);
00359         bits =
00360             SSL_CIPHER_get_bits(SSL_get_current_cipher(newssl),
00361                                 &alg_bits);
00362         lprintf(5, "SSL/TLS using %s on %s (%d of %d bits)\n",
00363                 SSL_CIPHER_get_name(SSL_get_current_cipher(newssl)),
00364                 SSL_CIPHER_get_version(SSL_get_current_cipher(newssl)),
00365                 bits, alg_bits);
00366 
00367         pthread_setspecific(ThreadSSL, newssl);
00368         return(0);
00369 }
00370 
00371 
00372 
00379 void endtls(void)
00380 {
00381         SSL_CTX *ctx = NULL;
00382 
00383         if (THREADSSL == NULL) return;
00384 
00385         lprintf(5, "Ending SSL/TLS\n");
00386         SSL_shutdown(THREADSSL);
00387         ctx = SSL_get_SSL_CTX(THREADSSL);
00388 
00397         SSL_free(THREADSSL);
00398         pthread_setspecific(ThreadSSL, NULL);
00399 }
00400 
00401 
00409 void ssl_lock(int mode, int n, const char *file, int line)
00410 {
00411         if (mode & CRYPTO_LOCK)
00412                 pthread_mutex_lock(SSLCritters[n]);
00413         else
00414                 pthread_mutex_unlock(SSLCritters[n]);
00415 }
00416 
00422 void client_write_ssl(char *buf, int nbytes)
00423 {
00424         int retval;
00425         int nremain;
00426         char junk[1];
00427 
00428         if (THREADSSL == NULL) return;
00429 
00430         nremain = nbytes;
00431 
00432         while (nremain > 0) {
00433                 if (SSL_want_write(THREADSSL)) {
00434                         if ((SSL_read(THREADSSL, junk, 0)) < 1) {
00435                                 lprintf(9, "SSL_read in client_write: %s\n",
00436                                                 ERR_reason_error_string(ERR_get_error()));
00437                         }
00438                 }
00439                 retval = SSL_write(THREADSSL, &buf[nbytes - nremain], nremain);
00440                 if (retval < 1) {
00441                         long errval;
00442 
00443                         errval = SSL_get_error(THREADSSL, retval);
00444                         if (errval == SSL_ERROR_WANT_READ ||
00445                             errval == SSL_ERROR_WANT_WRITE) {
00446                                 sleep(1);
00447                                 continue;
00448                         }
00449                         lprintf(9, "SSL_write got error %ld, ret %d\n", errval, retval);
00450                         if (retval == -1) {
00451                                 lprintf(9, "errno is %d\n", errno);
00452                         }
00453                         endtls();
00454                         return;
00455                 }
00456                 nremain -= retval;
00457         }
00458 }
00459 
00460 
00468 int client_read_ssl(char *buf, int bytes, int timeout)
00469 {
00470 #if 0
00471         fd_set rfds;
00472         struct timeval tv;
00473         int retval;
00474         int s;
00475 #endif
00476         int len, rlen;
00477         char junk[1];
00478 
00479         if (THREADSSL == NULL) return(0);
00480 
00481         len = 0;
00482         while (len < bytes) {
00483 #if 0
00484 
00488                 FD_ZERO(&rfds);
00489                 s = BIO_get_fd(THREADSSL->rbio, NULL);
00490                 FD_SET(s, &rfds);
00491                 tv.tv_sec = timeout;
00492                 tv.tv_usec = 0;
00493 
00494                 retval = select(s + 1, &rfds, NULL, NULL, &tv);
00495 
00496                 if (FD_ISSET(s, &rfds) == 0) {
00497                         return (0);
00498                 }
00499 
00500 #endif
00501                 if (SSL_want_read(THREADSSL)) {
00502                         if ((SSL_write(THREADSSL, junk, 0)) < 1) {
00503                                 lprintf(9, "SSL_write in client_read: %s\n", ERR_reason_error_string(ERR_get_error()));
00504                         }
00505                 }
00506                 rlen = SSL_read(THREADSSL, &buf[len], bytes - len);
00507                 if (rlen < 1) {
00508                         long errval;
00509 
00510                         errval = SSL_get_error(THREADSSL, rlen);
00511                         if (errval == SSL_ERROR_WANT_READ ||
00512                             errval == SSL_ERROR_WANT_WRITE) {
00513                                 sleep(1);
00514                                 continue;
00515                         }
00516                         lprintf(9, "SSL_read got error %ld\n", errval);
00517                         endtls();
00518                         return (0);
00519                 }
00520                 len += rlen;
00521         }
00522         return (1);
00523 }
00524 
00525 
00526 #endif                          /* HAVE_OPENSSL */
00527 

Generated on Wed Jun 20 23:13:07 2007 for webcit by  doxygen 1.5.2