session server tls UPDATE refactor wraps
diff --git a/src/session_server_tls.c b/src/session_server_tls.c
index cb40ca9..8b47e36 100644
--- a/src/session_server_tls.c
+++ b/src/session_server_tls.c
@@ -102,8 +102,8 @@
static void *
nc_base64der_to_cert(const char *in)
{
- char *buf;
- void *cert = NULL;
+ char *buf = NULL;
+ void *cert;
NC_CHECK_ARG_RET(NULL, in, NULL);
@@ -117,11 +117,11 @@
return cert;
}
-int
+static int
nc_base64der_to_cert_add_to_store(const char *in, void *cert_store)
{
int ret;
- char *buf;
+ char *buf = NULL;
NC_CHECK_ARG_RET(NULL, in, cert_store, 1);
@@ -136,9 +136,9 @@
}
static void *
-nc_base64der_to_privatekey(const char *in, const char *key_str)
+nc_base64der_to_privkey(const char *in, const char *key_str)
{
- char *buf;
+ char *buf = NULL;
void *pkey;
NC_CHECK_ARG_RET(NULL, in, NULL);
@@ -154,7 +154,7 @@
return pkey;
}
-char *
+static char *
nc_server_tls_digest_to_hex(const unsigned char *digest, unsigned int digest_len)
{
unsigned int i;
@@ -171,7 +171,7 @@
return hex;
}
-char *
+static char *
nc_server_tls_md5(void *cert)
{
int rc;
@@ -188,7 +188,7 @@
return nc_server_tls_digest_to_hex(buf, buf_len);
}
-char *
+static char *
nc_server_tls_sha1(void *cert)
{
int rc;
@@ -205,7 +205,7 @@
return nc_server_tls_digest_to_hex(buf, buf_len);
}
-char *
+static char *
nc_server_tls_sha224(void *cert)
{
int rc;
@@ -222,7 +222,7 @@
return nc_server_tls_digest_to_hex(buf, buf_len);
}
-char *
+static char *
nc_server_tls_sha256(void *cert)
{
int rc;
@@ -239,7 +239,7 @@
return nc_server_tls_digest_to_hex(buf, buf_len);
}
-char *
+static char *
nc_server_tls_sha384(void *cert)
{
int rc;
@@ -256,7 +256,7 @@
return nc_server_tls_digest_to_hex(buf, buf_len);
}
-char *
+static char *
nc_server_tls_sha512(void *cert)
{
int rc;
@@ -441,11 +441,10 @@
}
for (i = 0; i < cert_count; i++) {
- cert = nc_tls_base64_to_cert_wrap(certs[i].data);
- if (!cert) {
- /* TODO skip? */
- continue;
- }
+ /* import stored cert */
+ cert = nc_base64der_to_cert(certs[i].data);
+
+ /* compare stored with received */
ret = nc_server_tls_certs_match_wrap(peer_cert, cert);
nc_tls_cert_destroy_wrap(cert);
if (ret) {
@@ -459,6 +458,95 @@
}
int
+nc_server_tls_get_username_from_cert(void *cert, NC_TLS_CTN_MAPTYPE map_type, char **username)
+{
+ char *subject, *cn, *san_value = NULL;
+ void *sans;
+ int i, nsans = 0, rc;
+ NC_TLS_CTN_MAPTYPE san_type = 0;
+
+#ifdef HAVE_LIBMEDTLS
+ char rdn_separator = ',';
+#else
+ char rdn_separator = '/';
+#endif
+
+ if (map_type == NC_TLS_CTN_COMMON_NAME) {
+ subject = nc_server_tls_get_subject_wrap(cert);
+ if (!subject) {
+ return -1;
+ }
+
+ cn = strstr(subject, "CN=");
+ if (!cn) {
+ WRN(NULL, "Certificate does not include the commonName field.");
+ free(subject);
+ return 1;
+ }
+
+ /* skip "CN=" */
+ cn += 3;
+ if (strchr(cn, rdn_separator)) {
+ *strchr(cn, rdn_separator) = '\0';
+ }
+ *username = strdup(cn);
+ free(subject);
+ NC_CHECK_ERRMEM_RET(!*username, -1);
+ } else {
+ sans = nc_tls_get_sans_wrap(cert);
+ if (!sans) {
+ WRN(NULL, "Certificate has no SANs or failed to retrieve them.");
+ return 1;
+ }
+ nsans = nc_tls_get_num_sans_wrap(sans);
+
+ for (i = 0; i < nsans; i++) {
+ if ((rc = nc_tls_get_san_value_type_wrap(sans, i, &san_value, &san_type))) {
+ if (rc == -1) {
+ /* fatal error */
+ nc_tls_sans_destroy_wrap(sans);
+ return -1;
+ }
+
+ /* got a type that we dont care about */
+ continue;
+ }
+
+ if ((map_type == NC_TLS_CTN_SAN_ANY) || (map_type == san_type)) {
+ /* found a match */
+ *username = san_value;
+ break;
+ }
+ free(san_value);
+ }
+
+ nc_tls_sans_destroy_wrap(sans);
+
+ if (i == nsans) {
+ switch (map_type) {
+ case NC_TLS_CTN_SAN_RFC822_NAME:
+ WRN(NULL, "Certificate does not include the SAN rfc822Name field.");
+ break;
+ case NC_TLS_CTN_SAN_DNS_NAME:
+ WRN(NULL, "Certificate does not include the SAN dNSName field.");
+ break;
+ case NC_TLS_CTN_SAN_IP_ADDRESS:
+ WRN(NULL, "Certificate does not include the SAN iPAddress field.");
+ break;
+ case NC_TLS_CTN_SAN_ANY:
+ WRN(NULL, "Certificate does not include any relevant SAN fields.");
+ break;
+ default:
+ break;
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
nc_server_tls_verify_cert(void *cert, int depth, int self_signed, struct nc_tls_verify_cb_data *cb_data)
{
int ret = 0, i;
@@ -482,7 +570,7 @@
if (depth == 0) {
if (self_signed) {
/* peer cert is not trusted, so it must match any configured end-entity cert
- * on the given endpoint in order for the cert to be authenticated */
+ * on the given endpoint in order for the client to be authenticated */
ret = nc_server_tls_verify_peer_cert(cert, &opts->ee_certs);
if (ret) {
/* we can still check the referenced endpoint's ee certs */
@@ -503,6 +591,7 @@
}
}
+ /* get matching ctn entries */
ret = nc_server_tls_cert_to_name(opts->ctn, cert, &cb_data->ctn_data);
if (ret == -1) {
/* fatal error */
@@ -524,24 +613,35 @@
}
}
- /* ctn */
+ /* obtain username from matched ctn entries */
if (depth == 0) {
for (i = 0; i < cb_data->ctn_data.matched_ctn_count; i++) {
if (cb_data->ctn_data.matched_ctn_type[i] == NC_TLS_CTN_SPECIFIED) {
session->username = strdup(cb_data->ctn_data.username);
- NC_CHECK_ERRMEM_RET(!session->username, -1);
+ NC_CHECK_ERRMEM_GOTO(!session->username, ret = -1, cleanup);
} else {
- ret = nc_server_tls_get_username_from_cert_wrap(cert, cb_data->ctn_data.matched_ctn_type[i], &session->username);
+ ret = nc_server_tls_get_username_from_cert(cert, cb_data->ctn_data.matched_ctn_type[i], &session->username);
if (ret == -1) {
+ /* fatal error */
goto cleanup;
+ } else if (!ret) {
+ /* username obtained */
+ break;
}
}
}
+ if (session->username) {
+ VRB(NULL, "Cert verify CTN: new client username recognized as \"%s\".", session->username);
+ } else {
+ VRB(NULL, "Cert verify CTN: unsuccessful, dropping the new client.");
+ ret = 1;
+ goto cleanup;
+ }
}
- if (server_opts.user_verify_clb && !server_opts.user_verify_clb(session)) {
+ if (session->username && server_opts.user_verify_clb && !server_opts.user_verify_clb(session)) {
VRB(session, "Cert verify: user verify callback revoked authorization.");
- ret = -1;
+ ret = 1;
goto cleanup;
}
@@ -576,6 +676,8 @@
void *cert = NULL;
void *pkey = NULL;
+ *srv_cert = *srv_pkey = NULL;
+
/* get data needed for setting the server cert */
if (opts->store == NC_STORE_LOCAL) {
/* local definition */
@@ -600,7 +702,7 @@
return 1;
}
- pkey = nc_base64der_to_privatekey(privkey_data, nc_privkey_format_to_str(privkey_type));
+ pkey = nc_base64der_to_privkey(privkey_data, nc_privkey_format_to_str(privkey_type));
if (!pkey) {
nc_tls_cert_destroy_wrap(cert);
return 1;
@@ -637,19 +739,19 @@
/* set uri */
if (curl_easy_setopt(handle, CURLOPT_URL, url)) {
ERR(NULL, "Setting URI \"%s\" to download CRL from failed.", url);
- return -1;
+ return 1;
}
/* set err buf */
if (curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, err_buf)) {
ERR(NULL, "Setting CURL error buffer option failed.");
- return -1;
+ return 1;
}
/* download */
if (curl_easy_perform(handle)) {
ERR(NULL, "Downloading CRL from \"%s\" failed (%s).", url, err_buf);
- return -1;
+ return 1;
}
return 0;
@@ -665,65 +767,26 @@
*handle = curl_easy_init();
if (!*handle) {
ERR(NULL, "Initializing CURL failed.");
- return -1;
+ return 1;
}
if (curl_easy_setopt(*handle, CURLOPT_WRITEFUNCTION, nc_server_tls_curl_cb)) {
ERR(NULL, "Setting curl callback failed.");
- return -1;
+ return 1;
}
if (curl_easy_setopt(*handle, CURLOPT_WRITEDATA, data)) {
ERR(NULL, "Setting curl callback data failed.");
- return -1;
+ return 1;
}
return 0;
}
static int
-nc_server_tls_crl_cert_ext(void *cert_store, void *crl_store)
+nc_server_tls_crl_path(const char *path, void *cert_store, void *crl_store)
{
- int ret = 0;
- CURL *handle = NULL;
- struct nc_curl_data downloaded = {0};
- char **uris = NULL;
- int uri_count = 0, i;
-
- /* init curl */
- ret = nc_server_tls_curl_init(&handle, &downloaded);
- if (ret) {
- goto cleanup;
- }
-
- ret = nc_server_tls_get_crl_distpoint_uris_wrap(cert_store, &uris, &uri_count);
- if (ret) {
- goto cleanup;
- }
-
- for (i = 0; i < uri_count; i++) {
- VRB(NULL, "Downloading CRL from \"%s\".", uris[i]);
- ret = nc_server_tls_curl_fetch(handle, uris[i]);
- if (ret) {
- /* failed to download the CRL from this entry, try the next entry */
- WRN(NULL, "Failed to fetch CRL from \"%s\".", uris[i]);
- continue;
- }
-
- /* convert the downloaded data to CRL and add it to the store */
- ret = nc_server_tls_add_crl_to_store_wrap(downloaded.data, downloaded.size, cert_store, crl_store);
- if (ret) {
- goto cleanup;
- }
- }
-
-cleanup:
- for (i = 0; i < uri_count; i++) {
- free(uris[i]);
- }
- free(uris);
- curl_easy_cleanup(handle);
- return ret;
+ return nc_tls_import_crl_path_wrap(path, cert_store, crl_store);
}
static int
@@ -758,11 +821,57 @@
return ret;
}
+static int
+nc_server_tls_crl_cert_ext(void *cert_store, void *crl_store)
+{
+ int ret = 0;
+ CURL *handle = NULL;
+ struct nc_curl_data downloaded = {0};
+ char **uris = NULL;
+ int uri_count = 0, i;
+
+ /* init curl */
+ ret = nc_server_tls_curl_init(&handle, &downloaded);
+ if (ret) {
+ goto cleanup;
+ }
+
+ /* get all the uris we can, even though some may point to the same CRL */
+ ret = nc_server_tls_get_crl_distpoint_uris_wrap(cert_store, &uris, &uri_count);
+ if (ret) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < uri_count; i++) {
+ VRB(NULL, "Downloading CRL from \"%s\".", uris[i]);
+ ret = nc_server_tls_curl_fetch(handle, uris[i]);
+ if (ret) {
+ /* failed to download the CRL from this entry, try the next entry */
+ WRN(NULL, "Failed to fetch CRL from \"%s\".", uris[i]);
+ continue;
+ }
+
+ /* convert the downloaded data to CRL and add it to the store */
+ ret = nc_server_tls_add_crl_to_store_wrap(downloaded.data, downloaded.size, cert_store, crl_store);
+ if (ret) {
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ for (i = 0; i < uri_count; i++) {
+ free(uris[i]);
+ }
+ free(uris);
+ curl_easy_cleanup(handle);
+ return ret;
+}
+
int
nc_server_tls_load_crl(struct nc_server_tls_opts *opts, void *cert_store, void *crl_store)
{
if (opts->crl_path) {
- if (nc_server_tls_crl_path_wrap(opts->crl_path, cert_store, crl_store)) {
+ if (nc_server_tls_crl_path(opts->crl_path, cert_store, crl_store)) {
return 1;
}
} else if (opts->crl_url) {
@@ -809,11 +918,16 @@
nc_server_tls_accept_check(int accept_ret, void *tls_session)
{
uint32_t verify;
+ char *err;
/* check certificate verification result */
verify = nc_tls_get_verify_result_wrap(tls_session);
if (!verify && (accept_ret == 1)) {
VRB(NULL, "Client certificate verified.");
+ } else if (verify) {
+ err = nc_tls_verify_error_string_wrap(verify);
+ ERR(NULL, "Client certificate error (%s).", err);
+ free(err);
}
if (accept_ret != 1) {
@@ -837,14 +951,6 @@
/* set verify cb data */
cb_data.session = session;
cb_data.opts = opts;
- cb_data.ee_certs = &opts->ee_certs;
- if (opts->referenced_endpt_name) {
- if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) {
- ERRINT;
- return 1;
- }
- cb_data.referenced_ee_certs = &referenced_endpt->opts.tls->ee_certs;
- }
/* prepare TLS context from which a session will be created */
tls_cfg = nc_server_tls_config_new_wrap();
@@ -872,6 +978,11 @@
/* load referenced endpoint's trusted CA certs if set */
if (opts->referenced_endpt_name) {
+ if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) {
+ ERR(session, "Referenced endpoint \"%s\" not found.", opts->referenced_endpt_name);
+ goto fail;
+ }
+
if (nc_server_tls_load_trusted_certs(&referenced_endpt->opts.tls->ca_certs, cert_store)) {
ERR(session, "Loading server CA certs from referenced endpoint failed.");
goto fail;
@@ -900,6 +1011,11 @@
}
}
+ /* set supported cipher suites */
+ if (opts->ciphers) {
+ nc_server_tls_set_cipher_suites_wrap(tls_cfg, opts->ciphers);
+ }
+
/* init TLS context and store data which may be needed later in it */
if (nc_tls_init_ctx_wrap(&session->ti.tls.ctx, sock, srv_cert, srv_pkey, cert_store, crl_store)) {
goto fail;
@@ -912,13 +1028,14 @@
if (nc_tls_setup_config_wrap(tls_cfg, NC_SERVER, &session->ti.tls.ctx)) {
goto fail;
} // TODO free openssl shit
+ session->ti.tls.config = tls_cfg;
+ tls_cfg = NULL;
/* fill session data and create TLS session from config */
- session->ti_type = NC_TI_OPENSSL; // TODO: prejmenovat
- if (!(session->ti.tls.session = nc_tls_session_new_wrap(tls_cfg))) {
+ session->ti_type = NC_TI_TLS;
+ if (!(session->ti.tls.session = nc_tls_session_new_wrap(session->ti.tls.config))) {
goto fail;
}
- session->ti.tls.config = tls_cfg;
/* set verify callback and its data */
nc_server_tls_set_verify_cb_wrap(session->ti.tls.session, &cb_data);
@@ -926,8 +1043,6 @@
/* set session fd */
nc_server_tls_set_fd_wrap(session->ti.tls.session, sock, &session->ti.tls.ctx);
- /* TODO: ciphers */
-
sock = -1;
/* do the handshake */
@@ -955,7 +1070,11 @@
close(sock);
}
- nc_tls_session_new_cleanup_wrap(tls_cfg, srv_cert, srv_pkey, cert_store, crl_store);
+ nc_tls_config_destroy_wrap(tls_cfg);
+ nc_tls_cert_destroy_wrap(srv_cert);
+ nc_tls_privkey_destroy_wrap(srv_pkey);
+ nc_tls_cert_store_destroy_wrap(cert_store);
+ nc_tls_crl_store_destroy_wrap(crl_store);
if (timeouted) {
return 0;