Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals

tls.c

00001 /*
00002  * Copyright (c) 2005, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: tls.c,v 1.16 2007/08/09 14:17:42 tho Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <sys/types.h>
00013 #include <sys/time.h>
00014 #include <unistd.h>
00015 #include <strings.h>
00016 #ifdef HAVE_LIBOPENSSL
00017 #include <openssl/ssl.h>
00018 #include <openssl/rand.h>
00019 #include <openssl/err.h>
00020 #include <openssl/x509_vfy.h>
00021 #include <u/libu.h>
00022 #include <klone/tls.h>
00023 #include <klone/utils.h>
00024 #include <klone/tlsprv.h>
00025 
00026 static int tls_sid = 1;
00027 static int tls_inited = 0; 
00028 
00029 /* private methods */
00030 static int tls_init (void);
00031 static int tls_context (SSL_CTX **);
00032 static int tls_load_creds (SSL_CTX *, tls_ctx_args_t *);
00033 static int tls_gendh_params (SSL_CTX *, const char *);
00034 static int tls_gen_eph_rsa (SSL_CTX *);
00035 static void tls_rand_seed (void);
00036 static int tls_sid_context (SSL_CTX *, int *);
00037 static DH *tls_load_dh_param (const char *);
00038 static int tls_no_passphrase_cb (char *, int, int, void *);
00039 static int tls_init_ctx_args (tls_ctx_args_t *);
00040 static int tls_set_ctx_vdepth (u_config_t *, tls_ctx_args_t *);
00041 static int tls_set_ctx_crlopts (u_config_t *, tls_ctx_args_t *);
00042 static int tls_set_ctx_vmode (u_config_t *, tls_ctx_args_t *);
00043 static int tls_check_ctx (tls_ctx_args_t *);
00044 static void tls_free_ctx_args (tls_ctx_args_t *cargs);
00045 static int tls_load_ctx_args (u_config_t *cfg, tls_ctx_args_t **cargs);
00046 static SSL_CTX *tls_init_ctx (tls_ctx_args_t *cargs);
00047 static int cb_vfy (int ok, X509_STORE_CTX *store_ctx);
00048 
00049 SSL_CTX *tls_load_init_ctx (u_config_t *cfg)
00050 {
00051     SSL_CTX *ctx = NULL;
00052     tls_ctx_args_t *cargs = NULL;
00053 
00054     dbg_return_if (cfg == NULL, NULL);
00055 
00056     dbg_err_if (tls_load_ctx_args(cfg, &cargs));
00057     dbg_err_if ((ctx = tls_init_ctx(cargs)) == NULL);
00058 
00059     tls_free_ctx_args(cargs);
00060 
00061     return ctx;
00062 err:
00063     if (cargs)
00064         tls_free_ctx_args(cargs);
00065     if (ctx)
00066         SSL_CTX_free(ctx);
00067     return NULL;
00068 }
00069 
00070 /* load SSL_CTX args from configuration */
00071 static int tls_load_ctx_args (u_config_t *cfg, tls_ctx_args_t **pcargs)
00072 {
00073     tls_ctx_args_t *cargs = NULL;
00074 
00075     dbg_return_if (cfg == NULL, ~0);
00076     dbg_return_if (pcargs == NULL, ~0);
00077 
00078     cargs = u_zalloc(sizeof(tls_ctx_args_t));
00079     dbg_err_if (cargs == NULL);
00080 
00081     (void) tls_init_ctx_args(cargs);
00082 
00083     cargs->cert = u_config_get_subkey_value(cfg, "cert_file");
00084     cargs->key = u_config_get_subkey_value(cfg, "key_file");
00085     cargs->certchain = u_config_get_subkey_value(cfg, "certchain_file");
00086     cargs->ca = u_config_get_subkey_value(cfg, "ca_file");
00087     cargs->dh = u_config_get_subkey_value(cfg, "dh_file");
00088     cargs->crl = u_config_get_subkey_value(cfg, "crl_file");
00089     dbg_err_if (tls_set_ctx_crlopts(cfg, cargs));
00090     dbg_err_if (tls_set_ctx_vdepth(cfg, cargs));
00091     dbg_err_if (tls_set_ctx_vmode(cfg, cargs));
00092 
00093     /* check cargs consistency against the supplied values */
00094     crit_err_ifm (tls_check_ctx(cargs), 
00095             "error validating SSL configuration options");
00096 
00097     *pcargs = cargs;
00098 
00099     return 0;
00100 err:
00101     if (cargs)
00102         tls_free_ctx_args(cargs);
00103     return ~0;
00104 }
00105 
00106 /* initialize 'parent' SSL context */
00107 static SSL_CTX *tls_init_ctx (tls_ctx_args_t *cargs)
00108 {
00109     SSL_CTX *c = NULL;
00110 
00111     dbg_return_if (cargs == NULL, NULL);
00112 
00113     /* global init */
00114     dbg_err_if (tls_init());
00115 
00116     /* create SSL CTX from where all the SSL sessions will be cloned */
00117     dbg_err_if (tls_context(&c));
00118 
00119     /* don't ask for unlocking passphrases: this assumes that all 
00120      * credentials are stored clear text */
00121     SSL_CTX_set_default_passwd_cb(c, tls_no_passphrase_cb);
00122     
00123     /* set key and certs against the SSL context */
00124     dbg_err_if (tls_load_creds(c, cargs));
00125  
00126     /* generate RSA ephemeral parameters and load into SSL_CTX */
00127     dbg_err_if (tls_gen_eph_rsa(c));
00128 
00129     /* (possibly) generate DH parameters and load into SSL_CTX */
00130     dbg_err_if (tls_gendh_params(c, cargs->dh));
00131 
00132     /* set the session id context */
00133     dbg_err_if (tls_sid_context(c, &tls_sid));
00134 
00135     return c;
00136 err:
00137     if (c)
00138         SSL_CTX_free(c);
00139     return NULL;
00140 }
00141 
00142 static int tls_sid_context (SSL_CTX *c, int *sid)
00143 {
00144     int rc;
00145 
00146     dbg_return_if (c == NULL, ~0); 
00147     dbg_return_if (sid == NULL, ~0); 
00148     
00149     /* every time tls_init_ctx() is called, move on the session id context */
00150     (*sid)++;
00151 
00152     rc = SSL_CTX_set_session_id_context(c, (void *) sid, sizeof(int));
00153     dbg_err_ifm (rc == 0, "error setting sid: %s", tls_get_error());
00154     
00155     return 0;
00156 err:
00157     return ~0;
00158 }
00159 
00160 static int tls_context (SSL_CTX **pc)
00161 {
00162     SSL_CTX *c = NULL;
00163 
00164     dbg_return_if (pc == NULL, ~0);
00165 
00166     c = SSL_CTX_new(SSLv23_server_method());
00167     dbg_err_ifm (c == NULL, "error creating SSL CTX: %s", tls_get_error());
00168 
00169     *pc = c;
00170 
00171     return 0;
00172 err:
00173     return ~0;
00174 }
00175 
00176 /* XXX very primitive */
00177 char *tls_get_error (void)
00178 {
00179     unsigned long e = ERR_get_error();
00180     return ERR_error_string(e, NULL);
00181 }
00182 
00183 /* if skey is NULL, assume private key in scert, ca can be NULL */
00184 static int tls_load_creds (SSL_CTX *c, tls_ctx_args_t *cargs)
00185 {
00186     dbg_return_if (c == NULL, ~0);
00187     dbg_return_if (cargs == NULL, ~0);
00188     dbg_return_if (cargs->cert == NULL, ~0);
00189 
00190     /* if key file unspecified assume key+cert are bundled */
00191     if (!cargs->key)
00192         cargs->key = cargs->cert;
00193     
00194     /* set ca if supplied */
00195     if (cargs->ca)
00196         crit_err_ifm(tls_load_verify_locations(c, cargs->ca),
00197                 "error loading CA certificate from %s", cargs->ca);
00198 
00199     /* explicitly set the list of CAs for which we accept certificates */
00200     if (cargs->ca && cargs->vmode != SSL_VERIFY_NONE)
00201         SSL_CTX_set_client_CA_list(c, tls_load_client_CA_file(cargs->ca));
00202 
00203     /* load server certificate */
00204     crit_err_ifm (tls_use_certificate_file(c, cargs->cert, 
00205                 SSL_FILETYPE_PEM) <= 0, 
00206             "error loading server certificate from %s", cargs->cert);
00207 
00208     /* load private key (perhaps from the cert file) */
00209     crit_err_ifm (tls_use_PrivateKey_file(c, cargs->key, SSL_FILETYPE_PEM) <= 0,
00210             "error loading the private key from %s", cargs->key);
00211 
00212     /* check skey consistency against scert */
00213     crit_err_ifm (!SSL_CTX_check_private_key(c),
00214             "the given private key doesn't seem to belong "
00215             "to the server certificate");
00216 
00217     /* load optional server certficate chain */
00218     if (cargs->certchain)
00219         crit_err_ifm (tls_use_certificate_chain(c, cargs->certchain, 
00220                     0, NULL) < 0, 
00221                 "error loading server certificate chain");
00222 
00223     /* load optional CRL file + opts into args */
00224     if (cargs->crl)
00225         crit_err_ifm (tls_use_crls(c, cargs), "error loading CA CRL file");
00226 
00227     /* set SSL verify mode (no, optional, required) and callbacks */
00228     SSL_CTX_set_verify(c, cargs->vmode, cb_vfy);
00229 
00230     /* set verification depth */
00231     if (cargs->depth > 0)
00232         SSL_CTX_set_verify_depth(c, cargs->depth);
00233 
00234     return 0;
00235 err:
00236     return ~0;
00237 }
00238 
00239 static int cb_vfy (int ok, X509_STORE_CTX *store_ctx)
00240 {
00241     int e;
00242     X509 *x;
00243     char buf[1024];
00244     
00245     if (ok)
00246         return ok;
00247 
00248     e = X509_STORE_CTX_get_error(store_ctx);
00249     x = store_ctx->current_cert;
00250 
00251     /* at present just put a note in the log.
00252      * the idea is that here we can catch CRL specific errors and, based 
00253      * on the value of crl_opts directive, use different accept/reject 
00254      * policies.  e.g. return ok in case X509_V_ERR_CRL_HAS_EXPIRED, etc. */
00255     info("%s; current certificate subject is %s", 
00256             X509_verify_cert_error_string(e), 
00257             X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof buf));
00258 
00259     return 0;
00260 }
00261 
00262 static int tls_init (void)
00263 {
00264     if (tls_inited)
00265         return 0;
00266 
00267     SSL_load_error_strings();
00268     dbg_err_if (!SSL_library_init());
00269     tls_rand_seed(); 
00270     tls_inited++;
00271 
00272     return 0;
00273 
00274 err:
00275     dbg("%s", tls_get_error()); 
00276     return ~0;
00277 }
00278 
00279 static void tls_rand_seed (void)
00280 {
00281     struct timeval tv;
00282     tls_rand_seed_t seed;
00283 
00284     (void) gettimeofday(&tv, NULL);
00285     
00286     seed.pid = getpid();
00287     seed.t1 = tv.tv_sec; 
00288     seed.t2 = tv.tv_usec;
00289     seed.stack = (void *) &seed;
00290 
00291     RAND_seed((const void *) &seed, sizeof seed);
00292 }
00293 
00294 /* generate RSA ephemeral parameters and load'em into SSL_CTX */
00295 static int tls_gen_eph_rsa(SSL_CTX *c)
00296 {
00297     RSA *eph_rsa = NULL;
00298 
00299     dbg_return_if (c == NULL, ~0);
00300 
00301     dbg_err_if (!(eph_rsa = RSA_generate_key(512, RSA_F4, 0, NULL)));
00302     dbg_err_if (!SSL_CTX_set_tmp_rsa(c, eph_rsa));
00303     RSA_free(eph_rsa); /* eph_rsa is dup'ed by SSL_CTX_set_tmp_rsa() */
00304 
00305     return 0;
00306 err:
00307     dbg("%s", tls_get_error());
00308     if (eph_rsa)
00309         RSA_free(eph_rsa);    
00310 
00311     return ~0;
00312 }
00313 
00314 /* generate DH ephemeral parameters and load'em into SSL_CTX */
00315 static int tls_gendh_params(SSL_CTX *c, const char *dhfile)
00316 {
00317     DH *eph_dh = NULL;
00318 
00319     dbg_return_if (c == NULL, ~0);
00320 
00321     eph_dh = dhfile ? tls_load_dh_param(dhfile) : get_dh1024(); 
00322     dbg_err_if (!(eph_dh));
00323 
00324     dbg_err_if (!SSL_CTX_set_tmp_dh(c, eph_dh));
00325     DH_free(eph_dh);
00326 
00327 #if 0
00328     /* Avoid small subgroup attacks (if p and g are strong primes
00329      * this is not strictly necessary).  This is said to have a negligible (?)
00330      * impact during negotiation phase. TODO: test it ! */
00331     (void) SSL_CTX_set_options(c, SSL_OP_SINGLE_DH_USE); */
00332 #endif /* 0 */
00333 
00334     return 0;
00335 err:
00336     dbg("%s", tls_get_error());
00337     if (eph_dh)
00338         DH_free(eph_dh);
00339 
00340     return ~0;
00341 }
00342 
00343 static DH *tls_load_dh_param (const char *res_name)
00344 {
00345     DH *dh = NULL;
00346     BIO *bio = NULL;
00347 
00348     dbg_return_if (res_name == NULL, NULL);
00349 
00350     /* say return_if here instead of err_if because bio_from_emb()
00351      * could have failed for a non-openssl error */
00352     dbg_return_if (!(bio = tls_get_file_bio(res_name)), NULL);
00353     dbg_err_if (!(dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)));
00354 
00355     BIO_free(bio);
00356 
00357     return dh;
00358 err:
00359     dbg("%s", tls_get_error());
00360     if (bio) 
00361         BIO_free(bio);
00362 
00363     return NULL;
00364 }
00365 
00366 static int tls_no_passphrase_cb (char *buf, int num, int w, void *arg)
00367 {
00368     /* avoid gcc complains */
00369     buf = NULL;
00370     arg = NULL;
00371     num = w = 0;
00372 
00373     return -1;
00374 }
00375 
00376 static int tls_init_ctx_args (tls_ctx_args_t *cargs)
00377 {
00378     dbg_return_if (!cargs, ~0);
00379 
00380     cargs->cert = NULL;
00381     cargs->key = NULL;
00382     cargs->ca = NULL;
00383     cargs->dh = NULL;
00384     cargs->crl = NULL;
00385     cargs->crlopts = 0;
00386     cargs->depth = 1;
00387     cargs->vmode = SSL_VERIFY_NONE;
00388 
00389     return 0;
00390 }
00391 
00392 static int tls_set_ctx_vdepth (u_config_t *cfg, tls_ctx_args_t *cargs)
00393 {
00394     u_config_t    *k;
00395     
00396     dbg_return_if (!cfg || !cargs, ~0);
00397 
00398     if (!u_config_get_subkey(cfg, "verify_depth", &k))
00399         cargs->depth = atoi(u_config_get_value(k));    
00400 
00401     return 0;
00402 }
00403 
00404 static int tls_set_ctx_crlopts (u_config_t *cfg, tls_ctx_args_t *cargs)
00405 {
00406     const char *v;
00407     
00408     dbg_return_if (cfg == NULL, ~0);
00409     dbg_return_if (cargs == NULL, ~0);
00410 
00411     v = u_config_get_subkey_value(cfg, "crl_opts");
00412 
00413     if (v == NULL)
00414     {
00415         cargs->crlopts = 0;
00416         return 0;
00417     }
00418 
00419     if (!strcasecmp(v, "check_all"))
00420         cargs->crlopts = X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL;
00421     else
00422         warn_err("unknown value %s for 'crl_opts' directive", v);
00423 
00424     return 0;
00425 err:
00426     return ~0;
00427 }
00428 
00429 /* 'verify_mode' and 'verify_client' are aliases
00430  * the former is deprecated and retained only for compatibility with klone 1 */
00431 static int tls_set_ctx_vmode (u_config_t *cfg, tls_ctx_args_t *cargs)
00432 {
00433     const char *v;
00434     
00435     dbg_return_if (cfg == NULL, ~0);
00436     dbg_return_if (cargs == NULL, ~0);
00437     
00438     /* try 'verify_mode' directive first then 'verify_client' */
00439     if  ((v = u_config_get_subkey_value(cfg, "verify_mode")) == NULL)
00440         v = u_config_get_subkey_value(cfg, "verify_client");
00441 
00442     if (v == NULL || !strcasecmp(v, "no"))  /* unset == none */
00443         cargs->vmode = SSL_VERIFY_NONE;
00444     else if (!strcasecmp(v, "optional"))
00445         cargs->vmode = SSL_VERIFY_PEER;
00446     else if (!strcasecmp(v, "require"))
00447         cargs->vmode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
00448     else
00449         warn_err("unknown verification value:\'%s\'", v);
00450     
00451     return 0;
00452 err:
00453     return ~0;
00454 }
00455 
00456 static int tls_check_ctx (tls_ctx_args_t *cargs)
00457 {
00458     dbg_return_if (cargs == NULL, ~0);
00459 
00460     /* cert_file is a MUST */
00461     crit_err_ifm (!cargs->cert || strlen(cargs->cert) == 0, 
00462         "missing cert_file option parameter");
00463 
00464     /* if private key file is missing, assume the key is inside cert_file */
00465     warn_ifm (!cargs->key, 
00466         "missing certificate key option, assuming the key is inside cert_file");
00467 
00468     /* if verify_mode == "required" the CA file MUST be present */
00469     if (cargs->vmode & SSL_VERIFY_PEER)
00470         crit_err_ifm (!cargs->ca, 
00471             "SSL verify is required but CA certificate filename is missing");
00472 
00473     /* if 'crl_file' was given, set crlopts at least to verify the client
00474      * certificate against the supplied CRL */
00475     if (cargs->crl && cargs->crlopts == 0)
00476         cargs->crlopts = X509_V_FLAG_CRL_CHECK;
00477 
00478     return 0;
00479 err:
00480     return ~0;
00481 }
00482 
00483 
00484 static void tls_free_ctx_args (tls_ctx_args_t *cargs)
00485 {
00486     KLONE_FREE(cargs);
00487     return;
00488 }
00489 #endif /* HAVE_LIBOPENSSL */