diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2009-04-02 14:30:52 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2009-04-02 14:30:52 +0000 |
commit | 117177735019c97721565de7e00119449b55dd72 (patch) | |
tree | 67cf83929709feb5e4526b048fbf3cfab8c9ab9e | |
parent | 714137767d4e5dcc2e091bf3dba123f121d00853 (diff) |
add support to specify a ca file (eg. /etc/ssl/cert.pem) to verify ssl
server certificates when connecting as an SSL client from relays. it
works so far, but needs more testing and is currently lacking support
for certificate revocation (like CRL or OCSP). the file ssl_privsep.c
is extended to implement more code that should be in openssl to allow
loading the ca from chroot...
-rw-r--r-- | usr.sbin/relayd/parse.y | 15 | ||||
-rw-r--r-- | usr.sbin/relayd/relay.c | 23 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.conf.5 | 26 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.h | 6 | ||||
-rw-r--r-- | usr.sbin/relayd/ssl_privsep.c | 85 |
5 files changed, 140 insertions, 15 deletions
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y index ded18cde6a9..09e99fb082f 100644 --- a/usr.sbin/relayd/parse.y +++ b/usr.sbin/relayd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.130 2009/04/01 15:07:38 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.131 2009/04/02 14:30:51 reyk Exp $ */ /* * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org> @@ -127,7 +127,7 @@ typedef struct { %} -%token ALL APPEND BACKLOG BACKUP BUFFER CACHE CHANGE CHECK +%token ALL APPEND BACKLOG BACKUP BUFFER CA CACHE CHANGE CHECK %token CIPHERS CODE COOKIE DEMOTE DIGEST DISABLE ERROR EXPECT %token EXTERNAL FILENAME FILTER FORWARD FROM HASH HEADER HOST ICMP %token INCLUDE INET INET6 INTERFACE INTERVAL IP LABEL LISTEN @@ -136,7 +136,7 @@ typedef struct { %token QUERYSTR REAL REDIRECT RELAY REMOVE REQUEST RESPONSE RETRY %token RETURN ROUNDROBIN ROUTE SACK SCRIPT SEND SESSION SOCKET %token SSL STICKYADDR STYLE TABLE TAG TCP TIMEOUT TO -%token TRANSPARENT TRAP UPDATES URL VIRTUAL WITH +%token TRANSPARENT TRAP UPDATES URL VIRTUAL WITH %token <v.string> STRING %token <v.number> NUMBER %type <v.string> hostname interface table @@ -886,6 +886,14 @@ sslflags : SESSION CACHE sslcache { proto->cache = $3; } } free($2); } + | CA FILENAME STRING { + if (proto->sslca != NULL) { + yyerror("sslca already specified"); + free($3); + YYERROR; + } + proto->sslca = $3; + } | NO flag { proto->sslflags &= ~($2); } | flag { proto->sslflags |= $1; } ; @@ -1466,6 +1474,7 @@ lookup(char *s) { "backlog", BACKLOG }, { "backup", BACKUP }, { "buffer", BUFFER }, + { "ca", CA }, { "cache", CACHE }, { "change", CHANGE }, { "check", CHECK }, diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c index a0b45fa4803..8117c8e21cf 100644 --- a/usr.sbin/relayd/relay.c +++ b/usr.sbin/relayd/relay.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay.c,v 1.108 2009/04/01 14:56:38 reyk Exp $ */ +/* $OpenBSD: relay.c,v 1.109 2009/04/02 14:30:51 reyk Exp $ */ /* * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> @@ -2615,6 +2615,15 @@ relay_ssl_ctx_create(struct relay *rlay) if (!SSL_CTX_set_cipher_list(ctx, proto->sslciphers)) goto err; + /* Verify the server certificate if we have a CA chain */ + if ((rlay->rl_conf.flags & F_SSLCLIENT) && + (rlay->rl_ssl_ca != NULL)) { + if (!ssl_ctx_load_verify_memory(ctx, + rlay->rl_ssl_ca, rlay->rl_ssl_ca_len)) + goto err; + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + } + if ((rlay->rl_conf.flags & F_SSL) == 0) return (ctx); @@ -3113,9 +3122,17 @@ relay_load_file(const char *name, off_t *len) int relay_load_certfiles(struct relay *rlay) { + struct protocol *proto = rlay->rl_proto; char certfile[PATH_MAX]; char hbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + if ((rlay->rl_conf.flags & F_SSLCLIENT) && (proto->sslca != NULL)) { + if ((rlay->rl_ssl_ca = relay_load_file(proto->sslca, + &rlay->rl_ssl_ca_len)) == NULL) + return (-1); + log_debug("relay_load_certfiles: using ca %s", proto->sslca); + } + if ((rlay->rl_conf.flags & F_SSL) == 0) return (0); @@ -3128,7 +3145,7 @@ relay_load_certfiles(struct relay *rlay) if ((rlay->rl_ssl_cert = relay_load_file(certfile, &rlay->rl_ssl_cert_len)) == NULL) return (-1); - log_debug("relay_load_certfile: using certificate %s", certfile); + log_debug("relay_load_certfiles: using certificate %s", certfile); if (snprintf(certfile, sizeof(certfile), "/etc/ssl/private/%s.key", hbuf) == -1) @@ -3136,7 +3153,7 @@ relay_load_certfiles(struct relay *rlay) if ((rlay->rl_ssl_key = relay_load_file(certfile, &rlay->rl_ssl_key_len)) == NULL) return (-1); - log_debug("relay_load_certfile: using private key %s", certfile); + log_debug("relay_load_certfiles: using private key %s", certfile); return (0); } diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5 index 3a08596fd07..22e1e731086 100644 --- a/usr.sbin/relayd/relayd.conf.5 +++ b/usr.sbin/relayd/relayd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: relayd.conf.5,v 1.101 2009/04/01 14:56:38 reyk Exp $ +.\" $OpenBSD: relayd.conf.5,v 1.102 2009/04/02 14:30:51 reyk Exp $ .\" .\" Copyright (c) 2006, 2007 Reyk Floeter <reyk@openbsd.org> .\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 1 2009 $ +.Dd $Mdocdate: April 2 2009 $ .Dt RELAYD.CONF 5 .Os .Sh NAME @@ -521,9 +521,9 @@ client will be retained in this case. The .Ic with ssl directive enables client-side SSL mode to connect to the remote host. -Note that -.Xr relayd 8 -will not verify the remote SSL certificate. +Verification of server certificates can be enabled by setting the +.Ic ca file +option in the protocol section. .Pp The following options may be specified for forward directives: .Pp @@ -945,6 +945,13 @@ Set the SSL options and session settings. This is only used if SSL is enabled in the relay. Valid options are: .Bl -tag -width Ds +.It Ic ca file Ar path +This option enables CA verification in SSL client mode. +The daemon will load the CA (Certificate Authority) certificates from +the specified path to verify the server certificates. +.Ox +provides a default CA bundle in +.Pa /etc/ssl/cert.pem . .It Ic ciphers Ar string Set the string defining the SSL cipher suite. If not specified, the default value @@ -1036,6 +1043,9 @@ Service name database. Location of the relay SSL server certificates, where .Ar address is the configured IP address of the relay. +.It Pa /etc/ssl/cert.pem +Default location of the CA bundle that can be used with +.Xr relayd 8 . .El .Sh EXAMPLES This configuration file would create a service @@ -1142,5 +1152,7 @@ and .An Reyk Floeter Aq reyk@openbsd.org . .Sh CAVEATS .Xr relayd 8 -does not support verification of server certificates when connecting -to a remote host using the SSL protocol. +Verification of SSL server certificates is based on a static CA bundle +and +.Xr relayd 8 +currently does not support CRLs (Certificate Revocation Lists). diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h index 5a0813250da..f436f871523 100644 --- a/usr.sbin/relayd/relayd.h +++ b/usr.sbin/relayd/relayd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.h,v 1.114 2009/04/01 14:56:38 reyk Exp $ */ +/* $OpenBSD: relayd.h,v 1.115 2009/04/02 14:30:51 reyk Exp $ */ /* * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -601,6 +601,7 @@ struct protocol { u_int8_t tcpipminttl; u_int8_t sslflags; char sslciphers[768]; + char *sslca; char name[MAX_NAME_SIZE]; int cache; enum prototype type; @@ -664,6 +665,8 @@ struct relay { off_t rl_ssl_cert_len; char *rl_ssl_key; off_t rl_ssl_key_len; + char *rl_ssl_ca; + off_t rl_ssl_ca_len; struct ctl_stats rl_stats[RELAY_MAXPROC + 1]; @@ -884,6 +887,7 @@ void ssl_error(const char *, const char *); /* ssl_privsep.c */ int ssl_ctx_use_private_key(SSL_CTX *, char *, off_t); int ssl_ctx_use_certificate_chain(SSL_CTX *, char *, off_t); +int ssl_ctx_load_verify_memory(SSL_CTX *, char *, off_t); /* relayd.c */ struct host *host_find(struct relayd *, objid_t); diff --git a/usr.sbin/relayd/ssl_privsep.c b/usr.sbin/relayd/ssl_privsep.c index ed01d55db5a..41983c0d441 100644 --- a/usr.sbin/relayd/ssl_privsep.c +++ b/usr.sbin/relayd/ssl_privsep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_privsep.c,v 1.6 2007/11/24 17:07:28 reyk Exp $ */ +/* $OpenBSD: ssl_privsep.c,v 1.7 2009/04/02 14:30:51 reyk Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. @@ -62,6 +62,9 @@ * Adapted from openssl's ssl_rsa.c by Pierre-Yves Ritschard . */ +#include <sys/types.h> +#include <sys/uio.h> + #include <unistd.h> #include <stdio.h> @@ -75,6 +78,23 @@ int ssl_ctx_use_private_key(SSL_CTX *, char *, off_t); int ssl_ctx_use_certificate_chain(SSL_CTX *, char *, off_t); +int ssl_ctx_load_verify_memory(SSL_CTX *, char *, off_t); +int ssl_by_mem_ctrl(X509_LOOKUP *, int, const char *, long, char **); + +X509_LOOKUP_METHOD x509_mem_lookup = { + "Load cert from memory", + NULL, /* new */ + NULL, /* free */ + NULL, /* init */ + NULL, /* shutdown */ + ssl_by_mem_ctrl, /* ctrl */ + NULL, /* get_by_subject */ + NULL, /* get_by_issuer_serial */ + NULL, /* get_by_fingerprint */ + NULL, /* get_by_alias */ +}; + +#define X509_L_ADD_MEM 3 int ssl_ctx_use_private_key(SSL_CTX *ctx, char *buf, off_t len) @@ -168,3 +188,66 @@ end: BIO_free(in); return (ret); } + +int +ssl_ctx_load_verify_memory(SSL_CTX *ctx, char *buf, off_t len) +{ + X509_LOOKUP *lu; + struct iovec iov; + + if ((lu = X509_STORE_add_lookup(ctx->cert_store, + &x509_mem_lookup)) == NULL) + return (0); + + iov.iov_base = buf; + iov.iov_len = len; + + if (!ssl_by_mem_ctrl(lu, X509_L_ADD_MEM, + (const char *)&iov, X509_FILETYPE_PEM, NULL)) + return (0); + + return (1); +} + +int +ssl_by_mem_ctrl(X509_LOOKUP *lu, int cmd, const char *buf, + long type, char **ret) +{ + STACK_OF(X509_INFO) *inf; + const struct iovec *iov; + X509_INFO *itmp; + BIO *in = NULL; + int i, count = 0; + + iov = (const struct iovec *)buf; + + if (type != X509_FILETYPE_PEM) + goto done; + + if ((in = BIO_new_mem_buf(iov->iov_base, iov->iov_len)) == NULL) + goto done; + + if ((inf = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) + goto done; + + for(i = 0; i < sk_X509_INFO_num(inf); i++) { + itmp = sk_X509_INFO_value(inf, i); + if(itmp->x509) { + X509_STORE_add_cert(lu->store_ctx, itmp->x509); + count++; + } + if(itmp->crl) { + X509_STORE_add_crl(lu->store_ctx, itmp->crl); + count++; + } + } + sk_X509_INFO_pop_free(inf, X509_INFO_free); + + done: + if (!count) + X509err(X509_F_X509_LOAD_CERT_CRL_FILE,ERR_R_PEM_LIB); + + if (in != NULL) + BIO_free(in); + return (count); +} |