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, const char *identity,
+ unsigned char *psk, int max_psk_len)
+{
+ unsigned int psk_len;
+ fr_tls_server_conf_t *conf;
+
+ 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) {
+ return 0;
+ }
+
+ psk_len = strlen(conf->psk_password);
+ if (psk_len > (2 * max_psk_len)) return 0;
+
+ return fr_hex2bin(conf->psk_password, psk, psk_len);
+}
+
+static unsigned int psk_client_callback(SSL *ssl, UNUSED const char *hint,
+ char *identity, unsigned int max_identity_len,
+ unsigned char *psk, unsigned int max_psk_len)
+{
+ unsigned int psk_len;
+ fr_tls_server_conf_t *conf;
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl,
+ FR_TLS_EX_INDEX_CONF);
+ if (!conf) return 0;
+
+ psk_len = strlen(conf->psk_password);
+ if (psk_len > (2 * max_psk_len)) return 0;
+
+ strlcpy(identity, conf->psk_identity, max_identity_len);
+
+ return fr_hex2bin(conf->psk_password, psk, psk_len);
+}
+
+#endif
+
tls_session_t *tls_new_client_session(fr_tls_server_conf_t *conf, int fd)
{
int verify_mode;
offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
{ "private_key_password", PW_TYPE_STRING_PTR,
offsetof(fr_tls_server_conf_t, private_key_password), NULL, NULL },
+#ifdef PSK_MAX_IDENTITY_LEN
+ { "psk_identity", PW_TYPE_STRING_PTR,
+ offsetof(fr_tls_server_conf_t, psk_identity), NULL, NULL },
+ { "psk_hexphrase", PW_TYPE_STRING_PTR,
+ offsetof(fr_tls_server_conf_t, psk_password), NULL, NULL },
+#endif
{ "dh_file", PW_TYPE_STRING_PTR,
offsetof(fr_tls_server_conf_t, dh_file), NULL, NULL },
{ "random_file", PW_TYPE_STRING_PTR,
static void cbtls_remove_session(UNUSED SSL_CTX *ctx, SSL_SESSION *sess)
{
- int i;
-
size_t size;
char buffer[2 * MAX_SESSION_SIZE + 1];
/*
* For creating certificate attributes.
*/
-static const char *cert_attr_names[5][2] = {
+static const char *cert_attr_names[6][2] = {
{ "TLS-Client-Cert-Serial", "TLS-Cert-Serial" },
{ "TLS-Client-Cert-Expiration", "TLS-Cert-Expiration" },
{ "TLS-Client-Cert-Subject", "TLS-Cert-Subject" },
{ "TLS-Client-Cert-Issuer", "TLS-Cert-Issuer" },
- { "TLS-Client-Cert-Common-Name", "TLS-Cert-Common-Name" }
+ { "TLS-Client-Cert-Common-Name", "TLS-Cert-Common-Name" },
+ { "TLS-Client-Cert-Subject-Alt-Name-Email", "TLS-Cert-Subject-Alt-Name-Email" }
};
#define FR_TLS_SERIAL (0)
#define FR_TLS_SUBJECT (2)
#define FR_TLS_ISSUER (3)
#define FR_TLS_CN (4)
+#define FR_TLS_SAN_EMAIL (5)
/*
* Before trusting a certificate, you must make sure that the
char buf[64];
X509 *client_cert;
SSL *ssl;
- int err, depth, lookup;
+ int err, depth, lookup, loc;
fr_tls_server_conf_t *conf;
int my_ok = ok;
REQUEST *request;
pairmake(cert_attr_names[FR_TLS_CN][lookup], common_name, T_OP_SET));
}
+#ifdef GEN_EMAIL
+ /*
+ * Get the RFC822 Subject Alternative Name
+ */
+ loc = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
+ if (lookup <= 1 && loc >= 0) {
+ X509_EXTENSION *ext = NULL;
+ GENERAL_NAMES *names = NULL;
+ int i;
+
+ if ((ext = X509_get_ext(client_cert, loc)) &&
+ (names = X509V3_EXT_d2i(ext))) {
+ for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
+ GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
+
+ switch (name->type) {
+ case GEN_EMAIL:
+ if (ASN1_STRING_length(name->d.rfc822Name) >= MAX_STRING_LEN)
+ break;
+
+ pairadd(certs,
+ pairmake(cert_attr_names[FR_TLS_SAN_EMAIL][lookup],
+ ASN1_STRING_data(name->d.rfc822Name), T_OP_SET));
+ break;
+ default:
+ /* XXX TODO handle other SAN types */
+ break;
+ }
+ }
+ }
+ if (names != NULL)
+ sk_GENERAL_NAME_free(names);
+ }
+#endif /* GEN_EMAIL */
+
/*
* If the CRL has expired, that might still be OK.
*/
* - Load the Private key & the certificate
* - Set the Context options & Verify options
*/
-static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf)
+static SSL_CTX *init_tls_ctx(fr_tls_server_conf_t *conf, int client)
{
const SSL_METHOD *meth;
SSL_CTX *ctx;
SSL_CTX_set_default_passwd_cb(ctx, cbtls_password);
}
+#ifdef PSK_MAX_IDENTITY_LEN
+ if ((conf->psk_identity && !conf->psk_password) ||
+ (!conf->psk_identity && conf->psk_password) ||
+ (conf->psk_identity && !*conf->psk_identity) ||
+ (conf->psk_password && !*conf->psk_password)) {
+ radlog(L_ERR, "Invalid PSK Configuration: psk_identity or psk_password are empty");
+ return NULL;
+ }
+
+ if (conf->psk_identity) {
+ size_t psk_len, hex_len;
+ char buffer[PSK_MAX_PSK_LEN];
+
+ if (conf->certificate_file ||
+ conf->private_key_password || conf->private_key_file ||
+ conf->ca_file || conf->ca_path) {
+ radlog(L_ERR, "When PSKs are used, No certificate configuration is permitted");
+ return NULL;
+ }
+
+ 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)) {
+ radlog(L_ERR, "psk_hexphrase is too long (max %d)",
+ PSK_MAX_PSK_LEN);
+ return NULL;
+ }
+
+ hex_len = fr_hex2bin(conf->psk_password, buffer, psk_len);
+ if (psk_len != (2 * hex_len)) {
+ radlog(L_ERR, "psk_hexphrase is not all hex");
+ return NULL;
+ }
+
+ goto post_ca;
+ }
+#endif
+
/*
* Load our keys and certificates
*
}
}
+#ifdef PSK_MAX_IDENTITY_LEN
+post_ca:
+#endif
+
/*
* Set ctx_options
*/
if (conf->session_id_name) {
snprintf(conf->session_context_id,
sizeof(conf->session_context_id),
- "FreeRADIUS EAP-TLS %s",
+ "FR eap %s",
conf->session_id_name);
} else {
snprintf(conf->session_context_id,
sizeof(conf->session_context_id),
- "FreeRADIUS EAP-TLS %p", conf);
+ "FR eap %p", conf);
}
/*
/*
* Initialize TLS
*/
- conf->ctx = init_tls_ctx(conf);
+ conf->ctx = init_tls_ctx(conf, 0);
if (conf->ctx == NULL) {
goto error;
}
/*
* Initialize TLS
*/
- conf->ctx = init_tls_ctx(conf);
+ conf->ctx = init_tls_ctx(conf, 1);
if (conf->ctx == NULL) {
goto error;
}