Skip to content

Commit

Permalink
Add Channel Binding support for GSSAPI/GSS-SPNEGO
Browse files Browse the repository at this point in the history
Signed-off-by: Simo Sorce <simo@redhat.com>
  • Loading branch information
simo5 authored and quanah committed Apr 8, 2020
1 parent 18ff41d commit 975edbb
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 17 deletions.
30 changes: 25 additions & 5 deletions plugins/gssapi.c
Expand Up @@ -830,7 +830,9 @@ gssapi_server_mech_authneg(context_t *text,
gss_buffer_desc name_without_realm;
gss_name_t client_name_MN = NULL, without = NULL;
gss_OID mech_type;

gss_channel_bindings_t bindings = GSS_C_NO_CHANNEL_BINDINGS;
struct gss_channel_bindings_struct cb = {0};

input_token = &real_input_token;
output_token = &real_output_token;
output_token->value = NULL; output_token->length = 0;
Expand Down Expand Up @@ -902,14 +904,20 @@ gssapi_server_mech_authneg(context_t *text,
real_input_token.length = clientinlen;
}

if (params->cbinding != NULL) {
cb.application_data.length = params->cbinding->len;
cb.application_data.value = params->cbinding->data;
bindings = &cb;
}


GSS_LOCK_MUTEX_CTX(params->utils, text);
maj_stat =
gss_accept_sec_context(&min_stat,
&(text->gss_ctx),
server_creds,
input_token,
GSS_C_NO_CHANNEL_BINDINGS,
bindings,
&text->client_name,
&mech_type,
output_token,
Expand Down Expand Up @@ -1505,7 +1513,8 @@ static sasl_server_plug_t gssapi_server_plugins[] =
| SASL_SEC_PASS_CREDENTIALS,
SASL_FEAT_WANT_CLIENT_FIRST
| SASL_FEAT_ALLOWS_PROXY
| SASL_FEAT_DONTUSE_USERPASSWD, /* features */
| SASL_FEAT_DONTUSE_USERPASSWD
| SASL_FEAT_CHANNEL_BINDING, /* features */
NULL, /* glob_context */
&gssapi_server_mech_new, /* mech_new */
&gssapi_server_mech_step, /* mech_step */
Expand All @@ -1529,6 +1538,7 @@ static sasl_server_plug_t gssapi_server_plugins[] =
SASL_FEAT_WANT_CLIENT_FIRST
| SASL_FEAT_ALLOWS_PROXY
| SASL_FEAT_DONTUSE_USERPASSWD
| SASL_FEAT_CHANNEL_BINDING
| SASL_FEAT_SUPPORTS_HTTP, /* features */
&gss_spnego_oid, /* glob_context */
&gssapi_server_mech_new, /* mech_new */
Expand Down Expand Up @@ -1662,6 +1672,8 @@ static int gssapi_client_mech_step(void *conn_context,
input_token->value = NULL;
input_token->length = 0;
gss_cred_id_t client_creds = (gss_cred_id_t)params->gss_creds;
gss_channel_bindings_t bindings = GSS_C_NO_CHANNEL_BINDINGS;
struct gss_channel_bindings_struct cb = {0};

if (clientout)
*clientout = NULL;
Expand Down Expand Up @@ -1777,6 +1789,12 @@ static int gssapi_client_mech_step(void *conn_context,
req_flags = req_flags | GSS_C_DELEG_FLAG;
}

if (params->cbinding != NULL) {
cb.application_data.length = params->cbinding->len;
cb.application_data.value = params->cbinding->data;
bindings = &cb;
}

GSS_LOCK_MUTEX_CTX(params->utils, text);
maj_stat = gss_init_sec_context(&min_stat,
client_creds, /* GSS_C_NO_CREDENTIAL */
Expand All @@ -1785,7 +1803,7 @@ static int gssapi_client_mech_step(void *conn_context,
text->mech_type,
req_flags,
0,
GSS_C_NO_CHANNEL_BINDINGS,
bindings,
input_token,
NULL,
output_token,
Expand Down Expand Up @@ -2190,7 +2208,8 @@ static sasl_client_plug_t gssapi_client_plugins[] =
| SASL_SEC_PASS_CREDENTIALS, /* security_flags */
SASL_FEAT_NEEDSERVERFQDN
| SASL_FEAT_WANT_CLIENT_FIRST
| SASL_FEAT_ALLOWS_PROXY, /* features */
| SASL_FEAT_ALLOWS_PROXY
| SASL_FEAT_CHANNEL_BINDING, /* features */
gssapi_required_prompts, /* required_prompts */
GSS_C_NO_OID, /* glob_context */
&gssapi_client_mech_new, /* mech_new */
Expand All @@ -2213,6 +2232,7 @@ static sasl_client_plug_t gssapi_client_plugins[] =
SASL_FEAT_NEEDSERVERFQDN
| SASL_FEAT_WANT_CLIENT_FIRST
| SASL_FEAT_ALLOWS_PROXY
| SASL_FEAT_CHANNEL_BINDING
| SASL_FEAT_SUPPORTS_HTTP, /* features */
gssapi_required_prompts, /* required_prompts */
&gss_spnego_oid, /* glob_context */
Expand Down
93 changes: 85 additions & 8 deletions tests/runtests.py
@@ -1,6 +1,7 @@
#!/usr/bin/python3

import argparse
import base64
import os
import shutil
import signal
Expand Down Expand Up @@ -126,14 +127,7 @@ def setup_kdc(testdir, env):

return kdc, env


def gssapi_tests(testdir):
""" SASL/GSSAPI Tests """
env = setup_socket_wrappers(testdir)
kdc, kenv = setup_kdc(testdir, env)
#print("KDC: {}, ENV: {}".format(kdc, kenv))
kenv['KRB5_TRACE'] = os.path.join(testdir, 'trace.log')

def gssapi_basic_test(kenv):
try:
srv = subprocess.Popen(["../tests/t_gssapi_srv"],
stdout=subprocess.PIPE,
Expand All @@ -155,11 +149,94 @@ def gssapi_tests(testdir):
srv.returncode, srv.stderr.read().decode('utf-8')))
except Exception as e:
print("FAIL: {}".format(e))
return

print("PASS: CLI({}) SRV({})".format(
cli.stdout.read().decode('utf-8').strip(),
srv.stdout.read().decode('utf-8').strip()))

def gssapi_channel_binding_test(kenv):
try:
bindings = base64.b64encode("MATCHING CBS".encode('utf-8'))
srv = subprocess.Popen(["../tests/t_gssapi_srv", "-c", bindings],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=kenv)
srv.stdout.readline() # Wait for srv to say it is ready
cli = subprocess.Popen(["../tests/t_gssapi_cli", "-c", bindings],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=kenv)
try:
cli.wait(timeout=5)
srv.wait(timeout=5)
except Exception as e:
print("Failed on {}".format(e));
cli.kill()
srv.kill()
if cli.returncode != 0 or srv.returncode != 0:
raise Exception("CLI ({}): {} --> SRV ({}): {}".format(
cli.returncode, cli.stderr.read().decode('utf-8'),
srv.returncode, srv.stderr.read().decode('utf-8')))
except Exception as e:
print("FAIL: {}".format(e))
return

print("PASS: CLI({}) SRV({})".format(
cli.stdout.read().decode('utf-8').strip(),
srv.stdout.read().decode('utf-8').strip()))

def gssapi_channel_binding_mismatch_test(kenv):
result = "FAIL"
try:
bindings = base64.b64encode("SRV CBS".encode('utf-8'))
srv = subprocess.Popen(["../tests/t_gssapi_srv", "-c", bindings],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=kenv)
srv.stdout.readline() # Wait for srv to say it is ready
bindings = base64.b64encode("CLI CBS".encode('utf-8'))
cli = subprocess.Popen(["../tests/t_gssapi_cli", "-c", bindings],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=kenv)
try:
cli.wait(timeout=5)
srv.wait(timeout=5)
except Exception as e:
print("Failed on {}".format(e));
cli.kill()
srv.kill()
if cli.returncode != 0 or srv.returncode != 0:
cli_err = cli.stderr.read().decode('utf-8').strip()
srv_err = srv.stderr.read().decode('utf-8').strip()
if "authentication failure" in srv_err:
result = "PASS"
raise Exception("CLI ({}): {} --> SRV ({}): {}".format(
cli.returncode, cli_err, srv.returncode, srv_err))
except Exception as e:
print("{}: {}".format(result, e))
return

print("FAIL: This test should fail [CLI({}) SRV({})]".format(
cli.stdout.read().decode('utf-8').strip(),
srv.stdout.read().decode('utf-8').strip()))

def gssapi_tests(testdir):
""" SASL/GSSAPI Tests """
env = setup_socket_wrappers(testdir)
kdc, kenv = setup_kdc(testdir, env)
#print("KDC: {}, ENV: {}".format(kdc, kenv))
kenv['KRB5_TRACE'] = os.path.join(testdir, 'trace.log')

print('GSSAPI BASIC:')
print(' ', end='')
gssapi_basic_test(kenv)

print('GSSAPI CHANNEL BINDING:')
print(' ', end='')
gssapi_channel_binding_test(kenv)

print('GSSAPI CHANNEL BINDING MISMTACH:')
print(' ', end='')
gssapi_channel_binding_mismatch_test(kenv)

os.killpg(kdc.pid, signal.SIGTERM)


Expand Down
14 changes: 14 additions & 0 deletions tests/t_common.c
Expand Up @@ -65,4 +65,18 @@ int getpath(void *context __attribute__((unused)), const char **path)
return SASL_OK;
}

void parse_cb(sasl_channel_binding_t *cb, char *buf, unsigned max, char *in)
{
unsigned len;
int r;

r = sasl_decode64(in, strlen(in), buf, max, &len);
if (r != SASL_OK) {
saslerr(r, "failed to parse channel bindings");
exit(-1);
}
cb->name = "TEST BINDINGS";
cb->critical = 0;
cb->data = (unsigned char *)buf;
cb->len = len;
}
2 changes: 2 additions & 0 deletions tests/t_common.h
Expand Up @@ -7,9 +7,11 @@
#include <sys/socket.h>

#include <sasl.h>
#include <saslutil.h>

void s_error(const char *hdr, ssize_t ret, ssize_t len, int err);
void send_string(int sd, const char *s, unsigned int l);
void recv_string(int sd, char *buf, unsigned int *buflen);
void saslerr(int why, const char *what);
int getpath(void *context __attribute__((unused)), const char **path);
void parse_cb(sasl_channel_binding_t *cb, char *buf, unsigned max, char *in);
21 changes: 19 additions & 2 deletions tests/t_gssapi_cli.c
Expand Up @@ -13,6 +13,7 @@

#include <arpa/inet.h>
#include <saslplug.h>
#include <saslutil.h>

static int setup_socket(void)
{
Expand All @@ -32,16 +33,28 @@ static int setup_socket(void)
return sock;
}

int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
int main(int argc, char *argv[])
{
sasl_callback_t callbacks[2] = {};
char buf[8192];
const char *chosenmech;
sasl_conn_t *conn;
const char *data;
unsigned int len;
sasl_channel_binding_t cb = {0};
char cb_buf[256];
int sd;
int r;
int c, r;

while ((c = getopt(argc, argv, "c:")) != EOF) {
switch (c) {
case 'c':
parse_cb(&cb, cb_buf, 256, optarg);
break;
default:
break;
}
}

/* initialize the sasl library */
callbacks[0].id = SASL_CB_GETPATH;
Expand All @@ -60,6 +73,10 @@ int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
exit(-1);
}

if (cb.name) {
sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
}

r = sasl_client_start(conn, "GSSAPI", NULL, &data, &len, &chosenmech);
if (r != SASL_OK && r != SASL_CONTINUE) {
saslerr(r, "starting SASL negotiation");
Expand Down
21 changes: 19 additions & 2 deletions tests/t_gssapi_srv.c
Expand Up @@ -44,15 +44,28 @@ static int setup_socket(void)
return sd;
}

int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
int main(int argc, char *argv[])
{
sasl_callback_t callbacks[2] = {};
char buf[8192];
sasl_conn_t *conn;
const char *data;
unsigned int len;
sasl_channel_binding_t cb = {0};
unsigned char cb_buf[256];
int sd;
int r;
int c, r;

while ((c = getopt(argc, argv, "c:")) != EOF) {
switch (c) {
case 'c':
parse_cb(&cb, cb_buf, 256, optarg);
break;
default:
break;
}
}


/* initialize the sasl library */
callbacks[0].id = SASL_CB_GETPATH;
Expand All @@ -72,6 +85,10 @@ int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
exit(-1);
}

if (cb.name) {
sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
}

sd = setup_socket();

len = 8192;
Expand Down

0 comments on commit 975edbb

Please sign in to comment.