diff options
| author | venaas <venaas> | 2007-01-25 12:42:48 +0000 | 
|---|---|---|
| committer | venaas <venaas@e88ac4ed-0b26-0410-9574-a7f39faa03bf> | 2007-01-25 12:42:48 +0000 | 
| commit | d1fd8449df7f12c6798849a13f1474fd40d66c32 (patch) | |
| tree | 52ced158cd5640abbae87e8c941ef8e6f2d8b04f | |
| parent | 234912c553f7808f25064b1a3980eb3651bb313e (diff) | |
further tls changes. not complete, contains some test code
git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@40 e88ac4ed-0b26-0410-9574-a7f39faa03bf
| -rw-r--r-- | radsecproxy.c | 275 | ||||
| -rw-r--r-- | radsecproxy.h | 3 | 
2 files changed, 218 insertions, 60 deletions
| diff --git a/radsecproxy.c b/radsecproxy.c index 51202e4..d6affca 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -6,10 +6,6 @@   * copyright notice and this permission notice appear in all copies.   */ -/* BUGS: - * peers can not yet be specified with literal IPv6 addresses due to port syntax - */ -  /* TODO:   * make our server ignore client retrans and do its own instead?   * accounting @@ -69,7 +65,8 @@ static struct replyq udp_server_replyq;  static int udp_server_sock = -1;  static pthread_mutex_t *ssl_locks;  static long *ssl_lock_count; -static SSL_CTX *ssl_ctx = NULL; +static SSL_CTX *ssl_ctx_cl = NULL; +static SSL_CTX *ssl_ctx_srv = NULL;  extern int optind;  extern char *optarg; @@ -86,9 +83,50 @@ void ssl_locking_callback(int mode, int type, const char *file, int line) {  	pthread_mutex_unlock(&ssl_locks[type]);  } -void ssl_init() { +static int verify_cb(int ok, X509_STORE_CTX *ctx) { +  char buf[256]; +  X509 *err_cert; +  int err, depth; + +  err_cert = X509_STORE_CTX_get_current_cert(ctx); +  err = X509_STORE_CTX_get_error(ctx); +  depth = X509_STORE_CTX_get_error_depth(ctx); + +  if (depth > MAX_CERT_DEPTH) { +      ok = 0; +      err = X509_V_ERR_CERT_CHAIN_TOO_LONG; +      X509_STORE_CTX_set_error(ctx, err); +  } + +  if (!ok) { +      X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); +      printf("verify error: num=%d:%s:depth=%d:%s\n", err, X509_verify_cert_error_string(err), depth, buf); + +      switch (err) { +      case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: +	  X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256); +	  printf("issuer=%s\n", buf); +	  break; +      case X509_V_ERR_CERT_NOT_YET_VALID: +      case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: +	  printf("Certificate not yet valid\n"); +	  break; +      case X509_V_ERR_CERT_HAS_EXPIRED: +	  printf("Certificate has expired\n"); +	  break; +      case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: +	  printf("Certificate no longer valid (after notAfter)\n"); +	  break; +      } +  } +  printf("certificate verify returns %d\n", ok); +  return ok; +} + +void ssl_init(SSL_CTX **ctx_srv, SSL_CTX **ctx_cl) {      int i;      unsigned long error; +    STACK_OF(X509_NAME) *calist;      if (!options.tlscertificatefile || !options.tlscertificatekeyfile) {  	printf("TLSCertificateFile and TLSCertificateKeyFile must be specified for TLS\n"); @@ -114,22 +152,88 @@ void ssl_init() {          RAND_seed((unsigned char *)&pid, sizeof(pid));      } -    ssl_ctx = SSL_CTX_new(TLSv1_method()); -    if (!ssl_ctx) { -	printf("failed to initialise ssl"); -	exit(1); +#if 0     +    if (ctx_srv) { +	*ctx_srv = SSL_CTX_new(TLSv1_server_method()); +	if (!SSL_CTX_use_certificate_chain_file(*ctx_srv, options.tlscertificatefile) || +	    !SSL_CTX_use_PrivateKey_file(*ctx_srv, options.tlscertificatekeyfile, SSL_FILETYPE_PEM) || +	    !SSL_CTX_check_private_key(*ctx_srv)) +	    goto errexit; +#if 1	 +#if 1 +	calist = (options.tlscacertificatefile +		  ? SSL_load_client_CA_file(options.tlscacertificatefile) +		  : sk_X509_NAME_new_null()); +	if (!calist || (options.tlscacertificatepath && +			 !SSL_add_dir_cert_subjects_to_stack(calist, options.tlscacertificatepath))) +	    goto errexit; +	SSL_CTX_set_client_CA_list(*ctx_srv, calist); +#endif	 +	if (!options.tlscacertificatefile && !options.tlscacertificatepath) { +	    printf("CA Certificate file/path need to be configured\n"); +	    exit(1); +	} +	if (!SSL_CTX_load_verify_locations(*ctx_srv, options.tlscacertificatefile, options.tlscacertificatepath)) +	    goto errexit; +	SSL_CTX_set_verify(*ctx_srv, SSL_VERIFY_PEER, verify_cb); +	SSL_CTX_set_verify_depth(*ctx_srv, MAX_CERT_DEPTH + 1); +#endif	      } - -    if (!SSL_CTX_use_certificate_file(ssl_ctx, options.tlscertificatefile, SSL_FILETYPE_PEM)) { -        while ((error = ERR_get_error())) -            err("SSL: %s", ERR_error_string(error, NULL)); -        errx("Failed to load certificate"); +    if (ctx_cl) { +	*ctx_cl = SSL_CTX_new(TLSv1_client_method()); +	if (!SSL_CTX_use_certificate_chain_file(*ctx_cl, options.tlscertificatefile) || +	    !SSL_CTX_use_PrivateKey_file(*ctx_cl, options.tlscertificatekeyfile, SSL_FILETYPE_PEM) || +	    !SSL_CTX_check_private_key(*ctx_cl)) +	    goto errexit; +	if (!options.tlscacertificatefile && !options.tlscacertificatepath) { +	    printf("CA Certificate file/path need to be configured\n"); +	    exit(1); +	} +	if (!SSL_CTX_load_verify_locations(*ctx_cl, options.tlscacertificatefile, options.tlscacertificatepath)) +	    goto errexit; +	SSL_CTX_set_verify(*ctx_cl, SSL_VERIFY_PEER, verify_cb); +	SSL_CTX_set_verify_depth(*ctx_cl, MAX_CERT_DEPTH + 1);      } -    if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, options.tlscertificatekeyfile, SSL_FILETYPE_PEM)) { -	while ((error = ERR_get_error())) -	    err("SSL: %s", ERR_error_string(error, NULL)); -	errx("Failed to load private key"); +#else +    if (ctx_srv) { +	*ctx_srv = SSL_CTX_new(TLSv1_server_method()); +	if (!SSL_CTX_use_certificate_chain_file(*ctx_srv, options.tlscertificatefile) || +	    !SSL_CTX_use_PrivateKey_file(*ctx_srv, options.tlscertificatekeyfile, SSL_FILETYPE_PEM) || +	    !SSL_CTX_check_private_key(*ctx_srv)) +	    goto errexit; +#if 0	 +	calist = (SSL_load_client_CA_file(options.tlscacertificatefile)); +	SSL_CTX_set_client_CA_list(*ctx_srv, calist); +#endif	 +	if (!SSL_CTX_load_verify_locations(*ctx_srv, options.tlscacertificatefile, NULL/*options.tlscacertificatepath*/)) +	    goto errexit; +	 +	SSL_CTX_set_verify(*ctx_srv, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb); +	SSL_CTX_set_verify_depth(*ctx_srv, MAX_CERT_DEPTH + 1); +    } +    if (ctx_cl) { +	*ctx_cl = SSL_CTX_new(TLSv1_client_method()); +	if (!SSL_CTX_use_certificate_chain_file(*ctx_cl, options.tlscertificatefile) || +	    !SSL_CTX_use_PrivateKey_file(*ctx_cl, options.tlscertificatekeyfile, SSL_FILETYPE_PEM) || +	    !SSL_CTX_check_private_key(*ctx_cl)) +	    goto errexit; +	if (!SSL_CTX_load_verify_locations(*ctx_cl,options.tlscacertificatefile, NULL/*options.tlscacertificatepath*/)) +	    goto errexit; +	 +	SSL_CTX_set_verify(*ctx_cl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb); +	SSL_CTX_set_verify_depth(*ctx_cl, MAX_CERT_DEPTH + 1); +#if 0	 +	calist = (SSL_load_client_CA_file(options.tlscacertificatefile)); +	SSL_CTX_set_client_CA_list(*ctx_cl, calist); +#endif	      } +#endif     +    return; +     + errexit: +    while ((error = ERR_get_error())) +	err("SSL: %s", ERR_error_string(error, NULL)); +    exit(1);  }      void printauth(char *s, unsigned char *t) { @@ -295,10 +399,54 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,      return rad;  } +int tlsverifycert(struct peer *peer) { +    int i, l, loc; +    X509 *cert; +    X509_NAME *nm; +    X509_NAME_ENTRY *e; +    unsigned char *v; +    unsigned long error; + +#if 1 +    if (SSL_get_verify_result(peer->ssl) != X509_V_OK) { +	printf("tlsverifycert: basic validation failed\n"); +	while ((error = ERR_get_error())) +	    err("clientwr: TLS: %s", ERR_error_string(error, NULL)); +	return 0; +    } +#endif     +    cert = SSL_get_peer_certificate(peer->ssl); +    if (!cert) { +	printf("tlsverifycert: failed to obtain certificate\n"); +	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; +	printf("cn: "); +	for (i = 0; i < l; i++) +	    printf("%c", v[i]); +	printf("\n"); +	if (l == strlen(peer->host) && !strncasecmp(peer->host, v, l)) { +	    printf("tlsverifycert: Found cn matching host %s, All OK\n", peer->host); +	    return 1; +	} +	printf("tlsverifycert: cn not matching host %s\n", peer->host); +    } +    X509_free(cert); +    return 0; +} +  void tlsconnect(struct server *server, struct timeval *when, char *text) {      struct timeval now;      time_t elapsed; -    unsigned long error;      printf("tlsconnect called from %s\n", text);      pthread_mutex_lock(&server->lock); @@ -331,12 +479,10 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) {  	if ((server->sock = connecttoserver(server->peer.addrinfo)) < 0)  	    continue;  	SSL_free(server->peer.ssl); -	server->peer.ssl = SSL_new(ssl_ctx); +	server->peer.ssl = SSL_new(ssl_ctx_cl);  	SSL_set_fd(server->peer.ssl, server->sock); -	if (SSL_connect(server->peer.ssl) > 0) +	if (SSL_connect(server->peer.ssl) > 0 && tlsverifycert(&server->peer))  	    break; -	while ((error = ERR_get_error())) -	    err("tlsconnect: TLS: %s", ERR_error_string(error, NULL));      }      printf("tlsconnect: TLS connection to %s port %s up\n", server->peer.host, server->peer.port);      gettimeofday(&server->lastconnecttry, NULL); @@ -1329,30 +1475,32 @@ void *tlsserverrd(void *arg) {          errx("accept failed, child exiting");      } -    if (pthread_create(&tlsserverwrth, NULL, tlsserverwr, (void *)client)) -	errx("pthread_create failed"); +    if (1 /*tlsverifycert(&client->peer)*/) { +	if (pthread_create(&tlsserverwrth, NULL, tlsserverwr, (void *)client)) +	    errx("pthread_create failed"); -    for (;;) { -	buf = radtlsget(client->peer.ssl); -	if (!buf) -	    break; -	printf("tlsserverrd: got Radius message from %s\n", client->peer.host); -	memset(&rq, 0, sizeof(struct request)); -	to = radsrv(&rq, buf, client); -	if (!to) { -	    printf("ignoring request, no place to send it\n"); -	    continue; +	for (;;) { +	    buf = radtlsget(client->peer.ssl); +	    if (!buf) +		break; +	    printf("tlsserverrd: got Radius message from %s\n", client->peer.host); +	    memset(&rq, 0, sizeof(struct request)); +	    to = radsrv(&rq, buf, client); +	    if (!to) { +		printf("ignoring request, no place to send it\n"); +		continue; +	    } +	    sendrq(to, client, &rq);  	} -	sendrq(to, client, &rq); -    } -    printf("tlsserverrd: connection lost\n"); -    // stop writer by setting peer.ssl to NULL and give signal in case waiting for data -    client->peer.ssl = NULL; -    pthread_mutex_lock(&client->replyq->count_mutex); -    pthread_cond_signal(&client->replyq->count_cond); -    pthread_mutex_unlock(&client->replyq->count_mutex); -    printf("tlsserverrd: waiting for writer to end\n"); -    pthread_join(tlsserverwrth, NULL); +	printf("tlsserverrd: connection lost\n"); +	// stop writer by setting peer.ssl to NULL and give signal in case waiting for data +	client->peer.ssl = NULL; +	pthread_mutex_lock(&client->replyq->count_mutex); +	pthread_cond_signal(&client->replyq->count_cond); +	pthread_mutex_unlock(&client->replyq->count_mutex); +	printf("tlsserverrd: waiting for writer to end\n"); +	pthread_join(tlsserverwrth, NULL); +    }      s = SSL_get_fd(ssl);      SSL_free(ssl);      close(s); @@ -1395,7 +1543,7 @@ int tlslistener() {  	    close(snew);  	    continue;  	} -	client->peer.ssl = SSL_new(ssl_ctx); +	client->peer.ssl = SSL_new(ssl_ctx_srv);  	SSL_set_fd(client->peer.ssl, snew);  	if (pthread_create(&tlsserverth, NULL, tlsserverrd, (void *)client))  	    errx("pthread_create failed"); @@ -1629,6 +1777,14 @@ void getmainconfig(const char *configfile) {  	endval[1] = '\0';  	printf("getmainconfig: %s = %s\n", opt, val); +	if (!strcasecmp(opt, "TLSCACertificateFile")) { +	    options.tlscacertificatefile = stringcopy(val, 0); +	    continue; +	} +	if (!strcasecmp(opt, "TLSCACertificatePath")) { +	    options.tlscacertificatepath = stringcopy(val, 0); +	    continue; +	}  	if (!strcasecmp(opt, "TLSCertificateFile")) {  	    options.tlscertificatefile = stringcopy(val, 0);  	    continue; @@ -1676,7 +1832,7 @@ void parseargs(int argc, char **argv) {  int main(int argc, char **argv) {      pthread_t udpserverth;      //    pthread_attr_t joinable; -    int i; +    int i, tlsclients = 0, tlsservers = 0;      //    parseargs(argc, argv);      getmainconfig("radsecproxy.conf"); @@ -1687,32 +1843,31 @@ int main(int argc, char **argv) {      //    pthread_attr_setdetachstate(&joinable, PTHREAD_CREATE_JOINABLE);      /* listen on UDP if at least one UDP client */ -          for (i = 0; i < client_count; i++)  	if (clients[i].peer.type == 'U') {  	    if (pthread_create(&udpserverth, NULL /*&joinable*/, udpserverrd, NULL))  		errx("pthread_create failed");  	    break;  	} - -    /* only initialise ssl here if at least one TLS server defined */ +     +    for (i = 0; i < client_count; i++) +	if (clients[i].peer.type == 'T') { +	    tlsclients = 1; +	    break; +	}      for (i = 0; i < server_count; i++)  	if (servers[i].peer.type == 'T') { -	    ssl_init(); +	    tlsservers = 1;  	    break;  	} - +    ssl_init(tlsclients ? &ssl_ctx_srv : NULL, tlsservers ? &ssl_ctx_cl : NULL); +          for (i = 0; i < server_count; i++)  	if (pthread_create(&servers[i].clientth, NULL, clientwr, (void *)&servers[i]))  	    errx("pthread_create failed"); -    /* start listener if at least one TLS client defined */ -    for (i = 0; i < client_count; i++) -	if (clients[i].peer.type == 'T') { -	    if (!ssl_ctx) -		ssl_init(); -	    return tlslistener(); -	} +    if (tlsclients) +	return tlslistener();      /* just hang around doing nothing, anything to do here? */      for (;;) diff --git a/radsecproxy.h b/radsecproxy.h index e6dca52..5719070 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -19,6 +19,7 @@  #define DEFAULT_UDP_PORT "1812"  #define DEFAULT_TLS_PORT "2083"  #define REQUEST_TIMEOUT 5 +#define MAX_CERT_DEPTH 5  #define RAD_Access_Request 1  #define RAD_Access_Accept 2 @@ -43,6 +44,8 @@  #define RAD_Attr_Value 2  struct options { +    char *tlscacertificatefile; +    char *tlscacertificatepath;      char *tlscertificatefile;      char *tlscertificatekeyfile;      char *udpserverport; | 
