Skip to content

Commit

Permalink
Issue proftpd#1330: Implement OpenSSH "Encrypt-Then-MAC" (ETM) algori…
Browse files Browse the repository at this point in the history
…thm extensions.
  • Loading branch information
Castaglia committed Sep 26, 2021
1 parent 2d14bc6 commit c07e862
Show file tree
Hide file tree
Showing 9 changed files with 1,450 additions and 135 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
added to mod_sftp.
- Issue 1333 - Implement an LDAPConnectTimeout directive, to configure the
timeout used when connecting to LDAP servers.
- Issue 1330 - Implement OpenSSH "Encrypt-Then-MAC" (ETM) algorithm extensions.

1.3.8rc2 - Released 29-Aug-2021
--------------------------------
Expand Down
3 changes: 3 additions & 0 deletions RELEASE_NOTES
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ ChangeLog files.
SFTPCiphers
"[email protected]", "[email protected]" (Bug #3759)

SFTPDigests
"[email protected]", ... (Issue #1330)

SFTPOptions NoHostkeyRotation


Expand Down
63 changes: 36 additions & 27 deletions contrib/mod_sftp/cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ int sftp_cipher_set_read_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
pctx = read_ctxs[read_cipher_idx];

bufsz = buflen = SFTP_CIPHER_BUFSZ;
ptr = buf = sftp_msg_getbuf(p, bufsz);
ptr = buf = palloc(p, bufsz);

/* Need to use SSH2-style format of K for the IV and key. */
sftp_msg_write_mpint(&buf, &buflen, k);
Expand Down Expand Up @@ -626,38 +626,31 @@ int sftp_cipher_read_data(struct ssh2_packet *pkt, unsigned char *data,

/* Allocate a buffer that's large enough. */
bufsz = (data_len + read_blocksz - 1);
ptr = buf2 = palloc(pkt->pool, bufsz);
ptr = buf2 = pcalloc(pkt->pool, bufsz);

} else {
ptr = buf2 = *buf;
}

if (pkt->packet_len == 0 &&
auth_len > 0) {
unsigned char prev_iv[1];

if (pkt->packet_len == 0) {
if (auth_len > 0) {
#if defined(EVP_CTRL_GCM_IV_GEN)
/* Increment the IV. */
if (EVP_CIPHER_CTX_ctrl(pctx, EVP_CTRL_GCM_IV_GEN, 1, prev_iv) != 1) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
"error incrementing %s IV data for client: %s", cipher->algo,
sftp_crypto_get_errors());
errno = EIO;
return -1;
}
#endif
unsigned char prev_iv[1];

if (pkt->aad_len > 0 &&
pkt->aad == NULL) {
if (EVP_Cipher(pctx, NULL, data, pkt->aad_len) < 0) {
/* Increment the IV. */
if (EVP_CIPHER_CTX_ctrl(pctx, EVP_CTRL_GCM_IV_GEN, 1, prev_iv) != 1) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
"error setting %s AAD data for client: %s", cipher->algo,
"error incrementing %s IV data for client: %s", cipher->algo,
sftp_crypto_get_errors());
errno = EIO;
return -1;
}
#endif
}

pkt->aad = palloc(pkt->pool, pkt->aad_len);
if (pkt->aad_len > 0 &&
pkt->aad == NULL) {
pkt->aad = pcalloc(pkt->pool, pkt->aad_len);
memcpy(pkt->aad, data, pkt->aad_len);
memcpy(ptr, data, pkt->aad_len);

Expand All @@ -668,6 +661,16 @@ int sftp_cipher_read_data(struct ssh2_packet *pkt, unsigned char *data,
data += pkt->aad_len;
data_len -= pkt->aad_len;
output_buflen -= pkt->aad_len;

if (auth_len > 0) {
if (EVP_Cipher(pctx, NULL, pkt->aad, pkt->aad_len) < 0) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
"error setting %s AAD data for client: %s", cipher->algo,
sftp_crypto_get_errors());
errno = EIO;
return -1;
}
}
}
}

