/* * Copyright (c) 2002-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ /* * OpenFWTK SSL wrapper functions * * (C) Copyright 2002 ArkanoiD * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef OpenBSD #include #include #include #else #include #include #include #endif #include "firewall.h" #include "auth.h" #include "fwfunc.h" #include "firewall2.h" SSL_CTX *proxy_SSLCTX; STACK_OF(X509_NAME) *proxy_SSLcertnames; int proxy_check_cert(ssl,host,vrfy) SSL *ssl; char *host; char *vrfy; { X509 *peer; char peer_CN[256]; int err; if (!strcasecmp(vrfy,"none")) return(0); if ((err = SSL_get_verify_result(ssl)) != X509_V_OK) { syslog (LLEV,"SSL certificate does not verify, %d", err); return(1); } if (strcasecmp(vrfy,"checkaddr")) return(0); peer = SSL_get_peer_certificate(ssl); X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName,peer_CN,256); return(!hostmatch(peer_CN,host)); } void proxy_SSLinit() { char *sslkeyfile = NULL; char *sslcertfile = NULL; char *sslCAfile = NULL; sslkeyfile = proxy_conf_string(proxy_confp,"private-key"); sslcertfile = proxy_conf_string(proxy_confp,"certificate"); sslCAfile = proxy_conf_string(proxy_confp,"CAfile"); SSL_library_init(); SSL_load_error_strings(); if (!sslcertfile) { syslog(LLEV,"fwtkcfgerr: certifcate file not specified"); exit(1); } if (!sslkeyfile) { syslog(LLEV,"fwtkcfgerr: key file not specified"); exit(1); } if (!(proxy_SSLCTX = SSL_CTX_new(SSLv23_method()))) { syslog(LLEV,"fwtksyserr: cannot create SSL context, %s", ERR_error_string(ERR_get_error(), NULL)); exit(1); } if (!(SSL_CTX_use_certificate_chain_file(proxy_SSLCTX, sslcertfile))) { syslog(LLEV,"fwtksyserr: cannot read certificate chain file %s:%s", sslcertfile,ERR_error_string(ERR_get_error(), NULL)); exit(1); } if (!(SSL_CTX_use_PrivateKey_file(proxy_SSLCTX,sslkeyfile, SSL_FILETYPE_PEM))) { syslog(LLEV,"fwtksyserr: error loading private key %s:%s", sslkeyfile, ERR_error_string(ERR_get_error(), NULL)); exit(1); } if (sslCAfile) { if (!(SSL_CTX_load_verify_locations(proxy_SSLCTX, sslCAfile,NULL))) { syslog(LLEV,"fwtksyserr: error setting verify locations %s:%s", sslCAfile, ERR_error_string(ERR_get_error(), NULL)); exit(1); } if (!(proxy_SSLcertnames =SSL_load_client_CA_file(sslCAfile))) { syslog(LLEV,"fwtksyserr: error loading CA file %s:%s", sslCAfile, ERR_error_string(ERR_get_error(), NULL)); exit(1); } } } SSL* proxy_SSLaccept(int fd, char *rladdr, char *riaddr, char *cvrfy) { SSL *cconn; cconn = SSL_new(proxy_SSLCTX); SSL_set_fd(cconn,fd); SSL_set_client_CA_list(cconn,proxy_SSLcertnames); if (strcasecmp(cvrfy,"none")) SSL_set_verify(cconn,SSL_VERIFY_PEER,NULL); else SSL_set_verify(cconn,SSL_VERIFY_NONE,NULL); if (SSL_accept(cconn) == -1) { syslog(LLEV,"fwtksyserr: error accepting SSL connection: %s", ERR_error_string(ERR_get_error(), NULL)); exit(1); } if (proxy_check_cert(cconn,riaddr,cvrfy)) { syslog(LLEV,"deny host=%s/%s certificate does not match host identification", rladdr,riaddr); exit(1); } return(cconn); } SSL* proxy_SSLconnect(int fd, char *dst, char *svrfy) { SSL *sconn; sconn = SSL_new(proxy_SSLCTX); SSL_set_fd(sconn,fd); if (strcasecmp(svrfy,"none")) SSL_set_verify(sconn,SSL_VERIFY_PEER,NULL); else SSL_set_verify(sconn,SSL_VERIFY_NONE,NULL); if (SSL_connect(sconn) == -1) { syslog(LLEV,"fwtksyserr: error initiating SSL connection: %s", ERR_error_string(ERR_get_error(), NULL)); exit(1); } if (proxy_check_cert(sconn,dst,svrfy)) { syslog(LLEV,"deny host=%s/%s destination=%s certificate does not match destination identification", proxy_stats.rladdr,proxy_stats.riaddr,dst); exit(1); } return(sconn); } int proxy_SSLread(SSL *conn, char *buf, int buflen) { int x; if ((x = SSL_read(conn,buf,buflen) > 0)) return(x); switch (SSL_get_error(conn,x)) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: return(0); case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: syslog(LLEV,"SSL read error: %.128s", ERR_error_string(ERR_get_error(), NULL)); return(0); default: return(0); } } int proxy_SSLwrite(SSL *conn, char *buf, int buflen) { unsigned int nbytes = 0; int j; while (nbytes < buflen) { j = SSL_write(conn,buf,buflen-nbytes); if (j <= 0) { switch (SSL_get_error(conn,j)) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: return (nbytes ? nbytes : j); case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: continue; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: syslog(LLEV,"SSL write error: %.128s", ERR_error_string(ERR_get_error(), NULL)); return (nbytes ? nbytes : j); } } buf += j; nbytes += j; } return nbytes; }