X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=lib%2Ftls.c;h=62e219e2f47f653c9ce88a2cb98ac0263b0482e6;hb=fed9094cd8cda69605d0c103acd14308379b6eb0;hp=12af4897f8066b9b195eaf880b146a93a8f82c5a;hpb=4d61fddb4f7e895b8814e7d18e0276498dca9bdb;p=radsecproxy.git diff --git a/lib/tls.c b/lib/tls.c index 12af489..62e219e 100644 --- a/lib/tls.c +++ b/lib/tls.c @@ -1,20 +1,22 @@ -/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. - See the file COPYING for licensing information. */ +/* Copyright 2010-2013 NORDUnet A/S. All rights reserved. + See LICENSE for licensing information. */ #if defined HAVE_CONFIG_H #include #endif +#include #include #include #include #include +#include #include #include #include -#include "rsp_list.h" -#include "../radsecproxy.h" +#include "radsecproxy/list.h" +#include "radsecproxy/radsecproxy.h" static struct tls * _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm) @@ -42,6 +44,7 @@ _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm) return c; } +#if defined RS_ENABLE_TLS_PSK static unsigned int psk_client_cb (SSL *ssl, const char *hint, @@ -107,6 +110,7 @@ psk_client_cb (SSL *ssl, return cred->secret_len; } +#endif /* RS_ENABLE_TLS_PSK */ int rs_tls_init (struct rs_connection *conn) @@ -140,13 +144,93 @@ rs_tls_init (struct rs_connection *conn) return -1; } +#if defined RS_ENABLE_TLS_PSK if (conn->active_peer->realm->transport_cred != NULL) { SSL_set_psk_client_callback (ssl, psk_client_cb); SSL_set_ex_data (ssl, 0, conn); } +#endif /* RS_ENABLE_TLS_PSK */ + conn->tls_ctx = ssl_ctx; conn->tls_ssl = ssl; rs_free (ctx, tlsconf); return RSE_OK; } + +/* draft-ietf-radext-radsec-11.txt + + * Certificate validation MUST include the verification rules as + per [RFC5280]. + + * Implementations SHOULD indicate their acceptable Certification + Authorities as per section 7.4.4 (server side) and x.y.z + ["Trusted CA Indication"] (client side) of [RFC5246] (see + Section 3.2) + + * Implementations SHOULD allow to configure a list of acceptable + certificates, identified via certificate fingerprint. When a + fingerprint configured, the fingerprint is prepended with an + ASCII label identifying the hash function followed by a colon. + Implementations MUST support SHA-1 as the hash algorithm and + use the ASCII label "sha-1" to identify the SHA-1 algorithm. + The length of a SHA-1 hash is 20 bytes and the length of the + corresponding fingerprint string is 65 characters. An example + certificate fingerprint is: sha- + 1:E1:2D:53:2B:7C:6B:8A:29:A2:76:C8:64:36:0B:08:4B:7A:F1:9E:9D + + * Peer validation always includes a check on whether the locally + configured expected DNS name or IP address of the server that + is contacted matches its presented certificate. DNS names and + IP addresses can be contained in the Common Name (CN) or + subjectAltName entries. For verification, only one of these + entries is to be considered. The following precedence + applies: for DNS name validation, subjectAltName:DNS has + precedence over CN; for IP address validation, subjectAltName: + iPAddr has precedence over CN. + + * Implementations SHOULD allow to configure a set of acceptable + values for subjectAltName:URI. + */ +int +tls_verify_cert (struct rs_connection *conn) +{ + int err = 0; + int success = 0; + X509 *peer_cert = NULL; + struct in6_addr addr; + const char *hostname = NULL; + + assert (conn->active_peer->conn == conn); + assert (conn->active_peer->hostname != NULL); + hostname = conn->active_peer->hostname; + + /* verifytlscert() performs basic verification as described by + OpenSSL VERIFY(1), i.e. verification of the certificate chain. */ + peer_cert = verifytlscert (conn->tls_ssl); + if (peer_cert == NULL) + { + err = rs_err_conn_push (conn, RSE_SSLERR, + "basic certificate validation failed"); + goto out; + } + + if (inet_pton (AF_INET, hostname, &addr)) + success = (subjectaltnameaddr (peer_cert, AF_INET, &addr) == 1); + else if (inet_pton (AF_INET6, hostname, &addr)) + success = (subjectaltnameaddr (peer_cert, AF_INET6, &addr) == 1); + else + success = (subjectaltnameregexp (peer_cert, GEN_DNS, hostname, NULL) == 1); + + if (!success) + success = (cnregexp (peer_cert, hostname, NULL) == 1); + + if (!success) + err = rs_err_conn_push (conn, RSE_CERT, "server certificate doesn't " + "match configured hostname \"%s\"", hostname); + + out: + if (peer_cert != NULL) + X509_free (peer_cert); + return err; +}