Skip to content

Commit

Permalink
Add sample for callback SASL_CB_SERVER_CHANNEL_BINDING
Browse files Browse the repository at this point in the history
With the callback SASL_CB_SERVER_CHANNEL_BINDING
a server can change the channel binding data to the
desired channel binding type of the client.

sample/client.c
Select the option -d or -D to use the channel
binding type "tls-server-end-point".
Or select the option -c or -C to use the channel
binding type "tls-unique".
Options -C or -D force client and server to use
channel binding.

sample/server.c
select option -c to activate channel binding
type "tls-unique".
Option -C forces clients to use channel binding.
Via callback "my_select_binding" the server changes
the binding type to "tls-server-end-point" if
required.

Note that client/server must use the binding type:
- "tls-exporter" for TLS 1.3
- "tls-unique" for TLS 1.2
- "tls-server-end-point" works for TLS 1.2 and 1.3

Issue cyrusimap#823

Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
  • Loading branch information
GuidoKiener committed Aug 9, 2024
1 parent 2285381 commit 7632d01
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 18 deletions.
44 changes: 34 additions & 10 deletions sample/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)

void usage(void)
{
fprintf(stderr, "usage: client [-c|-C] [-p port] [-s service] [-m mech] host\n");
fprintf(stderr, "usage: client [-c|-C|-d|-D] [-p port] [-s service] [-m mech] host\n");
exit(EX_USAGE);
}

Expand All @@ -354,16 +354,29 @@ int main(int argc, char *argv[])
int niflags, error;
struct sockaddr_storage local_ip, remote_ip;
int cb_flag = 0;
int cb_digest = 0;
sasl_channel_binding_t cb;

while ((c = getopt(argc, argv, "Ccp:s:m:")) != EOF) {
while ((c = getopt(argc, argv, "CcDdp:s:m:")) != EOF) {
switch(c) {
case 'C':
cb_flag = 2; /* channel bindings are critical */
cb_flag = 2; /* 'finish' channel bindings are critical */
cb_digest = 0;
break;

case 'c':
cb_flag = 1; /* channel bindings are optional */
cb_flag = 1; /* 'finish' channel bindings are optional */
cb_digest = 0;
break;

case 'D':
cb_flag = 2; /* 'digest' channel bindings are critical */
cb_digest = 1;
break;

case 'd':
cb_flag = 1; /* 'digest' bindings are optional */
cb_digest = 1;
break;

case 'p':
Expand Down Expand Up @@ -442,12 +455,23 @@ int main(int argc, char *argv[])
if (r != SASL_OK) saslfail(r, "allocating connection state");

if (cb_flag) {
cb.name = "sasl-sample";
cb.critical = cb_flag > 1;
cb.data = (unsigned char *) "this is a test of channel binding";
cb.len = (unsigned int) strlen((const char *) cb.data);

sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
/* see RFC 5929 and RFC 9266 for reference */
/* see cyrus-imapd for real implementation example */
const char finish_msg[] = "use SSL_get_(peer)_finished()";
const char digest_msg[] = "use X509_digest()";

cb.critical = cb_flag > 1;
if (cb_digest) {
cb.name = "tls-server-end-point";
cb.data = (const unsigned char*)digest_msg;
cb.len = sizeof(digest_msg);
}
else {
cb.name = "tls-unique"; /* or "tls-exporter" for TLS 1.3 */
cb.data = (const unsigned char*)finish_msg;
cb.len = sizeof(finish_msg);
}
sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
}

/* set external properties here
Expand Down
66 changes: 58 additions & 8 deletions sample/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,38 @@ enumerateAttributes(OM_uint32 *minor,
int noisy);
#endif

typedef int (*my_cb_ft)(void);

struct my_channel_binding
{
/* storage for 'tls-unique' or 'tls-exporter' */
sasl_channel_binding_t finish;
unsigned char finish_data[64]; /* use data[EVP_MAX_MD_SIZE] */
/* storage for 'tls-server-endpoint' */
sasl_channel_binding_t digest;
unsigned char digest_data[64]; /* use data[EVP_MAX_MD_SIZE] */
};

/* EXPORTED */
int my_select_binding(sasl_conn_t* conn,
void* context,
const char* plugin,
const char* cbindingname)
{
struct my_channel_binding *cb = context;

if (!conn || !context || !plugin || !cbindingname) {
return SASL_FAIL;
}

if (cb->digest.name != NULL &&
strcmp(cbindingname, cb->digest.name) == 0) {
/* overwrite channel binding with 'tls-server-end-point' data */
return sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb->digest);
}
return SASL_FAIL;
}

/* create a socket listening on port 'port' */
/* if af is PF_UNSPEC more than one socket may be returned */
/* the returned list is dynamically allocated, so caller needs to free it */
Expand Down Expand Up @@ -350,6 +382,12 @@ int main(int argc, char *argv[])
int r, i;
sasl_conn_t *conn;
int cb_flag = 0;
struct my_channel_binding cb;

const struct sasl_callback mysasl_cb[] = {
{ SASL_CB_SERVER_CHANNEL_BINDING, (my_cb_ft)&my_select_binding, &cb},
{ SASL_CB_LIST_END, NULL, NULL}
};

while ((c = getopt(argc, argv, "Cch:p:s:m:")) != EOF) {
switch(c) {
Expand Down Expand Up @@ -384,7 +422,7 @@ int main(int argc, char *argv[])
}

/* initialize the sasl library */
r = sasl_server_init(NULL, "sample");
r = sasl_server_init(mysasl_cb, "sample");
if (r != SASL_OK) saslfail(r, "initializing libsasl");

/* get a listening socket */
Expand All @@ -408,7 +446,6 @@ int main(int argc, char *argv[])
int nfds, fd = -1;
FILE *in, *out;
fd_set readfds;
sasl_channel_binding_t cb;

FD_ZERO(&readfds);
for (i = 1; i <= l[0]; i++)
Expand Down Expand Up @@ -483,13 +520,26 @@ int main(int argc, char *argv[])
NULL, 0, &conn);
if (r != SASL_OK) saslfail(r, "allocating connection state");

cb.name = "sasl-sample";
cb.critical = cb_flag > 1;
cb.data = (const unsigned char *) "this is a test of channel binding";
cb.len = (unsigned int) strlen((const char *) cb.data);

memset(&cb, 0, sizeof(cb));
if (cb_flag) {
sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
/* see RFC 5929 and RFC 9266 for reference */
/* see cyrus-imapd for real implementation example */
const char finish_msg[] = "use SSL_get_(peer)_finished()";
const char digest_msg[] = "use X509_digest()";

cb.finish.name = "tls-unique"; /* or "tls-exporter" for TLS 1.3 */
cb.finish.critical = cb_flag > 1;
cb.finish.data = cb.finish_data;
memcpy(cb.finish_data, finish_msg, sizeof(finish_msg));
cb.finish.len = sizeof(finish_msg);
sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb.finish);

/* Prepare alternate channel binding data for callback */
cb.digest.name = "tls-server-end-point";
cb.digest.critical = cb_flag > 1;
cb.digest.data = cb.digest_data;
memcpy(cb.digest_data, digest_msg, sizeof(digest_msg));
cb.digest.len = sizeof(digest_msg);
}

/* set external properties here
Expand Down

0 comments on commit 7632d01

Please sign in to comment.