Skip to content

Commit

Permalink
spnego_gssapi: implement TLS channel bindings for openssl
Browse files Browse the repository at this point in the history
This requires krb5 >= 1.19 because otherwise channel bindings won't be
forwarded through SPNEGO.
  • Loading branch information
steffen-kiess committed Dec 17, 2021
1 parent 1827089 commit 0ad6f58
Show file tree
Hide file tree
Showing 16 changed files with 145 additions and 13 deletions.
14 changes: 14 additions & 0 deletions lib/http_negotiate.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "sendf.h"
#include "http_negotiate.h"
#include "vauth/vauth.h"
#include "vtls/vtls.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
Expand Down Expand Up @@ -104,11 +105,24 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
neg_ctx->sslContext = conn->sslContext;
#endif
#ifdef HAVE_GSSAPI
result = Curl_ssl_get_tls_server_end_point(
data, FIRSTSOCKET, &neg_ctx->channel_binding_data,
&neg_ctx->channel_binding_data_len);
if(result) {
Curl_http_auth_cleanup_negotiate(conn);
return result;
}
#endif

/* Initialize the security context and decode our challenge */
result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
host, header, neg_ctx);

#ifdef HAVE_GSSAPI
free(neg_ctx->channel_binding_data);
#endif

if(result)
Curl_http_auth_cleanup_negotiate(conn);

Expand Down
2 changes: 2 additions & 0 deletions lib/urldata.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ struct negotiatedata {
gss_ctx_id_t context;
gss_name_t spn;
gss_buffer_desc output_token;
char *channel_binding_data;
size_t channel_binding_data_len;
#else
#ifdef USE_WINDOWS_SSPI
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
Expand Down
12 changes: 11 additions & 1 deletion lib/vauth/spnego_gssapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
gss_channel_bindings_t chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
struct gss_channel_bindings_struct chan;

(void) user;
(void) password;
Expand Down Expand Up @@ -146,13 +148,21 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
input_token.length = chlglen;
}

/* Set channel binding data */
if(nego->channel_binding_data) {
memset(&chan, 0, sizeof(struct gss_channel_bindings_struct));
chan.application_data.length = nego->channel_binding_data_len;
chan.application_data.value = nego->channel_binding_data;
chan_bindings = &chan;
}