Expand Down Expand Up @@ -819,7 +822,7 @@ int sftp_cipher_set_write_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
pctx = write_ctxs[write_cipher_idx];

bufsz = buflen = SFTP_CIPHER_BUFSZ;
ptr = buf = sftp_msg_getbuf(p, bufsz);
ptr = buf = palloc(p, bufsz);

/* Need to use SSH2-style format of K for the IV and key. */
sftp_msg_write_mpint(&buf, &buflen, k);
Expand Down Expand Up @@ -964,15 +967,18 @@ int sftp_cipher_write_data(struct ssh2_packet *pkt, unsigned char *buf,
* Encrypt-Then-MAC modes.
*/
datasz -= pkt->aad_len;

/* And, for ETM modes, we may need a little more space. */
datasz += sftp_cipher_get_write_block_size();
}

datalen = datasz;
ptr = data = palloc(pkt->pool, datasz);

if (auth_len > 0) {
#if defined(EVP_CTRL_GCM_IV_GEN)
unsigned char prev_iv[1];

#if defined(EVP_CTRL_GCM_IV_GEN)
/* Increment the IV. */
if (EVP_CIPHER_CTX_ctrl(pctx, EVP_CTRL_GCM_IV_GEN, 1, prev_iv) != 1) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
Expand All @@ -982,14 +988,17 @@ int sftp_cipher_write_data(struct ssh2_packet *pkt, unsigned char *buf,
return -1;
}
#endif
}

