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

tls_glue.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_glue.c,v 1.13 2007/08/08 22:04:12 tho Exp $
00009  */
00010 
00011 /*
00012  * This product includes software developed by Ralf S. Engelschall 
00013  * <rse@engelschall.com> for use in the mod_ssl project (http://www.modssl.org/)
00014  * 
00015  * This product includes software developed by the OpenSSL Project
00016  * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
00017  */
00018 
00019 #include "klone_conf.h"
00020 #include <u/libu.h>
00021 #include <klone/io.h>
00022 #include <klone/emb.h>
00023 #include <klone/tlsprv.h>
00024 
00025 #ifndef HAVE_LIBOPENSSL
00026 int tls_dummy_decl_stub = 0;
00027 #else /* HAVE_LIBOPENSSL */
00028 #include <openssl/ssl.h>
00029 #include <openssl/x509.h>
00030 
00031 
00032 /* map an emb resource to a OpenSSL memory BIO */
00033 BIO *bio_from_emb (const char *res_name)
00034 {
00035     int c;
00036     char buf[1024];
00037     io_t *tmp = NULL;
00038     BIO *b = NULL;
00039 
00040     dbg_return_if (res_name == NULL, NULL);
00041 
00042     dbg_err_if (emb_open(res_name, &tmp));
00043     dbg_err_if (!(b = BIO_new(BIO_s_mem())));
00044 
00045     for (;;)
00046     {
00047         c = io_read(tmp, buf, sizeof buf);
00048 
00049         if (c == 0)     /* EOF */
00050             break;
00051         else if (c < 0) /* read error */
00052             goto err;
00053 
00054         dbg_err_if (BIO_write(b, buf, c) <= 0);
00055     }
00056 
00057     io_free(tmp);
00058 
00059     return b;
00060 err:
00061     if (tmp) 
00062         io_free(tmp);
00063     if (b)  
00064         BIO_free(b);
00065 
00066     return NULL;
00067 }
00068 
00069 BIO* tls_get_file_bio(const char *res_name)
00070 {
00071     BIO *b = NULL;
00072 
00073     /* load the cert from the embfs */
00074     if((b = bio_from_emb(res_name)) != NULL)
00075         return b;
00076 
00077     /* load the cert from the file system */
00078     if((b = BIO_new_file(res_name, "r")) != NULL)
00079         return b;
00080 
00081     /* no cert found */
00082     return NULL;
00083 }
00084 
00085 
00086 /* XXX the original returns the number of certs/crls added */
00087 int tls_load_verify_locations (SSL_CTX *c, const char *res_name)
00088 {
00089     int i;
00090     BIO *b = NULL;
00091     STACK_OF(X509_INFO) *info = NULL;
00092 
00093     dbg_return_if (!c, ~0);
00094     dbg_return_if (!res_name, ~0);
00095 
00096     dbg_err_if (!(b = tls_get_file_bio(res_name)));
00097     dbg_err_if (!(info = PEM_X509_INFO_read_bio(b, NULL, NULL, NULL)));
00098     BIO_free(b);
00099 
00100     for (i = 0; i < sk_X509_INFO_num(info); i++)
00101     {
00102         X509_INFO   *tmp = sk_X509_INFO_value(info, i);
00103 
00104         if (tmp->x509)
00105             X509_STORE_add_cert(c->cert_store, tmp->x509); 
00106 
00107         if (tmp->crl)
00108             X509_STORE_add_crl(c->cert_store, tmp->crl); 
00109     }
00110 
00111     sk_X509_INFO_pop_free(info, X509_INFO_free);
00112 
00113     return 0;
00114 err:
00115     if (b)
00116         BIO_free(b);
00117     if (info)
00118         sk_X509_INFO_pop_free(info, X509_INFO_free);
00119 
00120     return ~0;
00121 } 
00122 
00123 /* reads certificates from file and returns a STACK_OF(X509_NAME) with 
00124  * the subject names found */
00125 STACK_OF(X509_NAME) *tls_load_client_CA_file (const char *res_name)
00126 {
00127     BIO *b = NULL;
00128     X509 *x = NULL;
00129     X509_NAME *xn = NULL;
00130     STACK_OF(X509_NAME) *ret, *sk;
00131 
00132     dbg_return_if (!res_name, NULL);
00133     
00134     dbg_err_if (!(ret = sk_X509_NAME_new_null()));
00135     dbg_err_if (!(sk = sk_X509_NAME_new(X509_NAME_cmp)));
00136     dbg_err_if (!(b = tls_get_file_bio(res_name)));
00137 
00138     for (;;)
00139     {
00140         if (!PEM_read_bio_X509(b, &x, NULL, NULL))
00141             break;
00142 
00143         dbg_err_if (!(xn = X509_get_subject_name(x)));
00144 
00145         /* check for duplicates */
00146         dbg_err_if (!(xn = X509_NAME_dup(xn)));
00147         if (sk_X509_NAME_find(sk, xn) >= 0)
00148             X509_NAME_free(xn);
00149         else
00150         {
00151             sk_X509_NAME_push(sk, xn);
00152             sk_X509_NAME_push(ret, xn);
00153         }
00154     }
00155 
00156     sk_X509_NAME_free(sk);
00157     BIO_free(b);
00158     X509_free(x);
00159 
00160     return ret;
00161 err:
00162     if (ret)
00163     {
00164         sk_X509_NAME_pop_free(ret, X509_NAME_free);
00165         ret = NULL;
00166     }
00167     if (sk)
00168         sk_X509_NAME_free(sk);
00169     if (b)
00170         BIO_free(b);
00171     if (x)
00172         X509_free(x);
00173 
00174     return ret;
00175 }
00176 
00177 /* basically a wrapper for SSL_CTX_use_certificate() */
00178 int tls_use_certificate_file (SSL_CTX *ctx, const char *res_name, int type)
00179 {
00180     BIO *b = NULL;
00181     int ret = 0;
00182     X509 *x = NULL;
00183 
00184     dbg_return_if (!ctx, 0);
00185     dbg_return_if (!res_name, 0);
00186     dbg_return_if (type != SSL_FILETYPE_PEM, 0);
00187 
00188     dbg_goto_if (!(b = tls_get_file_bio(res_name)), end);
00189     dbg_goto_if (!(x = PEM_read_bio_X509(b, NULL, NULL, NULL)), end);
00190     ret = SSL_CTX_use_certificate(ctx, x);
00191     /* fall through */
00192 end:
00193     if (x)
00194         X509_free(x);
00195     if (b)
00196         BIO_free(b);
00197 
00198     return ret;
00199 }
00200 
00201 int tls_use_crls (SSL_CTX *ctx, tls_ctx_args_t *cargs)
00202 {
00203 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
00204     int count;
00205     BIO *b = NULL;
00206     X509_CRL *crl = NULL;
00207     X509_STORE *store;
00208 
00209     dbg_return_if (cargs == NULL, ~0);
00210     dbg_return_if (cargs->crl == NULL, ~0);
00211 
00212     /* get X509 STORE i.e. client certificate verify context */
00213     dbg_err_if ((store = SSL_CTX_get_cert_store(ctx)) == NULL);
00214 
00215     /* read CRL from the resource (embfs or fs) */
00216     dbg_err_if ((b = tls_get_file_bio(cargs->crl)) == NULL);
00217 
00218     /* get CRLs one by one out of 'cargs->crl' */
00219     for (count = 0; ; count++)
00220     {
00221         crl = PEM_read_bio_X509_CRL(b, NULL, NULL, NULL);
00222 
00223         if (crl == NULL)
00224         {
00225             u_long e = ERR_peek_last_error();
00226 
00227             if (ERR_GET_REASON(e) == PEM_R_NO_START_LINE && count > 0)
00228             {
00229                 ERR_clear_error();
00230                 break;
00231             } 
00232             else if (count == 0)
00233                 warn_err("no CRL found in file \'%s\'", cargs->crl);
00234             else
00235                 warn_err("bad CRL (%d) in file \'%s\'", count, cargs->crl);
00236         }
00237 
00238         /* add CRL to the verify ctx */
00239         dbg_err_if (!X509_STORE_add_crl(store, crl));
00240         X509_CRL_free(crl);
00241         crl = NULL;
00242     }
00243  
00244     /* say to openssl how we want to check certificate revocation status:
00245      * every cert in chain or just the client certificate */
00246     X509_STORE_set_flags(store, cargs->crlopts);
00247 
00248     BIO_free(b);
00249 
00250     return 0;
00251 err:
00252     if (b)
00253         BIO_free(b);
00254     if (crl)
00255         X509_CRL_free(crl);
00256 
00257     return ~0;
00258 #else
00259     u_unused_args(ctx, cargs);
00260     warn("OpenSSL too old (%d): CRL configuration directives won't be honoured",
00261             OPENSSL_VERSION_NUMBER);
00262     return 0;
00263 #endif  
00264 }
00265 
00266 /* wrapper for SSL_CTX_use_PrivateKey() */
00267 int tls_use_PrivateKey_file (SSL_CTX *ctx, const char *res_name, int type)
00268 {
00269     int ret = 0;
00270     BIO *b = NULL;
00271     EVP_PKEY *pkey = NULL;
00272 
00273     dbg_return_if (!ctx, 0);
00274     dbg_return_if (!res_name, 0);
00275     dbg_return_if (type != SSL_FILETYPE_PEM, 0);
00276 
00277     dbg_goto_if (!(b = tls_get_file_bio(res_name)), end);
00278     dbg_goto_if (!(pkey = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL)), end);
00279     ret = SSL_CTX_use_PrivateKey(ctx, pkey);
00280     EVP_PKEY_free(pkey);
00281     /* fall through */
00282 end:
00283     if (b)
00284         BIO_free(b);
00285 
00286     return ret;
00287 }
00288 
00289 /* Read a file that optionally contains the server certificate in PEM
00290  * format, possibly followed by a sequence of CA certificates that
00291  * should be sent to the peer in the SSL Certificate message.  */
00292 int tls_use_certificate_chain (SSL_CTX *ctx, const char *res_name, 
00293         int skipfirst, int (*cb)(char *, int, int, void *)) 
00294 {
00295     BIO *b = NULL;
00296     X509 *x = NULL;
00297     unsigned long err;
00298     int n;
00299 
00300     dbg_return_if (!ctx, -1);
00301     dbg_return_if (!res_name, -1);
00302 
00303     dbg_err_if (!(b = tls_get_file_bio(res_name)));
00304 
00305     /* optionally skip a leading server certificate */
00306     if (skipfirst)
00307     {
00308         dbg_err_if (!(x = PEM_read_bio_X509(b, NULL, cb, NULL)));
00309         X509_free(x);
00310         x = NULL;
00311     }
00312 
00313     /* free a perhaps already configured extra chain */
00314     if (!ctx->extra_certs)
00315     {
00316         sk_X509_pop_free(ctx->extra_certs, X509_free);
00317         ctx->extra_certs = NULL;
00318     }
00319 
00320     /* create new extra chain by loading the certs */
00321     n = 0;
00322     while ((x = PEM_read_bio_X509(b, NULL, cb, NULL))) 
00323     {
00324         dbg_err_if (!SSL_CTX_add_extra_chain_cert(ctx, x));
00325         n++;
00326     }
00327 
00328     /* Make sure that only the error is just an EOF */
00329     if ((err = ERR_peek_error()) > 0) 
00330     {
00331         dbg_err_if (!(ERR_GET_LIB(err) == ERR_LIB_PEM && 
00332                     ERR_GET_REASON(err) == PEM_R_NO_START_LINE));
00333 
00334         while (ERR_get_error() > 0) ;
00335     }
00336 
00337     BIO_free(b);
00338 
00339     return n;
00340 err:
00341     if (b)
00342         BIO_free(b);
00343     if (x)
00344         X509_free(x);
00345 
00346     return -1;
00347 }
00348 
00349 #endif /* HAVE_LIBOPENSSL */