Hi, we have another feature suggestion for unbound server :-) Currently, unbound-control interacts with unbound using SSL-protected IP port. For this to function properly, certain SSL-related files should be generated and then maintained. These include client and server certificates and private keys. However, when unbound-control and unbound both reside on the same machine, then using SSL may be an overkill. Of course, not always :) But in our case, when we have a product that contains unbound server and needs to interact with it using unbound-control, we would really like to turn SSL off.
Actually, it's enough to use an SSL algorithm that does not require
authentication, in this case we don't need certificates and keys. A list of
such algorithms may be seen by typing 'openssl ciphers -v "aNULL"'.
Attached patch forces using any algorithm that doesn't require authentication
when a certain option is present in the config file. I have called
it 'control-use-cert', it may be "yes" or "no". With this option it's
possible to have such configuration:
>>>>>>>>>>>>>>>>>>>>>>>>
remote-control:
control-enable: yes
control-use-cert: no
>>>>>>>>>>>>>>>>>>>>>>>>
Note that connection is still encrypted, but not authenticated. And we don't
need to maintain any additional SSL-related files, that's good :-)
Another approach is disabling SSL completely, but that requires many
additional if's in the source code, that's why I thought that modifying SSL
parameters is the way to go.
Please review attached patch and post your suggestions!
Thanks!
--
Best regards,
Ilya Bakulin
genua
Gesellschaft fuer Netzwerk- und Unix-Administration mbH
Domagkstrasse 7, 85551 Kirchheim bei Muenchen
tel +49 89 991950-0, fax -999, www.genua.de
Geschaeftsfuehrer: Dr. Magnus Harlander, Dr. Michaela Harlander,
Bernhard Schneck. Amtsgericht Muenchen HRB 98238
diff --git a/daemon/remote.c b/daemon/remote.c
index a2b2204..981a135 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -46,6 +46,10 @@
#ifdef HAVE_OPENSSL_ERR_H
#include <openssl/err.h>
#endif
+#ifndef HEADER_DH_H
+#include <openssl/dh.h>
+#endif
+
#include <ctype.h>
#include <ldns/ldns.h>
#include "daemon/remote.h"
@@ -127,11 +131,45 @@ timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d)
#endif
}
+/*
+ * The following function was generated using the openssl utility, using
+ * the command : "openssl dhparam -dsaparam -C 512"
+ */
+DH *get_dh512()
+{
+ static unsigned char dh512_p[]={
+ 0xC9,0xD7,0x05,0xDA,0x5F,0xAB,0x14,0xE8,0x11,0x56,0x77,0x85,
+ 0xB1,0x24,0x2C,0x95,0x60,0xEA,0xE2,0x10,0x6F,0x0F,0x84,0xEC,
+ 0xF4,0x45,0xE8,0x90,0x7A,0xA7,0x03,0xFF,0x5B,0x88,0x53,0xDE,
+ 0xC4,0xDE,0xBC,0x42,0x78,0x71,0x23,0x7E,0x24,0xA5,0x5E,0x4E,
+ 0xEF,0x6F,0xFF,0x5F,0xAF,0xBE,0x8A,0x77,0x62,0xB4,0x65,0x82,
+ 0x7E,0xC9,0xED,0x2F,
+ };
+ static unsigned char dh512_g[]={
+ 0x8D,0x3A,0x52,0xBC,0x8A,0x71,0x94,0x33,0x2F,0xE1,0xE8,0x4C,
+ 0x73,0x47,0x03,0x4E,0x7D,0x40,0xE5,0x84,0xA0,0xB5,0x6D,0x10,
+ 0x6F,0x90,0x43,0x05,0x1A,0xF9,0x0B,0x6A,0xD1,0x2A,0x9C,0x25,
+ 0x0A,0xB9,0xD1,0x14,0xDC,0x35,0x1C,0x48,0x7C,0xC6,0x0C,0x6D,
+ 0x32,0x1D,0xD3,0xC8,0x10,0xA8,0x82,0x14,0xA2,0x1C,0xF4,0x53,
+ 0x23,0x3B,0x1C,0xB9,
+ };
+ DH *dh;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+ dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ { DH_free(dh); return(NULL); }
+ dh->length = 160;
+ return(dh);
+}
+
struct daemon_remote*
daemon_remote_create(struct config_file* cfg)
{
char* s_cert;
char* s_key;
+
struct daemon_remote* rc = (struct daemon_remote*)calloc(1,
sizeof(*rc));
if(!rc) {
@@ -156,40 +194,59 @@ daemon_remote_create(struct config_file* cfg)
daemon_remote_delete(rc);
return NULL;
}
- s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
- s_key = fname_after_chroot(cfg->server_key_file, cfg, 1);
- if(!s_cert || !s_key) {
+
+ if (cfg->remote_control_use_cert != 0) {
+ rc->use_cert = 1;
+ s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
+ s_key = fname_after_chroot(cfg->server_key_file, cfg, 1);
+ if(!s_cert || !s_key) {
log_err("out of memory in remote control fname");
goto setup_error;
- }
- verbose(VERB_ALGO, "setup SSL certificates");
- if (!SSL_CTX_use_certificate_file(rc->ctx,s_cert,SSL_FILETYPE_PEM)) {
+ }
+ verbose(VERB_ALGO, "setup SSL certificates");
+ if (!SSL_CTX_use_certificate_file(rc->ctx,s_cert,SSL_FILETYPE_PEM)) {
log_err("Error for server-cert-file: %s", s_cert);
log_crypto_err("Error in SSL_CTX use_certificate_file");
goto setup_error;
- }
- if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) {
+ }
+ if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) {
log_err("Error for server-key-file: %s", s_key);
log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
goto setup_error;
- }
- if(!SSL_CTX_check_private_key(rc->ctx)) {
+ }
+ if(!SSL_CTX_check_private_key(rc->ctx)) {
log_err("Error for server-key-file: %s", s_key);
log_crypto_err("Error in SSL_CTX check_private_key");
goto setup_error;
- }
- if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) {
+ }
+ if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) {
log_crypto_err("Error setting up SSL_CTX verify locations");
- setup_error:
+ setup_error:
free(s_cert);
free(s_key);
daemon_remote_delete(rc);
return NULL;
+ }
+ SSL_CTX_set_client_CA_list(rc->ctx, SSL_load_client_CA_file(s_cert));
+ SSL_CTX_set_verify(rc->ctx, SSL_VERIFY_PEER, NULL);
+ free(s_cert);
+ free(s_key);
+
+ } else {
+ /* No certificates are requested */
+ if(!SSL_CTX_set_cipher_list(rc->ctx, "aNULL")) {
+ log_crypto_err("Failed to set aNULL cipher list");
+ return NULL;
+ }
+
+ /* Since we have no certificates and hence no source of
+ * DH params, let's generate and set them
+ */
+ if(!SSL_CTX_set_tmp_dh(rc->ctx,get_dh512())) {
+ log_crypto_err("Wanted to set DH param, but failed");
+ return NULL;
+ }
}
- SSL_CTX_set_client_CA_list(rc->ctx, SSL_load_client_CA_file(s_cert));
- SSL_CTX_set_verify(rc->ctx, SSL_VERIFY_PEER, NULL);
- free(s_cert);
- free(s_key);
return rc;
}
@@ -1950,6 +2007,8 @@ int remote_control_callback(struct comm_point* c, void* arg, int err,
/* once handshake has completed, check authentication */
if(SSL_get_verify_result(s->ssl) == X509_V_OK) {
+ /* If we use certificates, check peer validity */
+ if (rc->use_cert) {
X509* x = SSL_get_peer_certificate(s->ssl);
if(!x) {
verbose(VERB_DETAIL, "remote control connection "
@@ -1959,6 +2018,7 @@ int remote_control_callback(struct comm_point* c, void* arg, int err,
}
verbose(VERB_ALGO, "remote control connection authenticated");
X509_free(x);
+ }
} else {
verbose(VERB_DETAIL, "remote control connection failed to "
"authenticate with client certificate");
diff --git a/daemon/remote.h b/daemon/remote.h
index 1edc1b8..c45102a 100644
--- a/daemon/remote.h
+++ b/daemon/remote.h
@@ -87,6 +87,8 @@ struct daemon_remote {
struct worker* worker;
/** commpoints for accepting remote control connections */
struct listen_list* accept_list;
+ /* if certificates are used */
+ uint8_t use_cert;
/** number of active commpoints that are handling remote control */
int active;
/** max active commpoints */
diff --git a/smallapp/unbound-checkconf.c b/smallapp/unbound-checkconf.c
index 8b56f96..a2903cb 100644
--- a/smallapp/unbound-checkconf.c
+++ b/smallapp/unbound-checkconf.c
@@ -407,7 +407,7 @@ morechecks(struct config_file* cfg, const char* fname)
endpwent();
}
#endif
- if(cfg->remote_control_enable) {
+ if(cfg->remote_control_enable && cfg->remote_control_use_cert) {
check_chroot_string("server-key-file", &cfg->server_key_file,
cfg->chrootdir, cfg);
check_chroot_string("server-cert-file", &cfg->server_cert_file,
diff --git a/smallapp/unbound-control.c b/smallapp/unbound-control.c
index a872f92..20c3e67 100644
--- a/smallapp/unbound-control.c
+++ b/smallapp/unbound-control.c
@@ -128,27 +128,38 @@ setup_ctx(struct config_file* cfg)
char* s_cert, *c_key, *c_cert;
SSL_CTX* ctx;
- s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
- c_key = fname_after_chroot(cfg->control_key_file, cfg, 1);
- c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1);
- if(!s_cert || !c_key || !c_cert)
+ if(cfg->remote_control_use_cert) {
+ s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
+ c_key = fname_after_chroot(cfg->control_key_file, cfg, 1);
+ c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1);
+ if(!s_cert || !c_key || !c_cert)
fatal_exit("out of memory");
+ }
ctx = SSL_CTX_new(SSLv23_client_method());
if(!ctx)
ssl_err("could not allocate SSL_CTX pointer");
if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2))
ssl_err("could not set SSL_OP_NO_SSLv2");
- if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) ||
- !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)
- || !SSL_CTX_check_private_key(ctx))
+
+ if(cfg->remote_control_use_cert) {
+ if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) ||
+ !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)
+ || !SSL_CTX_check_private_key(ctx))
ssl_err("Error setting up SSL_CTX client key and cert");
- if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1)
+ if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1)
ssl_err("Error setting up SSL_CTX verify, server cert");
- SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+ free(s_cert);
+ free(c_key);
+ free(c_cert);
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+
+ } else {
+ /* No fucking encryption */
+ if(!SSL_CTX_set_cipher_list(ctx, "aNULL")) {
+ ssl_err("Error setting NULL cipher!");
+ }
+ }
- free(s_cert);
- free(c_key);
- free(c_cert);
return ctx;
}
@@ -211,7 +222,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
/** setup SSL on the connection */
static SSL*
-setup_ssl(SSL_CTX* ctx, int fd)
+setup_ssl(SSL_CTX* ctx, int fd, struct config_file* cfg)
{
SSL* ssl;
X509* x;
@@ -237,10 +248,13 @@ setup_ssl(SSL_CTX* ctx, int fd)
/* check authenticity of server */
if(SSL_get_verify_result(ssl) != X509_V_OK)
ssl_err("SSL verification failed");
- x = SSL_get_peer_certificate(ssl);
- if(!x)
+ if(cfg->remote_control_use_cert) {
+ x = SSL_get_peer_certificate(ssl);
+ if(!x)
ssl_err("Server presented no peer certificate");
- X509_free(x);
+ X509_free(x);
+ }
+
return ssl;
}
@@ -318,7 +332,7 @@ go(const char* cfgfile, char* svr, int argc, char* argv[])
/* contact server */
fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0);
- ssl = setup_ssl(ctx, fd);
+ ssl = setup_ssl(ctx, fd, cfg);
/* send command */
ret = go_cmd(ssl, argc, argv);
@@ -406,9 +420,7 @@ int main(int argc, char* argv[])
strerror(errno));
}
}
-
ret = go(cfgfile, svr, argc, argv);
-
#ifdef USE_WINSOCK
WSACleanup();
#endif
diff --git a/util/config_file.h b/util/config_file.h
index 050c3a0..288267f 100644
--- a/util/config_file.h
+++ b/util/config_file.h
@@ -276,6 +276,8 @@ struct config_file {
struct config_strlist* control_ifs;
/** port number for the control port */
int control_port;
+ /** use certificates for remote control */
+ int remote_control_use_cert;
/** private key file for server */
char* server_key_file;
/** certificate file for server */
diff --git a/util/configlexer.lex b/util/configlexer.lex
index 2661ffd..ad6bddc 100644
--- a/util/configlexer.lex
+++ b/util/configlexer.lex
@@ -232,6 +232,7 @@ remote-control{COLON} { YDVAR(0, VAR_REMOTE_CONTROL) }
control-enable{COLON} { YDVAR(1, VAR_CONTROL_ENABLE) }
control-interface{COLON} { YDVAR(1, VAR_CONTROL_INTERFACE) }
control-port{COLON} { YDVAR(1, VAR_CONTROL_PORT) }
+control-use-cert{COLON} { YDVAR(1, VAR_CONTROL_USE_CERT) }
server-key-file{COLON} { YDVAR(1, VAR_SERVER_KEY_FILE) }
server-cert-file{COLON} { YDVAR(1, VAR_SERVER_CERT_FILE) }
control-key-file{COLON} { YDVAR(1, VAR_CONTROL_KEY_FILE) }
diff --git a/util/configparser.y b/util/configparser.y
index 09f77c5..0d89c99 100644
--- a/util/configparser.y
+++ b/util/configparser.y
@@ -104,6 +104,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_HARDEN_BELOW_NXDOMAIN
%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM
%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT
+%token VAR_CONTROL_USE_CERT
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -1162,7 +1163,7 @@ contents_rc: contents_rc content_rc
| ;
content_rc: rc_control_enable | rc_control_interface | rc_control_port |
rc_server_key_file | rc_server_cert_file | rc_control_key_file |
- rc_control_cert_file
+ rc_control_cert_file | rc_control_use_cert
;
rc_control_enable: VAR_CONTROL_ENABLE STRING_ARG
{
@@ -1190,6 +1191,16 @@ rc_control_interface: VAR_CONTROL_INTERFACE STRING_ARG
yyerror("out of memory");
}
;
+rc_control_use_cert: VAR_CONTROL_USE_CERT STRING_ARG
+ {
+ OUTYY(("P(control_use_cert:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->remote_control_use_cert =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
rc_server_key_file: VAR_SERVER_KEY_FILE STRING_ARG
{
OUTYY(("P(rc_server_key_file:%s)\n", $2));
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Unbound-users mailing list [email protected] http://unbound.nlnetlabs.nl/mailman/listinfo/unbound-users
