tls_glue.c

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

←Products
Copyright © 2005-2012 - KoanLogic S.r.l. - All rights reserved