diff --git a/dtls.c b/dtls.c index c215dc5..52c4d75 100644 --- a/dtls.c +++ b/dtls.c @@ -306,10 +306,11 @@ void *dtlsservernew(void *arg) { struct timeval timeout; struct addrinfo tmpsrvaddr; char tmp[INET6_ADDRSTRLEN], *subj; + struct hostportres *hp; debug(DBG_WARN, "dtlsservernew: incoming DTLS connection from %s", addr2string((struct sockaddr *)¶ms->addr, tmp, sizeof(tmp))); - conf = find_clconf(handle, (struct sockaddr *)¶ms->addr, NULL); + conf = find_clconf(handle, (struct sockaddr *)¶ms->addr, NULL, &hp); if (!conf) goto exit; @@ -343,7 +344,7 @@ void *dtlsservernew(void *arg) { accepted_tls = conf->tlsconf; while (conf) { - if (accepted_tls == conf->tlsconf && verifyconfcert(cert, conf)) { + if (accepted_tls == conf->tlsconf && verifyconfcert(cert, conf, NULL)) { subj = getcertsubject(cert); if(subj) { debug(DBG_WARN, "dtlsservernew: DTLS connection from %s, client %s, subject %s up", @@ -363,9 +364,10 @@ void *dtlsservernew(void *arg) { } goto exit; } - conf = find_clconf(handle, (struct sockaddr *)¶ms->addr, &cur); + conf = find_clconf(handle, (struct sockaddr *)¶ms->addr, &cur, &hp); } - debug(DBG_WARN, "dtlsservernew: ignoring request, no matching TLS client"); + debug(DBG_WARN, "dtlsservernew: ignoring request, no matching TLS client for %s", + addr2string((struct sockaddr *)¶ms->addr, tmp, sizeof(tmp))); if (cert) X509_free(cert); @@ -468,7 +470,7 @@ void *dtlslistener(void *arg) { continue; } - conf = find_clconf(handle, (struct sockaddr *)&from, NULL); + conf = find_clconf(handle, (struct sockaddr *)&from, NULL, NULL); if (!conf) { debug(DBG_INFO, "dtlslistener: got UDP from unknown peer %s, ignoring", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp))); if (recv(s, buf, 4, 0) == -1) @@ -607,7 +609,7 @@ int dtlsconnect(struct server *server, int timeout, char *text) { cert = verifytlscert(server->ssl); if (!cert) continue; - if (verifyconfcert(cert, server->conf)) { + if (verifyconfcert(cert, server->conf, hp)) { subj = getcertsubject(cert); if(subj) { debug(DBG_WARN, "dtlsconnect: DTLS connection to %s, subject %s up", server->conf->name, subj); diff --git a/hostport.c b/hostport.c index 1faf2e4..d0651d4 100644 --- a/hostport.c +++ b/hostport.c @@ -258,7 +258,7 @@ static int prefixmatch(void *a1, void *a2, uint8_t len) { return (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]); } -int _internal_addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t prefixlen, uint8_t checkport) { +int _internal_addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t prefixlen, uint8_t checkport, struct hostportres **hpreturn) { struct sockaddr_in6 *sa6 = NULL; struct in_addr *a4 = NULL; struct addrinfo *res; @@ -287,16 +287,20 @@ int _internal_addressmatches(struct list *hostports, struct sockaddr *addr, uint !memcmp(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16) && (!checkport || ((struct sockaddr_in6 *)res->ai_addr)->sin6_port == - ((struct sockaddr_in6 *)addr)->sin6_port))) + ((struct sockaddr_in6 *)addr)->sin6_port))) { + if (hpreturn) *hpreturn = hp; return 1; + } } else if (hp->prefixlen <= prefixlen) { if ((a4 && res->ai_family == AF_INET && prefixmatch(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, hp->prefixlen)) || (sa6 && res->ai_family == AF_INET6 && - prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, hp->prefixlen))) + prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, hp->prefixlen))) { + if (hpreturn) *hpreturn = hp; return 1; + } } } } @@ -312,18 +316,18 @@ int hostportmatches(struct list *hostports, struct list *matchhostports, uint8_t match = (struct hostportres *)entry->data; for (res = match->addrinfo; res; res = res->ai_next) { - if (_internal_addressmatches(hostports, res->ai_addr, match->prefixlen, checkport)) + if (_internal_addressmatches(hostports, res->ai_addr, match->prefixlen, checkport, NULL)) return 1; } } return 0; } -int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport) { - return _internal_addressmatches(hostports, addr, 255, checkport); +int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport, struct hostportres **hp) { + return _internal_addressmatches(hostports, addr, 255, checkport, hp); } -int connecttcphostlist(struct list *hostports, struct addrinfo *src) { +int connecttcphostlist(struct list *hostports, struct addrinfo *src, struct hostportres** hpreturn) { int s; struct list_node *entry; struct hostportres *hp = NULL; @@ -333,6 +337,7 @@ int connecttcphostlist(struct list *hostports, struct addrinfo *src) { debug(DBG_WARN, "connecttcphostlist: trying to open TCP connection to %s port %s", hp->host, hp->port); if ((s = connecttcp(hp->addrinfo, src, list_count(hostports) > 1 ? 5 : 30)) >= 0) { debug(DBG_WARN, "connecttcphostlist: TCP connection to %s port %s up", hp->host, hp->port); + if (hpreturn) *hpreturn = hp; return s; } } diff --git a/hostport.h b/hostport.h index 9069ecd..a554a77 100644 --- a/hostport.h +++ b/hostport.h @@ -2,6 +2,9 @@ * Copyright (c) 2012, NORDUnet A/S */ /* See LICENSE for licensing information. */ +#ifndef _HOSTPORT_H +#define _HOSTPORT_H + struct hostportres { char *host; char *port; @@ -17,9 +20,10 @@ int resolvehostport(struct hostportres *hp, int af, int socktype, uint8_t passiv int resolvehostports(struct list *hostports, int af, int socktype); struct addrinfo *resolvepassiveaddrinfo(char **hostport, int af, char *default_port, int socktype); int hostportmatches(struct list *hostports, struct list *matchhostports, uint8_t checkport); -int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport); -int connecttcphostlist(struct list *hostports, struct addrinfo *src); +int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport, struct hostportres **hp); +int connecttcphostlist(struct list *hostports, struct addrinfo *src, struct hostportres **hpreturn); +#endif /* _HOSTPORT_H */ /* Local Variables: */ /* c-file-style: "stroustrup" */ /* End: */ diff --git a/radsecproxy.c b/radsecproxy.c index d98695d..e7a9bb3 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -121,13 +121,13 @@ int prefixmatch(void *a1, void *a2, uint8_t len) { } /* returns next config with matching address, or NULL */ -struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *confs, struct list_node **cur, uint8_t server_p) { +struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *confs, struct list_node **cur, uint8_t server_p, struct hostportres **hp) { struct list_node *entry; struct clsrvconf *conf; for (entry = (cur && *cur ? list_next(*cur) : list_first(confs)); entry; entry = list_next(entry)) { conf = (struct clsrvconf *)entry->data; - if (conf->type == type && addressmatches(conf->hostports, addr, server_p)) { + if (conf->type == type && addressmatches(conf->hostports, addr, server_p, hp)) { if (cur) *cur = entry; return conf; @@ -136,12 +136,12 @@ struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *co return NULL; } -struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) { - return find_conf(type, addr, clconfs, cur, 0); +struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur, struct hostportres **hp) { + return find_conf(type, addr, clconfs, cur, 0, hp); } struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) { - return find_conf(type, addr, srvconfs, cur, 1); + return find_conf(type, addr, srvconfs, cur, 1, NULL); } /* returns next config of given type, or NULL */ diff --git a/radsecproxy.h b/radsecproxy.h index cf493b4..84c57fd 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -11,6 +11,7 @@ #include "radmsg.h" #include "gconfig.h" #include "rewrite.h" +#include "hostport.h" #include @@ -250,7 +251,7 @@ struct protodefs { #define RADLEN(x) ntohs(((uint16_t *)(x))[1]) -struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur); +struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur, struct hostportres **hp); struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur); struct clsrvconf *find_clconf_type(uint8_t type, struct list_node **cur); struct client *addclient(struct clsrvconf *conf, uint8_t lock); diff --git a/tcp.c b/tcp.c index ffb2f4c..5336435 100644 --- a/tcp.c +++ b/tcp.c @@ -120,7 +120,7 @@ int tcpconnect(struct server *server, int timeout, char *text) { pthread_mutex_lock(&server->lock); debug(DBG_INFO, "tcpconnect: connecting to %s", server->conf->name); - if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres)) < 0) + if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres, NULL)) < 0) continue; if (server->conf->keepalive) enable_keepalive(server->sock); @@ -339,7 +339,7 @@ void *tcpservernew(void *arg) { } debug(DBG_WARN, "tcpservernew: incoming TCP connection from %s", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp))); - conf = find_clconf(handle, (struct sockaddr *)&from, NULL); + conf = find_clconf(handle, (struct sockaddr *)&from, NULL, NULL); if (conf) { client = addclient(conf, 1); if (client) { diff --git a/tests/t_verify_cert.c b/tests/t_verify_cert.c index ca0d47e..b52a990 100644 --- a/tests/t_verify_cert.c +++ b/tests/t_verify_cert.c @@ -234,7 +234,7 @@ vY/uPjA=\n\ hp.prefixlen = 255; list_push(conf.hostports, &hp); - ok(1, verifyconfcert(certsimple, &conf), "check disabled"); + ok(1, verifyconfcert(certsimple, &conf, &hp), "check disabled"); while(list_shift(conf.hostports)); } @@ -249,7 +249,7 @@ vY/uPjA=\n\ hp.prefixlen = 0; list_push(conf.hostports, &hp); - ok(1,verifyconfcert(certsimple, &conf),"cidr prefix"); + ok(1,verifyconfcert(certsimple, &conf, &hp),"cidr prefix"); while(list_shift(conf.hostports)); } @@ -264,11 +264,11 @@ vY/uPjA=\n\ hp.prefixlen = 255; list_push(conf.hostports, &hp); - ok(1,verifyconfcert(certsimple, &conf), "simple cert cn"); - ok(0,verifyconfcert(certsimpleother, &conf), "negative simple cert cn"); + ok(1,verifyconfcert(certsimple, &conf, &hp), "simple cert cn"); + ok(0,verifyconfcert(certsimpleother, &conf, &hp), "negative simple cert cn"); /* as per RFC 6125 6.4.4: CN MUST NOT be matched if SAN is present */ - ok(0,verifyconfcert(certsandns, &conf), "simple cert cn vs san dns, RFC6125"); + ok(0,verifyconfcert(certsandns, &conf, &hp), "simple cert cn vs san dns, RFC6125"); while(list_shift(conf.hostports)); } @@ -284,11 +284,11 @@ vY/uPjA=\n\ hp.prefixlen = 255; list_push(conf.hostports, &hp); - ok(1,verifyconfcert(certsanip, &conf),"san ip"); - ok(0,verifyconfcert(certsanipother, &conf),"wrong san ip"); - ok(0,verifyconfcert(certsimple, &conf), "negative san ip"); - ok(1,verifyconfcert(certsanipindns, &conf),"san ip in dns"); - ok(1,verifyconfcert(certcomplex,&conf),"san ip in complex cert"); + ok(1,verifyconfcert(certsanip, &conf, &hp),"san ip"); + ok(0,verifyconfcert(certsanipother, &conf, &hp),"wrong san ip"); + ok(0,verifyconfcert(certsimple, &conf, &hp), "negative san ip"); + ok(1,verifyconfcert(certsanipindns, &conf, &hp),"san ip in dns"); + ok(1,verifyconfcert(certcomplex,&conf, &hp),"san ip in complex cert"); freeaddrinfo(hp.addrinfo); while(list_shift(conf.hostports)); @@ -306,11 +306,11 @@ vY/uPjA=\n\ hp.prefixlen = 255; list_push(conf.hostports, &hp); - ok(1,verifyconfcert(certsanipv6, &conf),"san ipv6"); - ok(0,verifyconfcert(certsanipother, &conf),"wrong san ipv6"); - ok(0,verifyconfcert(certsimple, &conf),"negative san ipv6"); - ok(1,verifyconfcert(certsanipv6indns, &conf),"san ipv6 in dns"); - ok(1,verifyconfcert(certcomplex,&conf),"san ipv6 in complex cert"); + ok(1,verifyconfcert(certsanipv6, &conf, &hp),"san ipv6"); + ok(0,verifyconfcert(certsanipother, &conf, &hp),"wrong san ipv6"); + ok(0,verifyconfcert(certsimple, &conf, &hp),"negative san ipv6"); + ok(1,verifyconfcert(certsanipv6indns, &conf, &hp),"san ipv6 in dns"); + ok(1,verifyconfcert(certcomplex,&conf, &hp),"san ipv6 in complex cert"); freeaddrinfo(hp.addrinfo); while(list_shift(conf.hostports)); @@ -326,10 +326,10 @@ vY/uPjA=\n\ hp.prefixlen = 255; list_push(conf.hostports, &hp); - ok(1,verifyconfcert(certsandns, &conf),"san dns"); - ok(0,verifyconfcert(certsandnsother, &conf),"negative san dns"); - ok(1,verifyconfcert(certcomplex,&conf),"san dns in complex cert"); - ok(0,verifyconfcert(certsimple, &conf),"missing san dns"); + ok(1,verifyconfcert(certsandns, &conf, &hp),"san dns"); + ok(0,verifyconfcert(certsandnsother, &conf, &hp),"negative san dns"); + ok(1,verifyconfcert(certcomplex,&conf, &hp),"san dns in complex cert"); + ok(0,verifyconfcert(certsimple, &conf, &hp),"missing san dns"); while(list_shift(conf.hostports)); } @@ -347,8 +347,8 @@ vY/uPjA=\n\ hp2.prefixlen = 255; list_push(conf.hostports, &hp2); - ok(1,verifyconfcert(certsimple, &conf),"multi hostport cn"); - ok(0,verifyconfcert(certsimpleother, &conf),"negative multi hostport cn"); + ok(1,verifyconfcert(certsimple, &conf, NULL),"multi hostport cn"); + ok(0,verifyconfcert(certsimpleother, &conf, NULL),"negative multi hostport cn"); while(list_shift(conf.hostports)); } @@ -366,9 +366,14 @@ vY/uPjA=\n\ hp2.prefixlen = 255; list_push(conf.hostports, &hp2); - ok(1,verifyconfcert(certsandns, &conf),"multi hostport san dns"); - ok(0,verifyconfcert(certsandnsother, &conf),"negative multi hostport san dns"); - ok(1,verifyconfcert(certcomplex,&conf),"multi hostport san dns in complex cert"); + ok(1,verifyconfcert(certsandns, &conf, NULL),"multi hostport san dns"); + ok(0,verifyconfcert(certsandnsother, &conf, NULL),"negative multi hostport san dns"); + ok(1,verifyconfcert(certcomplex,&conf, NULL),"multi hostport san dns in complex cert"); + + ok(0,verifyconfcert(certsandns, &conf, &hp1),"multi hostport explicit wrong cert"); + ok(1,verifyconfcert(certsandns, &conf, &hp2),"multi hostport explicit matching cert"); + ok(0,verifyconfcert(certcomplex, &conf, &hp1),"multi hostport explicit wrong complex cert"); + ok(1,verifyconfcert(certcomplex, &conf, &hp2),"multi hostport explicit matching complex cert"); while(list_shift(conf.hostports)); } @@ -380,9 +385,9 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "CN:/t..t/"),"explicit cn regex config"); - ok(1,verifyconfcert(certsimple, &conf),"explicit cn regex"); - ok(0,verifyconfcert(certsimpleother, &conf),"negative explicit cn regex"); - ok(1,verifyconfcert(certsandns, &conf), "explicit cn regex with SAN DNS"); + ok(1,verifyconfcert(certsimple, &conf, NULL),"explicit cn regex"); + ok(0,verifyconfcert(certsimpleother, &conf, NULL),"negative explicit cn regex"); + ok(1,verifyconfcert(certsandns, &conf, NULL), "explicit cn regex with SAN DNS"); freematchcertattr(&conf); } @@ -394,10 +399,10 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "SubjectAltName:IP:192.0.2.1"),"explicit san ip config"); - ok(1,verifyconfcert(certsanip, &conf),"explicit san ip"); - ok(0,verifyconfcert(certsanipother, &conf),"wrong explicit san ip"); - ok(0,verifyconfcert(certsimple, &conf), "missing explicit san ip"); - ok(1,verifyconfcert(certcomplex,&conf),"explicit san ip in complex cert"); + ok(1,verifyconfcert(certsanip, &conf, NULL),"explicit san ip"); + ok(0,verifyconfcert(certsanipother, &conf, NULL),"wrong explicit san ip"); + ok(0,verifyconfcert(certsimple, &conf, NULL), "missing explicit san ip"); + ok(1,verifyconfcert(certcomplex,&conf, NULL),"explicit san ip in complex cert"); freematchcertattr(&conf); } @@ -409,10 +414,10 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "SubjectAltName:IP:2001:db8::1"),"explicit san ipv6 config"); - ok(1,verifyconfcert(certsanipv6, &conf),"explicit san ipv6"); - ok(0,verifyconfcert(certsanipother, &conf),"wrong explicit san ipv6"); - ok(0,verifyconfcert(certsimple, &conf),"missing explicitsan ipv6"); - ok(1,verifyconfcert(certcomplex,&conf),"explicit san ipv6 in complex cert"); + ok(1,verifyconfcert(certsanipv6, &conf, NULL),"explicit san ipv6"); + ok(0,verifyconfcert(certsanipother, &conf, NULL),"wrong explicit san ipv6"); + ok(0,verifyconfcert(certsimple, &conf, NULL),"missing explicitsan ipv6"); + ok(1,verifyconfcert(certcomplex,&conf, NULL),"explicit san ipv6 in complex cert"); freematchcertattr(&conf); } @@ -424,10 +429,10 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "SubjectAltName:DNS:/t..t\\.local/"),"explicit san dns regex config"); - ok(1,verifyconfcert(certsandns, &conf),"explicit san dns"); - ok(0,verifyconfcert(certsandnsother, &conf),"negative explicit san dns"); - ok(0,verifyconfcert(certsimple,&conf),"missing explicit san dns"); - ok(1,verifyconfcert(certcomplex,&conf),"explicit san dns in complex cert"); + ok(1,verifyconfcert(certsandns, &conf, NULL),"explicit san dns"); + ok(0,verifyconfcert(certsandnsother, &conf, NULL),"negative explicit san dns"); + ok(0,verifyconfcert(certsimple,&conf, NULL),"missing explicit san dns"); + ok(1,verifyconfcert(certcomplex,&conf, NULL),"explicit san dns in complex cert"); freematchcertattr(&conf); } @@ -439,9 +444,9 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "SubjectAltName:URI:/https:\\/\\/test.local\\/profile#me/"),"explicit cn regex config"); - ok(1,verifyconfcert(certsanuri, &conf),"explicit san uri regex"); - ok(0,verifyconfcert(certsanuriother, &conf),"negative explicit san uri"); - ok(0,verifyconfcert(certsimple, &conf), "missing explicit san uri"); + ok(1,verifyconfcert(certsanuri, &conf, NULL),"explicit san uri regex"); + ok(0,verifyconfcert(certsanuriother, &conf, NULL),"negative explicit san uri"); + ok(0,verifyconfcert(certsimple, &conf, NULL), "missing explicit san uri"); freematchcertattr(&conf); } @@ -453,9 +458,9 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "SubjectAltName:rID:1.2.3.4"),"explicit san rid config"); - ok(1,verifyconfcert(certsanrid, &conf),"explicit san rid"); - ok(0,verifyconfcert(certsanridother, &conf),"negative explicit san rid"); - ok(0,verifyconfcert(certsimple, &conf), "missing explicit san rid"); + ok(1,verifyconfcert(certsanrid, &conf, NULL),"explicit san rid"); + ok(0,verifyconfcert(certsanridother, &conf, NULL),"negative explicit san rid"); + ok(0,verifyconfcert(certsimple, &conf, NULL), "missing explicit san rid"); freematchcertattr(&conf); } @@ -467,9 +472,9 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "SubjectAltName:otherName:1.3.6.1.5.5.7.8.8:/test.local/"),"explicit san otherName config"); - ok(1,verifyconfcert(certsanothername, &conf),"explicit san otherName"); - ok(0,verifyconfcert(certsanothernameother, &conf),"negative explicit san otherName"); - ok(0,verifyconfcert(certsimple, &conf), "missing explicit san otherName"); + ok(1,verifyconfcert(certsanothername, &conf, NULL),"explicit san otherName"); + ok(0,verifyconfcert(certsanothernameother, &conf, NULL),"negative explicit san otherName"); + ok(0,verifyconfcert(certsimple, &conf, NULL), "missing explicit san otherName"); freematchcertattr(&conf); } @@ -480,7 +485,7 @@ vY/uPjA=\n\ conf.certnamecheck = 0; ok(1,addmatchcertattr(&conf, "CN:/t..t"),"test regex config syntax"); - ok(1,verifyconfcert(certsimple, &conf),"test regex config syntax execution"); + ok(1,verifyconfcert(certsimple, &conf, NULL),"test regex config syntax execution"); freematchcertattr(&conf); } @@ -518,10 +523,10 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "CN:/t..t"),"combined config"); - ok(1,verifyconfcert(certsandns, &conf),"combined san dns"); - ok(0,verifyconfcert(certsandnsother, &conf),"negative combined san dns"); - ok(1,verifyconfcert(certcomplex,&conf),"combined san dns in complex cert"); - ok(0,verifyconfcert(certsimple, &conf),"combined missing san dns"); + ok(1,verifyconfcert(certsandns, &conf, &hp),"combined san dns"); + ok(0,verifyconfcert(certsandnsother, &conf, &hp),"negative combined san dns"); + ok(1,verifyconfcert(certcomplex,&conf, &hp),"combined san dns in complex cert"); + ok(0,verifyconfcert(certsimple, &conf, &hp),"combined missing san dns"); while(list_shift(conf.hostports)); freematchcertattr(&conf); @@ -540,12 +545,12 @@ vY/uPjA=\n\ ok(1,addmatchcertattr(&conf, "SubjectAltName:DNS:/test\\.local/"),"multiple check 1"); ok(1,addmatchcertattr(&conf, "SubjectAltName:rID:1.2.3.4"),"multiple check 2"); - ok(0,verifyconfcert(certsandns, &conf),"multiple missing rID"); - ok(0,verifyconfcert(certsanrid, &conf), "multiple missing DNS"); - ok(1,verifyconfcert(certmulti, &conf),"multiple SANs"); - ok(0,verifyconfcert(certmultiother, &conf),"multiple negative match"); - ok(0,verifyconfcert(certcomplex, &conf),"multiple missing rID in complex cert"); - ok(0,verifyconfcert(certsimple, &conf),"multiple missing everything"); + ok(0,verifyconfcert(certsandns, &conf, &hp),"multiple missing rID"); + ok(0,verifyconfcert(certsanrid, &conf, &hp), "multiple missing DNS"); + ok(1,verifyconfcert(certmulti, &conf, &hp),"multiple SANs"); + ok(0,verifyconfcert(certmultiother, &conf, &hp),"multiple negative match"); + ok(0,verifyconfcert(certcomplex, &conf, &hp),"multiple missing rID in complex cert"); + ok(0,verifyconfcert(certsimple, &conf, &hp),"multiple missing everything"); while(list_shift(conf.hostports)); freematchcertattr(&conf); diff --git a/tls.c b/tls.c index 8786749..76a97bd 100644 --- a/tls.c +++ b/tls.c @@ -92,6 +92,7 @@ int tlsconnect(struct server *server, int timeout, char *text) { int origflags; struct addrinfo *source = NULL; char *subj; + struct hostportres *hpconnected = NULL; debug(DBG_DBG, "tlsconnect: called from %s", text); pthread_mutex_lock(&server->lock); @@ -136,7 +137,7 @@ int tlsconnect(struct server *server, int timeout, char *text) { } debug(DBG_INFO, "tlsconnect: connecting to %s", server->conf->name); - if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres)) < 0) + if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres, &hpconnected)) < 0) continue; if (server->conf->keepalive) enable_keepalive(server->sock); @@ -163,7 +164,7 @@ int tlsconnect(struct server *server, int timeout, char *text) { cert = verifytlscert(server->ssl); if (!cert) continue; - if (verifyconfcert(cert, server->conf)) { + if (verifyconfcert(cert, server->conf, hpconnected)) { subj = getcertsubject(cert); if(subj) { debug(DBG_WARN, "tlsconnect: TLS connection to %s, subject %s up", server->conf->name, subj); @@ -506,6 +507,7 @@ void *tlsservernew(void *arg) { struct client *client; struct tls *accepted_tls = NULL; char tmp[INET6_ADDRSTRLEN], *subj; + struct hostportres *hp; s = *(int *)arg; free(arg); @@ -515,7 +517,7 @@ void *tlsservernew(void *arg) { } debug(DBG_WARN, "tlsservernew: incoming TLS connection from %s", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp))); - conf = find_clconf(handle, (struct sockaddr *)&from, &cur); + conf = find_clconf(handle, (struct sockaddr *)&from, &cur, &hp); if (conf) { pthread_mutex_lock(&conf->tlsconf->lock); ctx = tlsgetctx(handle, conf->tlsconf); @@ -550,7 +552,7 @@ void *tlsservernew(void *arg) { } while (conf) { - if (accepted_tls == conf->tlsconf && verifyconfcert(cert, conf)) { + if (accepted_tls == conf->tlsconf && verifyconfcert(cert, conf, NULL)) { subj = getcertsubject(cert); if(subj) { debug(DBG_WARN, "tlsservernew: TLS connection from %s, client %s, subject %s up", @@ -570,9 +572,10 @@ void *tlsservernew(void *arg) { debug(DBG_WARN, "tlsservernew: failed to create new client instance"); goto exit; } - conf = find_clconf(handle, (struct sockaddr *)&from, &cur); + conf = find_clconf(handle, (struct sockaddr *)&from, &cur, &hp); } - debug(DBG_WARN, "tlsservernew: ignoring request, no matching TLS client"); + debug(DBG_WARN, "tlsservernew: ignoring request, no matching TLS client for %s", + addr2string((struct sockaddr *)&from, tmp, sizeof(tmp))); if (cert) X509_free(cert); diff --git a/tlscommon.c b/tlscommon.c index 73980b9..d541bb1 100644 --- a/tlscommon.c +++ b/tlscommon.c @@ -711,64 +711,67 @@ static int matchsubjaltname(X509 *cert, struct certattrmatch* match) { } if (r<1) - debug(DBG_WARN, "matchsubjaltname: no matching Subject Alt Name found! (%s)", fail); + debug(DBG_DBG, "matchsubjaltname: no matching Subject Alt Name found! (%s)", fail); free(fail); GENERAL_NAMES_free(alt); return r; } -int certnamecheck(X509 *cert, struct list *hostports) { - struct list_node *entry; - struct hostportres *hp; +int certnamecheck(X509 *cert, struct hostportres *hp) { int r = 0; struct certattrmatch match; memset(&match, 0, sizeof(struct certattrmatch)); - for (entry = list_first(hostports); entry; entry = list_next(entry)) { - r = 0; - hp = (struct hostportres *)entry->data; - if (hp->prefixlen != 255) { - /* we disable the check for prefixes */ + r = 0; + if (hp->prefixlen != 255) { + /* we disable the check for prefixes */ + return 1; + } + if (inet_pton(AF_INET, hp->host, &match.ipaddr)) + match.af = AF_INET; + else if (inet_pton(AF_INET6, hp->host, &match.ipaddr)) + match.af = AF_INET6; + else + match.af = 0; + match.exact = hp->host; + + if (match.af) { + match.matchfn = &certattr_matchip; + match.type = GEN_IPADD; + r = matchsubjaltname(cert, &match); + } + if (!r) { + match.matchfn = &certattr_matchregex; + match.type = GEN_DNS; + r = matchsubjaltname(cert, &match); + } + if (r) { + if (r > 0) { + debug(DBG_DBG, "certnamecheck: Found subjectaltname matching %s %s", match.af ? "address" : "host", hp->host); return 1; } - if (inet_pton(AF_INET, hp->host, &match.ipaddr)) - match.af = AF_INET; - else if (inet_pton(AF_INET6, hp->host, &match.ipaddr)) - match.af = AF_INET6; - else - match.af = 0; - match.exact = hp->host; - - if (match.af) { - match.matchfn = &certattr_matchip; - match.type = GEN_IPADD; - r = matchsubjaltname(cert, &match); - } - if (!r) { - match.matchfn = &certattr_matchregex; - match.type = GEN_DNS; - r = matchsubjaltname(cert, &match); - } - if (r) { - if (r > 0) { - debug(DBG_DBG, "certnamecheck: Found subjectaltname matching %s %s", match.af ? "address" : "host", hp->host); - return 1; - } - debug(DBG_WARN, "certnamecheck: No subjectaltname matching %s %s", match.af ? "address" : "host", hp->host); - } else { - if (certattr_matchcn(cert, &match)) { - debug(DBG_DBG, "certnamecheck: Found cn matching host %s", hp->host); - return 1; - } - debug(DBG_WARN, "certnamecheck: cn not matching host %s", hp->host); + debug(DBG_WARN, "certnamecheck: No subjectaltname matching %s %s", match.af ? "address" : "host", hp->host); + } else { /* as per RFC 6125 6.4.4: CN MUST NOT be matched if SAN is present */ + if (certattr_matchcn(cert, &match)) { + debug(DBG_DBG, "certnamecheck: Found cn matching host %s", hp->host); + return 1; } + debug(DBG_WARN, "certnamecheck: cn not matching host %s", hp->host); + } + return 0; +} + +int certnamecheckany(X509 *cert, struct list *hostports) { + struct list_node *entry; + for (entry = list_first(hostports); entry; entry = list_next(entry)) { + if (certnamecheck(cert, (struct hostportres *)entry->data)) return 1; } return 0; } -int verifyconfcert(X509 *cert, struct clsrvconf *conf) { +int verifyconfcert(X509 *cert, struct clsrvconf *conf, struct hostportres *hpconnected) { char *subject; int ok = 1; struct list_node *entry; @@ -777,9 +780,16 @@ int verifyconfcert(X509 *cert, struct clsrvconf *conf) { debug(DBG_DBG, "verifyconfcert: verify certificate for host %s, subject %s", conf->name, subject); if (conf->certnamecheck) { debug(DBG_DBG, "verifyconfcert: verify hostname"); - if (!certnamecheck(cert, conf->hostports)) { - debug(DBG_DBG, "verifyconfcert: certificate name check failed for host %s", conf->name); - ok = 0; + if (hpconnected) { + if (!certnamecheck(cert, hpconnected)) { + debug(DBG_WARN, "verifyconfcert: certificate name check failed for host %s (%s)", conf->name, hpconnected->host); + ok = 0; + } + } else { + if (!certnamecheckany(cert, conf->hostports)) { + debug(DBG_DBG, "verifyconfcert: no matching CN or SAN found for host %s", conf->name); + ok = 0; + } } } diff --git a/tlscommon.h b/tlscommon.h index 6be9079..30cf265 100644 --- a/tlscommon.h +++ b/tlscommon.h @@ -3,6 +3,7 @@ /* See LICENSE for licensing information. */ #include +#include "hostport.h" #if OPENSSL_VERSION_NUMBER < 0x10100000L #define ASN1_STRING_get0_data(o) ((o)->data) @@ -40,7 +41,7 @@ void sslinit(); struct tls *tlsgettls(char *alt1, char *alt2); SSL_CTX *tlsgetctx(uint8_t type, struct tls *t); X509 *verifytlscert(SSL *ssl); -int verifyconfcert(X509 *cert, struct clsrvconf *conf); +int verifyconfcert(X509 *cert, struct clsrvconf *conf, struct hostportres *); char *getcertsubject(X509 *cert); int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val); int addmatchcertattr(struct clsrvconf *conf, const char *match); diff --git a/udp.c b/udp.c index e3e1464..6e86fbe 100644 --- a/udp.c +++ b/udp.c @@ -160,7 +160,7 @@ unsigned char *radudpget(int s, struct client **client, struct server **server) } p = client - ? find_clconf(handle, (struct sockaddr *)&from, NULL) + ? find_clconf(handle, (struct sockaddr *)&from, NULL, NULL) : find_srvconf(handle, (struct sockaddr *)&from, NULL); if (!p) { debug(DBG_WARN, "radudpget: got packet from wrong or unknown UDP peer %s, ignoring", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp)));