Merge tag 'release_3_0_4_rc1' into tr-upgrade
[freeradius.git] / src / main / tls.c
index 51dcd2e..c44122e 100644 (file)
@@ -40,6 +40,7 @@ USES_APPLE_DEPRECATED_API     /* OpenSSL API has been deprecated by Apple */
 #ifdef HAVE_UTIME_H
 #include <utime.h>
 #endif
+#include <ctype.h>
 
 #ifdef WITH_TLS
 #ifdef HAVE_OPENSSL_RAND_H
@@ -80,25 +81,61 @@ static unsigned int         record_minus(record_t *buf, void *ptr,
                                     unsigned int size);
 
 #ifdef PSK_MAX_IDENTITY_LEN
-static unsigned int psk_server_callback(SSL *ssl, char const *identity,
+static int identity_is_safe( const char *identity)
+{
+       while (identity &&identity[0]) {
+               char c = identity[0];
+               identity++;
+               if (isalpha(c) || isdigit(c))
+                       continue;
+               else if ((c == '@') || (c == '-') || (c == '_'))
+                       continue;
+               else if (isspace(c) || (c == '.'))
+                       continue;
+               else return 0;
+       }
+       return 1;
+}
+
+static unsigned int psk_server_callback(SSL *ssl, const char *identity,
                                        unsigned char *psk,
                                        unsigned int max_psk_len)
 {
-       unsigned int psk_len;
+       unsigned int psk_len = 0;
        fr_tls_server_conf_t *conf;
+       REQUEST *request;
+       
 
        conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl,
                                                       FR_TLS_EX_INDEX_CONF);
        if (!conf) return 0;
 
-       /*
-        *      FIXME: Look up the PSK password based on the identity!
-        */
-       if (strcmp(identity, conf->psk_identity) != 0) {
+       request = (REQUEST *)SSL_get_ex_data(ssl,
+                                            FR_TLS_EX_INDEX_REQUEST);
+       if (request) {
+               VALUE_PAIR *vp;
+               char psk_buffer[2*PSK_MAX_PSK_LEN+1];
+                size_t hex_len = 0;
+               if (max_psk_len > PSK_MAX_PSK_LEN)
+                 max_psk_len = PSK_MAX_PSK_LEN;
+               vp = pairmake(request, &request->config_items,
+                                 "tls-psk-identity",
+                                 identity, T_OP_SET);
+               if (vp) {
+                       if (identity_is_safe(identity))
+                         hex_len = radius_xlat((char *) psk_buffer,
+                                               2*max_psk_len+1,
+                                               request, "%{psksql:select hex(key) from psk_keys where keyid = '%{control:tls-psk-identity}';}",
+                                               NULL, NULL);
+                       if (hex_len >0)
+                         return fr_hex2bin(psk, psk_buffer, hex_len);
+               }
+       }
+               if (strcmp(identity, conf->psk_identity) != 0) {
                return 0;
        }
 
-       psk_len = strlen(conf->psk_password);
+               psk_len = strlen(conf->psk_password);
        if (psk_len > (2 * max_psk_len)) return 0;
 
        return fr_hex2bin(psk, conf->psk_password, psk_len);
@@ -1999,7 +2036,7 @@ void tls_global_cleanup(void)
  *     - Load the Private key & the certificate
  *     - Set the Context options & Verify options
  */
-static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
+ SSL_CTX *tls_init_ctx(fr_tls_server_conf_t *conf, int client)
 {
        SSL_CTX *ctx;
        X509_STORE *certstore;
@@ -2106,6 +2143,19 @@ static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
                return NULL;
        }
 
+       /*
+        * There are two ways PSKs can be configured for a server. The
+        * first is the same as a client: psk_identity and
+        * psk_hexphrase. The second is to dynamically configure PSKs
+        * and to have the psk_xlat return them. The second is
+        * compatible with certificates; either the PSK or cert will
+        * be used depending on what the client uses.
+        */
+       if (!client)
+               SSL_CTX_set_psk_server_callback(ctx,
+                                               psk_server_callback);
+
+
        if (conf->psk_identity) {
                size_t psk_len, hex_len;
                char buffer[PSK_MAX_PSK_LEN];
@@ -2120,10 +2170,7 @@ static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
                if (client) {
                        SSL_CTX_set_psk_client_callback(ctx,
                                                        psk_client_callback);
-               } else {
-                       SSL_CTX_set_psk_server_callback(ctx,
-                                                       psk_server_callback);
-               }
+               } 
 
                psk_len = strlen(conf->psk_password);
                if (strlen(conf->psk_password) > (2 * PSK_MAX_PSK_LEN)) {
@@ -2436,7 +2483,7 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs)
        /*
         *      Initialize TLS
         */
-       conf->ctx = init_tls_ctx(conf, 0);
+       conf->ctx = tls_init_ctx(conf, 0);
        if (conf->ctx == NULL) {
                goto error;
        }
@@ -2515,7 +2562,7 @@ fr_tls_server_conf_t *tls_client_conf_parse(CONF_SECTION *cs)
        /*
         *      Initialize TLS
         */
-       conf->ctx = init_tls_ctx(conf, 1);
+       conf->ctx = tls_init_ctx(conf, 1);
        if (conf->ctx == NULL) {
                goto error;
        }