summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordu.net>2012-01-31 13:15:20 +0100
committerLinus Nordberg <linus@nordu.net>2012-01-31 13:15:20 +0100
commitdcd224f1fdf864fba1e1c1dd0b3f521fe43e4013 (patch)
treea7e03caec791dfd3311520a5a985d5923f25ac90
parent76e68c0c676a9e795c70cc86d4b8e27396863d14 (diff)
Implement TLS-PSK.
-rw-r--r--lib/conf.c27
-rw-r--r--lib/examples/client.conf7
-rw-r--r--lib/include/radsec/radsec-impl.h8
-rw-r--r--lib/include/radsec/radsec.h1
-rw-r--r--lib/tls.c72
5 files changed, 106 insertions, 9 deletions
diff --git a/lib/conf.c b/lib/conf.c
index e813409..37fd9b4 100644
--- a/lib/conf.c
+++ b/lib/conf.c
@@ -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 {
diff --git a/lib/tls.c b/lib/tls.c
index 6fcf5a0..9427f78 100644
--- a/lib/tls.c
+++ b/lib/tls.c
@@ -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);