if (pkt->aad_len > 0) {
uint32_t packet_len;
if (pkt->aad_len > 0 &&
pkt->aad == NULL) {
uint32_t packet_len;

packet_len = htonl(pkt->packet_len);
pkt->aad = palloc(pkt->pool, pkt->aad_len);
memcpy(pkt->aad, &packet_len, pkt->aad_len);
packet_len = htonl(pkt->packet_len);
pkt->aad = pcalloc(pkt->pool, pkt->aad_len);
memcpy(pkt->aad, &packet_len, pkt->aad_len);

if (auth_len > 0) {
if (EVP_Cipher(pctx, NULL, pkt->aad, pkt->aad_len) < 0) {
(void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
"error setting %s AAD (%lu bytes) for client: %s", cipher->algo,
Expand Down
30 changes: 22 additions & 8 deletions contrib/mod_sftp/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,28 @@ static struct sftp_digest digests[] = {
*/
#ifdef HAVE_SHA256_OPENSSL
{ "hmac-sha2-256", "sha256", EVP_sha256, 0, TRUE, TRUE },
{ "[email protected]", "sha256", EVP_sha256, 0, TRUE, TRUE },
#endif /* SHA256 support in OpenSSL */
#ifdef HAVE_SHA512_OPENSSL
{ "hmac-sha2-512", "sha512", EVP_sha512, 0, TRUE, TRUE },
{ "[email protected]", "sha512", EVP_sha512, 0, TRUE, TRUE },
#endif /* SHA512 support in OpenSSL */
{ "hmac-sha1", "sha1", EVP_sha1, 0, TRUE, TRUE },
{ "[email protected]", "sha1",EVP_sha1, 0, TRUE, TRUE },
{ "hmac-sha1-96", "sha1", EVP_sha1, 12, TRUE, TRUE },
{ "[email protected]", "sha1", EVP_sha1, 12, TRUE, TRUE },
{ "hmac-md5", "md5", EVP_md5, 0, FALSE, FALSE },
{ "[email protected]", "md5", EVP_md5, 0, FALSE, TRUE },
{ "hmac-md5-96", "md5", EVP_md5, 12, FALSE, FALSE },
{ "[email protected]", "md5", EVP_md5, 12, FALSE, TRUE },
#if !defined(OPENSSL_NO_RIPEMD)
{ "hmac-ripemd160", "rmd160", EVP_ripemd160, 0, FALSE, FALSE },
#endif /* !OPENSSL_NO_RIPEMD */
#if OPENSSL_VERSION_NUMBER > 0x000907000L
{ "[email protected]", NULL, NULL, 8, TRUE, FALSE },
{ "[email protected]", NULL, NULL, 8, TRUE, FALSE },
{ "[email protected]", NULL, NULL, 16, TRUE, FALSE },
{ "[email protected]", NULL, NULL, 16, TRUE, FALSE },
#endif /* OpenSSL-0.9.7 or later */
{ "none", "null", EVP_md_null, 0, FALSE, TRUE },
{ NULL, NULL, NULL, 0, FALSE, FALSE }
Expand Down Expand Up @@ -1046,10 +1054,12 @@ const EVP_MD *sftp_crypto_get_digest(const char *name, uint32_t *mac_len) {
const EVP_MD *digest = NULL;

#if OPENSSL_VERSION_NUMBER > 0x000907000L
if (strncmp(name, "[email protected]", 12) == 0) {
if (strcmp(name, "[email protected]") == 0 ||
strcmp(name, "[email protected]") == 0) {
digest = get_umac64_digest();

} else if (strncmp(name, "[email protected]", 13) == 0) {
} else if (strcmp(name, "[email protected]") == 0 ||
strcmp(name, "[email protected]") == 0) {
digest = get_umac128_digest();
#else
if (FALSE) {
Expand Down Expand Up @@ -1237,16 +1247,18 @@ const char *sftp_crypto_get_kexinit_digest_list(pool *p) {
}
#endif /* OPENSSL_FIPS */

if (strncmp(c->argv[i], "none", 5) != 0) {
if (strcmp(c->argv[i], "none") != 0) {
if (digests[j].openssl_name != NULL &&
EVP_get_digestbyname(digests[j].openssl_name) != NULL) {
res = pstrcat(p, res, *res ? "," : "",
pstrdup(p, digests[j].name), NULL);

} else {
/* The umac-64/umac-128 digests are special cases. */
if (strncmp(digests[j].name, "[email protected]", 12) == 0 ||
strncmp(digests[j].name, "[email protected]", 13) == 0) {
if (strcmp(digests[j].name, "[email protected]") == 0 ||
strcmp(digests[j].name, "[email protected]") == 0 ||
strcmp(digests[j].name, "[email protected]") == 0 ||
strcmp(digests[j].name, "[email protected]") == 0) {
res = pstrcat(p, res, *res ? "," : "",
pstrdup(p, digests[j].name), NULL);

Expand Down Expand Up @@ -1284,16 +1296,18 @@ const char *sftp_crypto_get_kexinit_digest_list(pool *p) {
}
#endif /* OPENSSL_FIPS */

if (strncmp(digests[i].name, "none", 5) != 0) {
if (strcmp(digests[i].name, "none") != 0) {
if (digests[i].openssl_name != NULL &&
EVP_get_digestbyname(digests[i].openssl_name) != NULL) {
res = pstrcat(p, res, *res ? "," : "",
pstrdup(p, digests[i].name), NULL);

} else {
/* The umac-64/umac-128 digests are special cases. */
if (strncmp(digests[i].name, "[email protected]", 12) == 0 ||
strncmp(digests[i].name, "[email protected]", 13) == 0) {
if (strcmp(digests[i].name, "[email protected]") == 0 ||
strcmp(digests[i].name, "[email protected]") == 0 ||
strcmp(digests[i].name, "[email protected]") == 0 ||
strcmp(digests[i].name, "[email protected]") == 0) {
res = pstrcat(p, res, *res ? "," : "",
pstrdup(p, digests[i].name), NULL);

Expand Down
Loading

0 comments on commit c07e862

Please sign in to comment.