summaryrefslogtreecommitdiffstats
path: root/src/include/tls-h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/include/tls-h448
1 files changed, 448 insertions, 0 deletions
diff --git a/src/include/tls-h b/src/include/tls-h
new file mode 100644
index 0000000..7bb994b
--- /dev/null
+++ b/src/include/tls-h
@@ -0,0 +1,448 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_TLS_H
+#define FR_TLS_H
+
+#ifdef WITH_TLS
+/**
+ * $Id$
+ *
+ * @file tls.h
+ * @brief Structures and prototypes for TLS wrappers
+ *
+ * @copyright 2010 Network RADIUS SARL <info@networkradius.com>
+ */
+
+RCSIDH(tls_h, "$Id$")
+
+#include <freeradius-devel/conffile.h>
+
+/*
+ * For RH 9, which apparently needs this.
+ */
+#ifndef OPENSSL_NO_KRB5
+# define OPENSSL_NO_KRB5
+#endif
+#include <openssl/err.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+# include <openssl/engine.h>
+#endif
+#include <openssl/ssl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct fr_tls_server_conf_t fr_tls_server_conf_t;
+
+typedef enum {
+ FR_TLS_INVALID = 0, //!< Invalid, don't reply.
+ FR_TLS_REQUEST, //!< Request, ok to send, invalid to receive.
+ FR_TLS_RESPONSE, //!< Response, ok to receive, invalid to send.
+ FR_TLS_SUCCESS, //!< Success, send success.
+ FR_TLS_FAIL, //!< Fail, send fail.
+ FR_TLS_NOOP, //!< Noop, continue.
+
+ FR_TLS_START, //!< Start, ok to send, invalid to receive.
+ FR_TLS_OK, //!< Ok, continue.
+ FR_TLS_ACK, //!< Acknowledge, continue.
+ FR_TLS_FIRST_FRAGMENT, //!< First fragment.
+ FR_TLS_MORE_FRAGMENTS, //!< More fragments, to send/receive.
+ FR_TLS_LENGTH_INCLUDED, //!< Length included.
+ FR_TLS_MORE_FRAGMENTS_WITH_LENGTH, //!< More fragments with length.
+ FR_TLS_HANDLED //!< TLS code has handled it.
+} fr_tls_status_t;
+extern FR_NAME_NUMBER const fr_tls_status_table[];
+
+#define MAX_RECORD_SIZE 16384
+
+/*
+ * A single TLS record may be up to 16384 octets in length, but a
+ * TLS message may span multiple TLS records, and a TLS
+ * certificate message may in principle be as long as 16MB.
+ *
+ * However, note that in order to protect against reassembly
+ * lockup and denial of service attacks, it may be desirable for
+ * an implementation to set a maximum size for one such group of
+ * TLS messages.
+ *
+ * The TLS Message Length field is four octets, and provides the
+ * total length of the TLS message or set of messages that is
+ * being fragmented; this simplifies buffer allocation.
+ */
+
+/*
+ * FIXME: Dynamic allocation of buffer to overcome MAX_RECORD_SIZE overflows.
+ * or configure TLS not to exceed MAX_RECORD_SIZE.
+ */
+typedef struct _record_t {
+ uint8_t data[MAX_RECORD_SIZE];
+ size_t used;
+} record_t;
+
+typedef struct _tls_info_t {
+ int origin; // 0 - received (from peer), 1 - sending (to peer)
+ int content_type;
+ uint8_t handshake_type;
+ uint8_t alert_level;
+ uint8_t alert_description;
+ bool initialized;
+
+ char info_description[256];
+ size_t record_len;
+} tls_info_t;
+
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
+#define ssl_session ssl->session
+#else
+#define ssl_session session
+#endif
+
+/** Contains EAP-REQUEST specific data (ie FR_TLS_DATA(fragment), EAPTLS-ALERT, EAPTLS-REQUEST ...)
+ *
+ * The tls_session_t Structure gets stored as opaque in eap_handler_t
+ */
+typedef struct _tls_session_t {
+ SSL_CTX *ctx;
+ SSL *ssl;
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ SSL_SESSION *session;
+#endif
+ tls_info_t info;
+
+ BIO *into_ssl;
+ BIO *from_ssl;
+ record_t clean_in; //!< Data that needs to be sent but only after it is soiled.
+ record_t clean_out; //!< Data that is cleaned after receiving.
+ record_t dirty_in; //!< Data EAP server receives.
+ record_t dirty_out; //!< Data EAP server sends.
+
+ void (*record_init)(record_t *buf);
+ void (*record_close)(record_t *buf);
+ unsigned int (*record_plus)(record_t *buf, void const *ptr, unsigned int size);
+ unsigned int (*record_minus)(record_t *buf, void *ptr, unsigned int size);
+
+ bool invalid_hb_used; //!< Whether heartbleed attack was detected.
+ bool connected; //!< whether the outgoing socket is connected
+ bool is_init_finished; //!< whether or not init is finished
+ bool client_cert_ok; //!< whether or not we validated the client certificate
+ bool authentication_success; //!< whether or not the user was authenticated (cert or PW)
+ bool quick_session_tickets; //!< for EAP-TLS.
+
+ /*
+ * Framed-MTU attribute in RADIUS, if present, can also be used to set this
+ */
+ size_t mtu; //!< Current fragment size transmitted.
+ size_t tls_msg_len; //!< Actual/Total TLS message length.
+ bool fragment; //!< Flag, In fragment mode or not.
+ bool length_flag; //!< A flag to include length in every TLS Data/Alert packet.
+ //!< If set to no then only the first fragment contains length.
+ int peap_flag;
+
+ size_t tls_record_in_total_len; //!< How long the peer indicated the complete tls record
+ //!< would be.
+ size_t tls_record_in_recvd_len; //!< How much of the record we've received so far.
+
+ /*
+ * Used by TTLS & PEAP to keep track of other per-session data.
+ */
+ void *opaque;
+ void (*free_opaque)(void *opaque);
+
+ char const *label;
+ bool allow_session_resumption; //!< Whether session resumption is allowed.
+ bool session_not_resumed; //!< Whether our session was not resumed.
+
+ fr_tls_server_conf_t const *conf; //! for better complaints
+} tls_session_t;
+
+/*
+ * RFC 2716, Section 4.2:
+ *
+ * Flags
+ *
+ * 0 1 2 3 4 5 6 7 8
+ * +-+-+-+-+-+-+-+-+
+ * |L M S R R R R R|
+ * +-+-+-+-+-+-+-+-+
+ *
+ * L = Length included
+ * M = More fragments
+ * S = EAP-TLS start
+ * R = Reserved
+ */
+#define TLS_START(x) (((x) & 0x20) != 0)
+#define TLS_MORE_FRAGMENTS(x) (((x) & 0x40) != 0)
+#define TLS_LENGTH_INCLUDED(x) (((x) & 0x80) != 0)
+
+#define TLS_CHANGE_CIPHER_SPEC(x) (((x) & 0x0014) == 0x0014)
+#define TLS_ALERT(x) (((x) & 0x0015) == 0x0015)
+#define TLS_HANDSHAKE(x) (((x) & 0x0016) == 0x0016)
+
+#define SET_START(x) ((x) | (0x20))
+#define SET_MORE_FRAGMENTS(x) ((x) | (0x40))
+#define SET_LENGTH_INCLUDED(x) ((x) | (0x80))
+
+/*
+ * Following enums from rfc2246
+ *
+ * Hmm... since we dpeend on OpenSSL, it would be smarter to
+ * use the OpenSSL names for these.
+ */
+enum ContentType {
+ change_cipher_spec = 20,
+ alert = 21,
+ handshake = 22,
+ application_data = 23
+};
+
+enum AlertLevel {
+ warning = 1,
+ fatal = 2
+};
+
+enum AlertDescription {
+ close_notify = 0,
+ unexpected_message = 10,
+ bad_record_mac = 20,
+ decryption_failed = 21,
+ record_overflow = 22,
+ decompression_failure = 30,
+ handshake_failure = 40,
+ bad_certificate = 42,
+ unsupported_certificate = 43,
+ certificate_revoked = 44,
+ certificate_expired = 45,
+ certificate_unknown = 46,
+ illegal_parameter = 47,
+ unknown_ca = 48,
+ access_denied = 49,
+ decode_error = 50,
+ decrypt_error = 51,
+ export_restriction = 60,
+ protocol_version = 70,
+ insufficient_security = 71,
+ internal_error = 80,
+ user_canceled = 90,
+ no_renegotiation = 100
+};
+
+enum HandshakeType {
+ hello_request = 0,
+ client_hello = 1,
+ server_hello = 2,
+ certificate = 11,
+ server_key_exchange = 12,
+ certificate_request = 13,
+ server_hello_done = 14,
+ certificate_verify = 15,
+ client_key_exchange = 16,
+ handshake_finished = 20
+};
+
+
+/*
+ * From rfc
+ Flags
+
+ 0 1 2 3 4 5 6 7 8
+ +-+-+-+-+-+-+-+-+
+ |L M S R R R R R|
+ +-+-+-+-+-+-+-+-+
+
+ L = Length included
+ M = More fragments
+ S = EAP-TLS start
+ R = Reserved
+
+ The L bit (length included) is set to indicate the presence of the
+ four octet TLS Message Length field, and MUST be set for the first
+ fragment of a fragmented TLS message or set of messages. The M bit
+ (more fragments) is set on all but the last fragment. The S bit
+ (EAP-TLS start) is set in an EAP-TLS Start message. This
+ differentiates the EAP-TLS Start message from a fragment
+ acknowledgement.
+
+ TLS Message Length
+
+ The TLS Message Length field is four octets, and is present only
+ if the L bit is set. This field provides the total length of the
+ TLS message or set of messages that is being fragmented.
+
+ TLS data
+
+ The TLS data consists of the encapsulated TLS packet in TLS record
+ format.
+ *
+ * The data structures present here
+ * maps only to the typedata in the EAP packet
+ *
+ * Based on the L bit flag, first 4 bytes of data indicate the length
+ */
+
+/* Callbacks */
+int cbtls_password(char *buf, int num, int rwflag, void *userdata);
+void cbtls_info(SSL const *s, int where, int ret);
+void cbtls_msg(int write_p, int msg_version, int content_type, void const *buf, size_t len, SSL *ssl,
+ void *arg);
+int cbtls_verify(int ok, X509_STORE_CTX *ctx);
+
+/* threads.c */
+int tls_mutexes_init(void);
+
+/* TLS */
+int tls_global_init(bool spawn_flag, bool check);
+#ifdef ENABLE_OPENSSL_VERSION_CHECK
+int tls_global_version_check(char const *acknowledged);
+#endif
+
+int tls_error_log(REQUEST *request, char const *msg, ...) CC_HINT(format (printf, 2, 3));
+int tls_error_io_log(REQUEST *request, tls_session_t *session, int ret, char const *msg, ...)
+ CC_HINT(format (printf, 4, 5));
+
+void tls_global_cleanup(void);
+tls_session_t *tls_new_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, REQUEST *request, bool client_cert, bool allow_tls13);
+tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, int fd, VALUE_PAIR **certs);
+fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs);
+fr_tls_server_conf_t *tls_client_conf_parse(CONF_SECTION *cs);
+fr_tls_server_conf_t *tls_server_conf_alloc(TALLOC_CTX *ctx);
+SSL_CTX *tls_init_ctx(fr_tls_server_conf_t *conf, int client, char const *chain_file, char const *private_key_file);
+int tls_handshake_recv(REQUEST *, tls_session_t *ssn);
+int tls_handshake_send(REQUEST *, tls_session_t *ssn);
+void tls_session_information(tls_session_t *ssn);
+void tls_session_id(SSL_SESSION *ssn, char *buffer, size_t bufsize);
+X509_STORE *fr_init_x509_store(fr_tls_server_conf_t *conf);
+
+/*
+ * Low-level TLS stuff
+ */
+int tls_success(tls_session_t *ssn, REQUEST *request);
+void tls_fail(tls_session_t *ssn);
+fr_tls_status_t tls_ack_handler(tls_session_t *tls_session, REQUEST *request);
+fr_tls_status_t tls_application_data(tls_session_t *ssn, REQUEST *request);
+
+#define FR_TLS_EX_INDEX_HANDLER (10)
+#define FR_TLS_EX_INDEX_CONF (11)
+#define FR_TLS_EX_INDEX_REQUEST (12)
+#define FR_TLS_EX_INDEX_IDENTITY (13)
+#define FR_TLS_EX_INDEX_STORE (14)
+#define FR_TLS_EX_INDEX_SSN (15)
+#define FR_TLS_EX_INDEX_TALLOC (16)
+#define FR_TLS_EX_INDEX_FIX_CERT_ORDER (17)
+
+extern int fr_tls_ex_index_certs;
+extern int fr_tls_ex_index_vps;
+
+/* configured values goes right here */
+struct fr_tls_server_conf_t {
+ SSL_CTX *ctx;
+ CONF_SECTION *cs;
+
+ char const *private_key_password;
+ char const *private_key_file;
+ char const *certificate_file;
+ char const *random_file;
+ char const *ca_path;
+ char const *ca_file;
+ char const *dh_file;
+ char const *rsa_file;
+ uint32_t verify_depth;
+ bool file_type;
+ bool include_length;
+ bool auto_chain;
+ bool disable_single_dh_use;
+ bool disable_tlsv1;
+ bool disable_tlsv1_1;
+ bool disable_tlsv1_2;
+ bool disallow_untrusted; //!< allow untrusted CAs to issue client certificates
+
+ int min_version;
+ int max_version;
+
+ char const *tls_min_version;
+ char const *tls_max_version;
+
+ /*
+ * Always < 4096 (due to radius limit), 0 by default = 1024
+ */
+ uint32_t fragment_size;
+ bool check_crl;
+ bool check_all_crl;
+ bool allow_expired_crl;
+ uint32_t ca_path_reload_interval;
+ uint32_t ca_path_last_reload;
+ X509_STORE *old_x509_store;
+ char const *check_cert_cn;
+ char const *cipher_list;
+ bool cipher_server_preference;
+ char const *check_cert_issuer;
+ char const *sigalgs_list;
+
+ bool session_cache_enable;
+ uint32_t session_lifetime;
+ uint32_t session_cache_size;
+ char const *session_id_name;
+ char const *session_cache_path;
+ char const *session_cache_server;
+ fr_hash_table_t *cache_ht;
+ char session_context_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
+
+ bool verify_skip_if_ocsp_ok;
+ char const *verify_tmp_dir;
+ char const *verify_client_cert_cmd;
+ bool require_client_cert;
+
+ bool fix_cert_order;
+
+ pthread_mutex_t mutex;
+
+#ifdef HAVE_OPENSSL_OCSP_H
+ /*
+ * OCSP Configuration
+ */
+ bool ocsp_enable;
+ bool ocsp_override_url;
+ char const *ocsp_url;
+ bool ocsp_use_nonce;
+ X509_STORE *ocsp_store;
+ uint32_t ocsp_timeout;
+ bool ocsp_softfail;
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+ char const *ecdh_curve;
+#endif
+#endif
+
+#ifdef PSK_MAX_IDENTITY_LEN
+ char const *psk_identity;
+ char const *psk_password;
+ char const *psk_query;
+#endif
+
+ char const *realm_dir;
+ fr_hash_table_t *realms;
+
+ char const *client_hostname;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WITH_TLS */
+#endif /* FR_TLS_H */