/* Generate our challenge-response message */
major_status = Curl_gss_init_sec_context(data,
&minor_status,
&nego->context,
nego->spn,
&Curl_spnego_mech_oid,
GSS_C_NO_CHANNEL_BINDINGS,
chan_bindings,
&input_token,
&output_token,
TRUE,
Expand Down
3 changes: 2 additions & 1 deletion lib/vtls/bearssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,8 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_false_start, /* false_start */
bearssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif /* USE_BEARSSL */
3 changes: 2 additions & 1 deletion lib/vtls/gskit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1319,7 +1319,8 @@ const struct Curl_ssl Curl_ssl_gskit = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif /* USE_GSKIT */
3 changes: 2 additions & 1 deletion lib/vtls/gtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1654,7 +1654,8 @@ const struct Curl_ssl Curl_ssl_gnutls = {
Curl_none_false_start, /* false_start */
gtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif /* USE_GNUTLS */
3 changes: 2 additions & 1 deletion lib/vtls/mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,8 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
Curl_none_false_start, /* false_start */
mbedtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif /* USE_MBEDTLS */
3 changes: 2 additions & 1 deletion lib/vtls/mesalink.c
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,8 @@ const struct Curl_ssl Curl_ssl_mesalink = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif
3 changes: 2 additions & 1 deletion lib/vtls/nss.c
Original file line number Diff line number Diff line change
Expand Up @@ -2476,7 +2476,8 @@ const struct Curl_ssl Curl_ssl_nss = {
nss_false_start, /* false_start */
nss_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif /* USE_NSS */
72 changes: 71 additions & 1 deletion lib/vtls/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4580,6 +4580,75 @@ static void ossl_disassociate_connection(struct Curl_easy *data,
}
}

static CURLcode ossl_get_tls_server_end_point(struct Curl_easy *data,
int sockindex, char **binding,
size_t *len)
{
/* required for X509_get_signature_nid support */
#if OPENSSL_VERSION_NUMBER > 0x10100000L
struct connectdata *conn = data->conn;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
const char prefix[] = "tls-server-end-point:";

X509 *cert;
int algo_nid;
const EVP_MD *algo_type;
const char *algo_name;
unsigned int length;
u_char buf[EVP_MAX_MD_SIZE];

cert = SSL_get_peer_certificate(backend->handle);
if(!cert) {
/* No server certificate, don't do channel binding */
*binding = NULL;
*len = 0;
return CURLE_OK;
}

if(!OBJ_find_sigid_algs(X509_get_signature_nid(cert), &algo_nid, NULL)) {
failf(data,
"Unable to find digest NID for certificate signature algorithm");
return CURLE_SSL_INVALIDCERTSTATUS;
}

/* https://datatracker.ietf.org/doc/html/rfc5929#section-4.1 */
if(algo_nid == NID_md5 || algo_nid == NID_sha1) {
algo_type = EVP_sha256();
}
else {
algo_type = EVP_get_digestbynid(algo_nid);
if(!algo_type) {
algo_name = OBJ_nid2sn(algo_nid);
failf(data, "Could not find digest algorithm %s (NID %d)",
algo_name ? algo_name : "(null)", algo_nid);
return CURLE_SSL_INVALIDCERTSTATUS;
}
}

if(!X509_digest(cert, algo_type, buf, &length)) {
failf(data, "X509_digest() failed");
return CURLE_SSL_INVALIDCERTSTATUS;
}

*binding = malloc(sizeof(prefix) - 1 + length);
if(!*binding)
return CURLE_OUT_OF_MEMORY;
memcpy(*binding, prefix, sizeof(prefix) - 1);
memcpy(*binding + sizeof(prefix) - 1, buf, length);
*len = sizeof(prefix) - 1 + length;

return CURLE_OK;
#else
/* No X509_get_signature_nid support */
(void)data; /* unused */
(void)sockindex; /* unused */
*binding = NULL;
*len = 0;
return CURLE_OK;
#endif
}

const struct Curl_ssl Curl_ssl_openssl = {
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */

Expand Down Expand Up @@ -4620,7 +4689,8 @@ const struct Curl_ssl Curl_ssl_openssl = {
NULL, /* sha256sum */
#endif
ossl_associate_connection, /* associate_connection */
ossl_disassociate_connection /* disassociate_connection */
ossl_disassociate_connection, /* disassociate_connection */
ossl_get_tls_server_end_point /* get_tls_server_end_point */
};

#endif /* USE_OPENSSL */
3 changes: 2 additions & 1 deletion lib/vtls/rustls.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,8 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif /* USE_RUSTLS */
3 changes: 2 additions & 1 deletion lib/vtls/schannel.c
Original file line number Diff line number Diff line change
Expand Up @@ -2458,7 +2458,8 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_false_start, /* false_start */
schannel_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif /* USE_SCHANNEL */
3 changes: 2 additions & 1 deletion lib/vtls/sectransp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3500,7 +3500,8 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_false_start, /* false_start */
sectransp_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#ifdef __clang__
Expand Down
14 changes: 13 additions & 1 deletion lib/vtls/vtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,17 @@ void Curl_ssl_detach_conn(struct Curl_easy *data,
}
}

CURLcode Curl_ssl_get_tls_server_end_point(struct Curl_easy *data,
int sockindex, char **binding,
size_t *len)
{
if(Curl_ssl->get_tls_server_end_point)
return Curl_ssl->get_tls_server_end_point(data, sockindex, binding, len);
*binding = NULL;
*len = 0;
return CURLE_OK;
}

void Curl_ssl_close_all(struct Curl_easy *data)
{
/* kill the session ID cache if not shared */
Expand Down Expand Up @@ -1272,7 +1283,8 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

const struct Curl_ssl *Curl_ssl =
Expand Down
14 changes: 14 additions & 0 deletions lib/vtls/vtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ struct Curl_ssl {
struct connectdata *conn,
int sockindex);
void (*disassociate_connection)(struct Curl_easy *data, int sockindex);

CURLcode (*get_tls_server_end_point)(struct Curl_easy *data, int sockindex,
char **binding, size_t *len);
};

#ifdef USE_SSL
Expand Down Expand Up @@ -295,6 +298,17 @@ void Curl_ssl_associate_conn(struct Curl_easy *data,
void Curl_ssl_detach_conn(struct Curl_easy *data,
struct connectdata *conn);

/* Return the tls-server-end-point channel binding, including the
* 'tls-server-end-point:' prefix.
* If successful, a pointer to the data is stored in *binding and the length of
* the data is stored in *len. The caller must free the data with free().
* If getting the channel binding is not supported, *binding will be set to
* NULL.
*/
CURLcode Curl_ssl_get_tls_server_end_point(struct Curl_easy *data,
int sockindex, char **binding,
size_t *len);

#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */

#else /* if not USE_SSL */
Expand Down
3 changes: 2 additions & 1 deletion lib/vtls/wolfssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1207,7 +1207,8 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
Curl_none_false_start, /* false_start */
wolfssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL /* disassociate_connection */
NULL, /* disassociate_connection */
NULL /* get_tls_server_end_point */
};

#endif

0 comments on commit 0ad6f58

Please sign in to comment.