diff options
-rw-r--r-- | lib/conf.c | 27 | ||||
-rw-r--r-- | lib/examples/client.conf | 7 | ||||
-rw-r--r-- | lib/include/radsec/radsec-impl.h | 8 | ||||
-rw-r--r-- | lib/include/radsec/radsec.h | 1 | ||||
-rw-r--r-- | lib/tls.c | 72 |
5 files changed, 106 insertions, 9 deletions
@@ -26,7 +26,8 @@ #cacertpath = STRING certfile = STRING certkeyfile = STRING - psk = STRING # Transport pre-shared key. + pskstr = STRING # Transport pre-shared key, ASCII (UTF-8?) string form. + pskhexstr = STRING # Transport pre-shared key, hexadecimal string form. pskid = STRING pskex = "PSK"|"DHE_PSK"|"RSA_PSK" } @@ -67,7 +68,8 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) /*CFG_STR ("cacertpath", NULL, CFGF_NONE),*/ CFG_STR ("certfile", NULL, CFGF_NONE), CFG_STR ("certkeyfile", NULL, CFGF_NONE), - CFG_STR ("psk", NULL, CFGF_NONE), + CFG_STR ("pskstr", NULL, CFGF_NONE), + CFG_STR ("pskhexstr", NULL, CFGF_NONE), CFG_STR ("pskid", NULL, CFGF_NONE), CFG_STR ("pskex", "PSK", CFGF_NONE), CFG_SEC ("server", server_opts, CFGF_MULTI), @@ -110,7 +112,7 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) { struct rs_realm *r = NULL; const char *typestr; - char *psk; + char *pskstr = NULL, *pskhexstr = NULL; r = rs_calloc (ctx, 1, sizeof(*r)); if (r == NULL) @@ -154,8 +156,9 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) r->certfile = cfg_getstr (cfg_realm, "certfile"); r->certkeyfile = cfg_getstr (cfg_realm, "certkeyfile"); - psk = cfg_getstr (cfg_realm, "psk"); - if (psk) + pskstr = cfg_getstr (cfg_realm, "pskstr"); + pskhexstr = cfg_getstr (cfg_realm, "pskhexstr"); + if (pskstr || pskhexstr) { char *kex = cfg_getstr (cfg_realm, "pskex"); rs_cred_type_t type = RS_CRED_NONE; @@ -180,7 +183,19 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) NULL); cred->type = type; cred->identity = cfg_getstr (cfg_realm, "pskid"); - cred->secret = psk; + if (pskhexstr) + { + cred->secret_encoding = RS_KEY_ENCODING_ASCII_HEX; + cred->secret = pskhexstr; + if (pskstr) + ; /* TODO: warn that we're ignoring pskstr */ + } + else + { + cred->secret_encoding = RS_KEY_ENCODING_UTF8; + cred->secret = pskstr; + } + r->transport_cred = cred; } } diff --git a/lib/examples/client.conf b/lib/examples/client.conf index edd090e..cedd259 100644 --- a/lib/examples/client.conf +++ b/lib/examples/client.conf @@ -1,4 +1,4 @@ -dictionary = "/usr/share/freeradius/dictionary" +dictionary = "/home/linus/usr/moonshot/share/freeradius/dictionary" realm blocking-udp { type = "UDP" @@ -18,8 +18,9 @@ realm blocking-tls { cacertfile = "tests/demoCA/newcerts/01.pem" certfile = "tests/demoCA/newcerts/02.pem" certkeyfile = "tests/demoCA/private/c2key.pem" - psk = "sikrit psk" - pskid = "allan" + #pskstr = "sikrit psk" + pskhexstr = "deadbeef4711" + pskid = "Client_identity" pskex = "PSK" server { hostname = "localhost" diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index 01288d3..59cb8bf 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -23,6 +23,12 @@ enum rs_cred_type { }; typedef unsigned int rs_cred_type_t; +enum rs_key_encoding { + RS_KEY_ENCODING_UTF8 = 1, + RS_KEY_ENCODING_ASCII_HEX = 2, +}; +typedef unsigned int rs_key_encoding_t; + #if defined (__cplusplus) extern "C" { #endif @@ -31,6 +37,8 @@ struct rs_credentials { enum rs_cred_type type; char *identity; char *secret; + enum rs_key_encoding secret_encoding; + unsigned int secret_len; }; struct rs_error { diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index 2744cd2..abaa6e2 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -34,6 +34,7 @@ enum rs_error_code { RSE_TIMEOUT_IO = 18, /* I/O timeout. */ RSE_TIMEOUT = 19, /* High level timeout. */ RSE_DISCO = 20, + RSE_CRED = 21, /* Credentials. */ }; enum rs_conn_type { @@ -8,6 +8,7 @@ #include <assert.h> #include <openssl/ssl.h> #include <openssl/err.h> +#include <openssl/bn.h> #include <radsec/radsec.h> #include <radsec/radsec-impl.h> @@ -41,6 +42,72 @@ _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm) return c; } +static unsigned int +psk_client_cb (SSL *ssl, + const char *hint, + char *identity, + unsigned int max_identity_len, + unsigned char *psk, + unsigned int max_psk_len) +{ + struct rs_connection *conn = NULL; + struct rs_credentials *cred = NULL; + + conn = SSL_get_ex_data (ssl, 0); + assert (conn != NULL); + cred = conn->active_peer->realm->transport_cred; + assert (cred != NULL); + /* NOTE: Ignoring identity hint from server. */ + + if (strlen (cred->identity) + 1 > max_identity_len) + { + rs_err_conn_push (conn, RSE_CRED, "PSK identity longer than max %d", + max_identity_len - 1); + return 0; + } + strcpy (identity, cred->identity); + + switch (cred->secret_encoding) + { + case RS_KEY_ENCODING_UTF8: + cred->secret_len = strlen (cred->secret); + if (cred->secret_len > max_psk_len) + { + rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d", + max_psk_len); + return 0; + } + memcpy (psk, cred->secret, cred->secret_len); + break; + case RS_KEY_ENCODING_ASCII_HEX: + { + BIGNUM *bn = NULL; + + if (BN_hex2bn (&bn, cred->secret) == 0) + { + rs_err_conn_push (conn, RSE_CRED, "Unable to convert pskhexstr"); + if (bn != NULL) + BN_clear_free (bn); + return 0; + } + if ((unsigned int) BN_num_bytes (bn) > max_psk_len) + { + rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d", + max_psk_len); + BN_clear_free (bn); + return 0; + } + cred->secret_len = BN_bn2bin (bn, psk); + BN_clear_free (bn); + } + break; + default: + assert (!"unknown psk encoding"); + } + + return cred->secret_len; +} + int rs_tls_init (struct rs_connection *conn) { @@ -73,6 +140,11 @@ rs_tls_init (struct rs_connection *conn) return -1; } + if (conn->active_peer->realm->transport_cred != NULL) + { + SSL_set_psk_client_callback (ssl, psk_client_cb); + SSL_set_ex_data (ssl, 0, conn); + } conn->tls_ctx = ssl_ctx; conn->tls_ssl = ssl; rs_free (ctx, tlsconf); |