Commit 5d05ee2d authored by venaas's avatar venaas Committed by venaas
Browse files

added subjectaltname cert checks, incl regexp uri

git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@155 e88ac4ed-0b26-0410-9574-a7f39faa03bf
parent 9c528aa6
......@@ -35,6 +35,8 @@
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <regex.h>
#include <libgen.h>
#include <pthread.h>
......@@ -43,6 +45,7 @@
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/hmac.h>
#include <openssl/x509v3.h>
#include "debug.h"
#include "list.h"
#include "radsecproxy.h"
......@@ -127,16 +130,6 @@ static int verify_cb(int ok, X509_STORE_CTX *ctx) {
return ok;
}
#ifdef DEBUG
void printauth(char *s, unsigned char *t) {
int i;
printf("%s:", s);
for (i = 0; i < 16; i++)
printf("%02x ", t[i]);
printf("\n");
}
#endif
int resolvepeer(struct clsrvconf *conf, int ai_flags) {
struct addrinfo hints, *addrinfo;
......@@ -360,14 +353,106 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,
return rad;
}
int subjectaltnameaddr(X509 *cert, int family, struct in6_addr *addr) {
int loc, i, l, n, r = 0;
char *v;
X509_EXTENSION *ex;
STACK_OF(GENERAL_NAME) *alt;
GENERAL_NAME *gn;
debug(DBG_DBG, "subjectaltnameaddr");
loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
if (loc < 0)
return r;
ex = X509_get_ext(cert, loc);
alt = X509V3_EXT_d2i(ex);
if (!alt)
return r;
n = sk_GENERAL_NAME_num(alt);
for (i = 0; i < n; i++) {
gn = sk_GENERAL_NAME_value(alt, i);
if (gn->type != GEN_IPADD)
continue;
r = -1;
v = (char *)ASN1_STRING_data(gn->d.ia5);
l = ASN1_STRING_length(gn->d.ia5);
if (((family == AF_INET && l == sizeof(struct in_addr)) || (family == AF_INET6 && l == sizeof(struct in6_addr)))
&& !memcmp(v, &addr, l)) {
r = 1;
break;
}
}
GENERAL_NAMES_free(alt);
return r;
}
int subjectaltnameregexp(X509 *cert, int type, char *exact, regex_t *regex) {
int loc, i, l, n, r = 0;
char *s, *v;
X509_EXTENSION *ex;
STACK_OF(GENERAL_NAME) *alt;
GENERAL_NAME *gn;
debug(DBG_DBG, "subjectaltnameregexp");
loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
if (loc < 0)
return r;
ex = X509_get_ext(cert, loc);
alt = X509V3_EXT_d2i(ex);
if (!alt)
return r;
n = sk_GENERAL_NAME_num(alt);
for (i = 0; i < n; i++) {
gn = sk_GENERAL_NAME_value(alt, i);
if (gn->type != type)
continue;
r = -1;
v = (char *)ASN1_STRING_data(gn->d.ia5);
l = ASN1_STRING_length(gn->d.ia5);
if (l <= 0)
continue;
#ifdef DEBUG
printfchars(NULL, gn->type == GEN_DNS ? "dns" : "uri", NULL, v, l);
#endif
if (exact) {
if (memcmp(v, exact, l))
continue;
} else {
s = stringcopy((char *)v, l);
if (!s) {
debug(DBG_ERR, "malloc failed");
continue;
}
if (regexec(regex, s, 0, NULL, 0)) {
free(s);
continue;
}
free(s);
}
r = 1;
break;
}
GENERAL_NAMES_free(alt);
return r;
}
int tlsverifycert(SSL *ssl, struct clsrvconf *conf) {
int l, loc;
int l, loc, r;
X509 *cert;
X509_NAME *nm;
X509_NAME_ENTRY *e;
unsigned char *v;
ASN1_STRING *s;
char *v;
uint8_t type = 0; /* 0 for DNS, AF_INET for IPv4, AF_INET6 for IPv6 */
unsigned long error;
struct in6_addr addr;
if (SSL_get_verify_result(ssl) != X509_V_OK) {
debug(DBG_ERR, "tlsverifycert: basic validation failed");
while ((error = ERR_get_error()))
......@@ -379,34 +464,60 @@ int tlsverifycert(SSL *ssl, struct clsrvconf *conf) {
if (!cert) {
debug(DBG_ERR, "tlsverifycert: failed to obtain certificate");
return 0;
}
nm = X509_get_subject_name(cert);
loc = -1;
for (;;) {
loc = X509_NAME_get_index_by_NID(nm, NID_commonName, loc);
if (loc == -1)
break;
e = X509_NAME_get_entry(nm, loc);
l = ASN1_STRING_to_UTF8(&v, X509_NAME_ENTRY_get_data(e));
if (l < 0)
continue;
}
if (inet_pton(AF_INET, conf->host, &addr))
type = AF_INET;
else if (inet_pton(AF_INET6, conf->host, &addr))
type = AF_INET6;
r = type ? subjectaltnameaddr(cert, type, &addr) : subjectaltnameregexp(cert, GEN_DNS, conf->host, NULL);
if (r) {
if (r < 0) {
X509_free(cert);
debug(DBG_DBG, "tlsverifycert: No subjectaltname matching %s %s", type ? "address" : "host", conf->host);
return 0;
}
debug(DBG_DBG, "tlsverifycert: Found subjectaltname matching %s %s", type ? "address" : "host", conf->host);
} else {
nm = X509_get_subject_name(cert);
loc = -1;
for (;;) {
loc = X509_NAME_get_index_by_NID(nm, NID_commonName, loc);
if (loc == -1)
break;
e = X509_NAME_get_entry(nm, loc);
s = X509_NAME_ENTRY_get_data(e);
v = (char *) ASN1_STRING_data(s);
l = ASN1_STRING_length(s);
if (l < 0)
continue;
#ifdef DEBUG
{
int i;
printf("cn: ");
for (i = 0; i < l; i++)
printf("%c", v[i]);
printf("\n");
printfchars(NULL, "cn", NULL, v, l);
#endif
if (l == strlen(conf->host) && !strncasecmp(conf->host, v, l)) {
r = 1;
debug(DBG_DBG, "tlsverifycert: Found cn matching host %s", conf->host);
break;
}
}
#endif
if (l == strlen(conf->host) && !strncasecmp(conf->host, (char *)v, l)) {
debug(DBG_DBG, "tlsverifycert: Found cn matching host %s, All OK", conf->host);
return 1;
if (!r) {
X509_free(cert);
debug(DBG_ERR, "tlsverifycert: cn not matching host %s", conf->host);
return 0;
}
}
if (conf->certuriregex) {
r = subjectaltnameregexp(cert, GEN_URI, NULL, conf->certuriregex);
if (r < 1) {
debug(DBG_DBG, "tlsverifycert: subjectaltname URI not matching regex");
X509_free(cert);
return 0;
}
debug(DBG_ERR, "tlsverifycert: cn not matching host %s", conf->host);
debug(DBG_DBG, "tlsverifycert: subjectaltname URI matching regex");
}
X509_free(cert);
return 0;
return 1;
}
void tlsconnect(struct server *server, struct timeval *when, char *text) {
......@@ -832,21 +943,10 @@ int msmppencrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
first = 0;
}
#if 0
printf("msppencrypt auth in: ");
for (i = 0; i < 16; i++)
printf("%02x ", auth[i]);
printf("\n");
printf("msppencrypt salt in: ");
for (i = 0; i < 2; i++)
printf("%02x ", salt[i]);
printf("\n");
printf("msppencrypt in: ");
for (i = 0; i < len; i++)
printf("%02x ", text[i]);
printf("\n");
#if 0
printfchars(NULL, "msppencrypt auth in", "%02x ", auth, 16);
printfchars(NULL, "msppencrypt salt in", "%02x ", salt, 2);
printfchars(NULL, "msppencrypt in", "%02x ", text, len);
#endif
if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
......@@ -859,10 +959,7 @@ int msmppencrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
}
#if 0
printf("msppencrypt hash: ");
for (i = 0; i < 16; i++)
printf("%02x ", hash[i]);
printf("\n");
printfchars(NULL, "msppencrypt hash", "%02x ", hash, 16);
#endif
for (i = 0; i < 16; i++)
......@@ -871,9 +968,7 @@ int msmppencrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
for (offset = 16; offset < len; offset += 16) {
#if 0
printf("text + offset - 16 c(%d): ", offset / 16);
for (i = 0; i < 16; i++)
printf("%02x ", (text + offset - 16)[i]);
printf("\n");
printfchars(NULL, NULL, "%02x ", text + offset - 16, 16);
#endif
if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
!EVP_DigestUpdate(&mdctx, shared, sharedlen) ||
......@@ -883,11 +978,8 @@ int msmppencrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
pthread_mutex_unlock(&lock);
return 0;
}
#if 0
printf("msppencrypt hash: ");
for (i = 0; i < 16; i++)
printf("%02x ", hash[i]);
printf("\n");
#if 0
printfchars(NULL, "msppencrypt hash", "%02x ", hash, 16);
#endif
for (i = 0; i < 16; i++)
......@@ -895,10 +987,7 @@ int msmppencrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
}
#if 0
printf("msppencrypt out: ");
for (i = 0; i < len; i++)
printf("%02x ", text[i]);
printf("\n");
printfchars(NULL, "msppencrypt out", "%02x ", text, len);
#endif
pthread_mutex_unlock(&lock);
......@@ -920,21 +1009,10 @@ int msmppdecrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
first = 0;
}
#if 0
printf("msppdecrypt auth in: ");
for (i = 0; i < 16; i++)
printf("%02x ", auth[i]);
printf("\n");
printf("msppedecrypt salt in: ");
for (i = 0; i < 2; i++)
printf("%02x ", salt[i]);
printf("\n");
printf("msppedecrypt in: ");
for (i = 0; i < len; i++)
printf("%02x ", text[i]);
printf("\n");
#if 0
printfchars(NULL, "msppdecrypt auth in", "%02x ", auth, 16);
printfchars(NULL, "msppdecrypt salt in", "%02x ", salt, 2);
printfchars(NULL, "msppdecrypt in", "%02x ", text, len);
#endif
if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
......@@ -947,10 +1025,7 @@ int msmppdecrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
}
#if 0
printf("msppedecrypt hash: ");
for (i = 0; i < 16; i++)
printf("%02x ", hash[i]);
printf("\n");
printfchars(NULL, "msppdecrypt hash", "%02x ", hash, 16);
#endif
for (i = 0; i < 16; i++)
......@@ -959,9 +1034,7 @@ int msmppdecrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
for (offset = 16; offset < len; offset += 16) {
#if 0
printf("text + offset - 16 c(%d): ", offset / 16);
for (i = 0; i < 16; i++)
printf("%02x ", (text + offset - 16)[i]);
printf("\n");
printfchars(NULL, NULL, "%02x ", text + offset - 16, 16);
#endif
if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) ||
!EVP_DigestUpdate(&mdctx, shared, sharedlen) ||
......@@ -971,23 +1044,17 @@ int msmppdecrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
pthread_mutex_unlock(&lock);
return 0;
}
#if 0
printf("msppedecrypt hash: ");
for (i = 0; i < 16; i++)
printf("%02x ", hash[i]);
printf("\n");
#if 0
printfchars(NULL, "msppdecrypt hash", "%02x ", hash, 16);
#endif
for (i = 0; i < 16; i++)
plain[offset + i] = text[offset + i] ^ hash[i];
for (i = 0; i < 16; i++)
plain[offset + i] = text[offset + i] ^ hash[i];
}
memcpy(text, plain, len);
#if 0
printf("msppedecrypt out: ");
for (i = 0; i < len; i++)
printf("%02x ", text[i]);
printf("\n");
printfchars(NULL, "msppdecrypt out", "%02x ", text, len);
#endif
pthread_mutex_unlock(&lock);
......@@ -1039,9 +1106,6 @@ int attrvalidate(unsigned char *attrs, int length) {
}
int pwdrecrypt(uint8_t *pwd, uint8_t len, char *oldsecret, char *newsecret, uint8_t *oldauth, uint8_t *newauth) {
#ifdef DEBUG
int i;
#endif
if (len < 16 || len > 128 || len % 16) {
debug(DBG_WARN, "pwdrecrypt: invalid password length");
return 0;
......@@ -1052,10 +1116,7 @@ int pwdrecrypt(uint8_t *pwd, uint8_t len, char *oldsecret, char *newsecret, uint
return 0;
}
#ifdef DEBUG
printf("pwdrecrypt: password: ");
for (i = 0; i < len; i++)
printf("%02x ", pwd[i]);
printf("\n");
printfchars(NULL, "pwdrecrypt: password", "%02x ", pwd, len);
#endif
if (!pwdencrypt(pwd, len, newsecret, strlen(newsecret), newauth)) {
debug(DBG_WARN, "pwdrecrypt: cannot encrypt password");
......@@ -1210,8 +1271,8 @@ void radsrv(struct request *rq) {
return;
}
#ifdef DEBUG
printauth("auth", auth);
#ifdef DEBUG
printfchars(NULL, "auth", "%02x ", auth, 16);
#endif
attr = attrget(attrs, len, RAD_Attr_User_Password);
......@@ -1380,7 +1441,7 @@ void *clientrd(void *arg) {
buf[1] = (char)server->requests[i].origid;
memcpy(buf + 4, server->requests[i].origauth, 16);
#ifdef DEBUG
printauth("origauth/buf+4", buf + 4);
printfchars(NULL, "origauth/buf+4", "%02x ", buf + 4, 16);
#endif
if (messageauth) {
......@@ -2120,8 +2181,34 @@ void getgeneralconfig(FILE *f, char *block, ...) {
}
}
int addmatchcertattr(struct clsrvconf *conf, char *matchcertattr) {
char *v;
v = matchcertattr + 20;
if (strncasecmp(matchcertattr, "SubjectAltName:URI:/", 20) || !*v)
return 0;
/* regexp, remove optional trailing / if present */
if (v[strlen(v) - 1] == '/')
v[strlen(v) - 1] = '\0';
if (!*v)
return 0;
conf->certuriregex = malloc(sizeof(regex_t));
if (!conf->certuriregex) {
debug(DBG_ERR, "malloc failed");
return 0;
}
if (regcomp(conf->certuriregex, v, REG_ICASE | REG_NOSUB)) {
regfree(conf->certuriregex);
conf->certuriregex = NULL;
debug(DBG_ERR, "failed to compile regular expression %s", v);
return 0;
}
return 1;
}
void confclient_cb(FILE *f, char *block, char *opt, char *val) {
char *type = NULL, *tls = NULL;
char *type = NULL, *tls = NULL, *matchcertattr = NULL;
struct clsrvconf *conf;
debug(DBG_DBG, "confclient_cb called for %s", block);
......@@ -2136,6 +2223,7 @@ void confclient_cb(FILE *f, char *block, char *opt, char *val) {
"host", CONF_STR, &conf->host,
"secret", CONF_STR, &conf->secret,
"tls", CONF_STR, &tls,
"matchcertificateattribute", CONF_STR, &matchcertattr,
NULL
);
......@@ -2150,6 +2238,8 @@ void confclient_cb(FILE *f, char *block, char *opt, char *val) {
conf->ssl_ctx = tls ? tlsgetctx(tls, NULL) : tlsgetctx("defaultclient", "default");
if (!conf->ssl_ctx)
debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
if (matchcertattr && !addmatchcertattr(conf, matchcertattr))
debugx(1, DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block);
conf->type = 'T';
client_tls_count++;
} else
......@@ -2157,6 +2247,8 @@ void confclient_cb(FILE *f, char *block, char *opt, char *val) {
free(type);
if (tls)
free(tls);
if (matchcertattr)
free(matchcertattr);
if (!resolvepeer(conf, 0))
debugx(1, DBG_ERR, "failed to resolve host %s port %s, exiting", conf->host, conf->port);
......@@ -2169,7 +2261,7 @@ void confclient_cb(FILE *f, char *block, char *opt, char *val) {
}
void confserver_cb(FILE *f, char *block, char *opt, char *val) {
char *type = NULL, *tls = NULL, *statusserver = NULL;
char *type = NULL, *tls = NULL, *matchcertattr = NULL, *statusserver = NULL;
struct clsrvconf *conf;
debug(DBG_DBG, "confserver_cb called for %s", block);
......@@ -2185,6 +2277,7 @@ void confserver_cb(FILE *f, char *block, char *opt, char *val) {
"port", CONF_STR, &conf->port,
"secret", CONF_STR, &conf->secret,
"tls", CONF_STR, &tls,
"matchcertificateattribute", CONF_STR, &matchcertattr,
"StatusServer", CONF_STR, &statusserver,
NULL
);
......@@ -2202,6 +2295,8 @@ void confserver_cb(FILE *f, char *block, char *opt, char *val) {
conf->ssl_ctx = tls ? tlsgetctx(tls, NULL) : tlsgetctx("defaultserver", "default");
if (!conf->ssl_ctx)
debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
if (matchcertattr && !addmatchcertattr(conf, matchcertattr))
debugx(1, DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block);
if (!conf->port)
conf->port = stringcopy(DEFAULT_TLS_PORT, 0);
conf->type = 'T';
......@@ -2211,6 +2306,8 @@ void confserver_cb(FILE *f, char *block, char *opt, char *val) {
free(type);
if (tls)
free(tls);
if (matchcertattr)
free(matchcertattr);
if (!resolvepeer(conf, 0))
debugx(1, DBG_ERR, "failed to resolve host %s port %s, exiting", conf->host, conf->port);
......
......@@ -78,6 +78,7 @@ struct clsrvconf {
char *host;
char *port;
char *secret;
regex_t *certuriregex;
uint8_t statusserver;
SSL_CTX *ssl_ctx;
struct addrinfo *addrinfo;
......@@ -130,9 +131,8 @@ struct tls {
sizeof(struct sockaddr_in) : \
sizeof(struct sockaddr_in6))
void errx(char *format, ...);
void err(char *format, ...);
char *stringcopy(char *s, int len);
char *addr2string(struct sockaddr *addr, socklen_t len);
void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len);
int bindport(int type, char *port);
int connectport(int type, char *host, char *port);
/*
* Copyright (C) 2006 Stig Venaas <venaas@uninett.no>
* Copyright (C) 2006, 2007 Stig Venaas <venaas@uninett.no>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -61,7 +61,17 @@ char *stringcopy(char *s, int len) {
r[len] = '\0';
return r;
}
void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len) {
int i;
unsigned char *s = (unsigned char *)chars;
if (prefix)
printf(prefixfmt ? prefixfmt : "%s: ", prefix);
for (i = 0; i < len; i++)
printf(charfmt ? charfmt : "%c", s[i]);
printf("\n");
}
char *addr2string(struct sockaddr *addr, socklen_t len) {
struct sockaddr_in6 *sa6;
struct sockaddr_in sa4;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment