diff options
| author | Linus Nordberg <linus@nordu.net> | 2012-01-31 13:15:20 +0100 | 
|---|---|---|
| committer | Linus Nordberg <linus@nordu.net> | 2012-01-31 13:15:20 +0100 | 
| commit | dcd224f1fdf864fba1e1c1dd0b3f521fe43e4013 (patch) | |
| tree | a7e03caec791dfd3311520a5a985d5923f25ac90 | |
| parent | 76e68c0c676a9e795c70cc86d4b8e27396863d14 (diff) | |
Implement TLS-PSK.
| -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); | 
