Skip to content

Commit

Permalink
RFC 9266: Channel Bindings for TLS 1.3 cyrusimap#4191
Browse files Browse the repository at this point in the history
TLS connections of the IMAPD service provide channel binding data
for the SASL authentication layer. The current implementation
sets the correct "tls-unique" channel binding data for TLS
versions 1.2 and lower, however not for TLS version 1.3.

TLS version 1.3 requires using specific exporter keying material
(EKM) according to RFC 9266 Section 2:
Label:      "EXPORTER-Channel-Binding"
Context:    Zero-length string
Key Length: 32 bytes

Signed-off-by: Guido Kiener <guido@kiener-muenchen.de>
  • Loading branch information
GuidoKiener authored and rjbs committed Sep 20, 2024
1 parent c1a4661 commit 43aa26e
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 19 deletions.
48 changes: 38 additions & 10 deletions imap/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1313,19 +1313,47 @@ EXPORTED int tls_start_servertls(int readfd, int writefd, int timeout,
saslprops->ssf = (sasl_ssf_t) tls_cipher_usebits;

#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
if (SSL_session_reused(tls_conn)) {
saslprops->cbinding.len = SSL_get_finished(tls_conn,
saslprops->tls_finished,
MAX_FINISHED_LEN);
if (SSL_version(tls_conn) <= TLS1_2_VERSION) {
if (SSL_session_reused(tls_conn)) {
saslprops->cbinding.len =
SSL_get_finished(tls_conn,
saslprops->tls_finished,
MAX_FINISHED_LEN);
}
else {
saslprops->cbinding.len =
SSL_get_peer_finished(tls_conn,
saslprops->tls_finished,
MAX_FINISHED_LEN);
}
saslprops->cbinding.name = "tls-unique";
saslprops->cbinding.data = saslprops->tls_finished;
}
#if (OPENSSL_VERSION_NUMBER >= 0x10100001L)
else {
/* see RFC 9266 Section 2, Definition of label, context, length */
static const char label[] = "EXPORTER-Channel-Binding";
static const size_t key_len = 32;

assert(key_len <= sizeof(saslprops->tls_finished));
if (1 != SSL_export_keying_material(tls_conn,
saslprops->tls_finished, key_len,
label, sizeof(label)-1,
0, 0, 0)) {
syslog(LOG_ERR, "Error reading EKM for channel binding");
}
else {
saslprops->cbinding.name = "tls-exporter";
saslprops->cbinding.data = saslprops->tls_finished;
saslprops->cbinding.len = key_len;
}
}
#else
else {
saslprops->cbinding.len = SSL_get_peer_finished(tls_conn,
saslprops->tls_finished,
MAX_FINISHED_LEN);
/* This case should not happen. It's a strange OpenSSL variant */
syslog(LOG_ERR, "No EKM (channel binding) for TLS 1.3 or higher");
}

saslprops->cbinding.name = "tls-unique";
saslprops->cbinding.data = saslprops->tls_finished;
#endif /* (OPENSSL_VERSION_NUMBER >= 0x10100001L) */
#endif /* (OPENSSL_VERSION_NUMBER >= 0x0090800fL) */

#if OPENSSL_VERSION_NUMBER >= 0x10002000L
Expand Down
44 changes: 35 additions & 9 deletions imtest/imtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,20 +791,46 @@ static void do_starttls(int ssl, char *keyfile, unsigned *ssf)
imtest_fatal("Error setting SASL property (external auth_id)");

#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
static unsigned char finished[EVP_MAX_MD_SIZE];
static struct sasl_channel_binding cbinding;

if (SSL_session_reused(tls_conn)) {
cbinding.len = SSL_get_peer_finished(tls_conn,
finished, sizeof(finished));
if (SSL_version(tls_conn) <= TLS1_2_VERSION) {
static unsigned char finished[EVP_MAX_MD_SIZE];

if (SSL_session_reused(tls_conn)) {
cbinding.len =
SSL_get_peer_finished(tls_conn, finished, sizeof(finished));
}
else {
cbinding.len =
SSL_get_finished(tls_conn, finished, sizeof(finished));
}

cbinding.name = "tls-unique";
cbinding.critical = 0;
cbinding.data = finished;
}
#if (OPENSSL_VERSION_NUMBER >= 0x10100001L)
else {
cbinding.len = SSL_get_finished(tls_conn, finished, sizeof(finished));
}
/* see RFC 9266 Section 2, Definition of label, context, length */
static const char label[] = "EXPORTER-Channel-Binding";
static unsigned char exported_key[32];
static const size_t key_len = sizeof(exported_key);

cbinding.name = "tls-unique";
cbinding.critical = 0;
cbinding.data = finished;
if (1 != SSL_export_keying_material(tls_conn, exported_key, key_len,
label, sizeof(label)-1, 0, 0, 0)) {
imtest_fatal("Error reading EKM for channel binding");
}
cbinding.name = "tls-exporter";
cbinding.critical = 0;
cbinding.len = key_len;
cbinding.data = exported_key;
}
#else
else {
/* This case should not happen. It's a strange OpenSSL variant */
imtest_fatal("No EKM (channel binding) for TLS 1.3 or higher");
}
#endif /* (OPENSSL_VERSION_NUMBER >= 0x10100001L) */

result = sasl_setprop(conn, SASL_CHANNEL_BINDING, &cbinding);
if (result!=SASL_OK)
Expand Down

0 comments on commit 43aa26e

Please sign in to comment.