aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelen <jjelen@redhat.com>2018-10-04 15:21:36 +0200
committerAndreas Schneider <asn@cryptomilk.org>2018-10-09 13:05:38 +0200
commit72bd2fe1972673ca173cba635472d6e7ad5783d1 (patch)
tree2638bdacd54eab4db36b38ccb2004e1e8792b905
parenta2120e168b70218a82617b630e2030ff126a21ec (diff)
downloadlibssh-72bd2fe1972673ca173cba635472d6e7ad5783d1.tar.gz
libssh-72bd2fe1972673ca173cba635472d6e7ad5783d1.tar.xz
libssh-72bd2fe1972673ca173cba635472d6e7ad5783d1.zip
libmbedtls: Support OpenSSH-compatible AES-GCM ciphers using mbedTLS
Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--include/libssh/crypto.h6
-rw-r--r--include/libssh/misc.h2
-rw-r--r--src/kex.c8
-rw-r--r--src/libgcrypt.c14
-rw-r--r--src/libmbedcrypto.c159
-rw-r--r--src/misc.c13
6 files changed, 188 insertions, 14 deletions
diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h
index 8777f0c9..9eea580b 100644
--- a/include/libssh/crypto.h
+++ b/include/libssh/crypto.h
@@ -29,6 +29,8 @@
#ifdef HAVE_LIBGCRYPT
#include <gcrypt.h>
+#elif defined(HAVE_LIBMBEDCRYPTO)
+#include <mbedtls/gcm.h>
#endif
#include "libssh/wrapper.h"
@@ -152,6 +154,10 @@ struct ssh_cipher_struct {
mbedtls_cipher_context_t encrypt_ctx;
mbedtls_cipher_context_t decrypt_ctx;
mbedtls_cipher_type_t type;
+#ifdef MBEDTLS_GCM_C
+ mbedtls_gcm_context gcm_ctx;
+ unsigned char last_iv[AES_GCM_IVLEN];
+#endif /* MBEDTLS_GCM_C */
#endif
struct chacha20_poly1305_keysched *chacha20_schedule;
unsigned int keysize; /* bytes of key used. != keylen */
diff --git a/include/libssh/misc.h b/include/libssh/misc.h
index bc50cff8..94da3979 100644
--- a/include/libssh/misc.h
+++ b/include/libssh/misc.h
@@ -81,4 +81,6 @@ int ssh_timeout_update(struct ssh_timestamp *ts, int timeout);
int ssh_match_group(const char *group, const char *object);
+void uint64_inc(unsigned char *counter);
+
#endif /* MISC_H_ */
diff --git a/src/kex.c b/src/kex.c
index 382d88fb..ae71f370 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -48,7 +48,13 @@
#elif defined HAVE_LIBMBEDCRYPTO
# define BLOWFISH "blowfish-cbc,"
-# define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
+# ifdef MBEDTLS_GCM_C
+# define GCM "aes256-gcm@openssh.com,aes128-gcm@openssh.com,"
+# else
+# define GCM ""
+# endif /* MBEDTLS_GCM_C */
+# define AES GCM "aes256-ctr,aes192-ctr,aes128-ctr," \
+ "aes256-cbc,aes192-cbc,aes128-cbc,"
# define DES "3des-cbc"
# define DES_SUPPORTED "3des-cbc"
diff --git a/src/libgcrypt.c b/src/libgcrypt.c
index 7160bb1c..2b4e3371 100644
--- a/src/libgcrypt.c
+++ b/src/libgcrypt.c
@@ -31,6 +31,7 @@
#include "libssh/crypto.h"
#include "libssh/wrapper.h"
#include "libssh/string.h"
+#include "libssh/misc.h"
#ifdef HAVE_LIBGCRYPT
#include <gcrypt.h>
@@ -429,19 +430,6 @@ aes_aead_get_length(struct ssh_cipher_struct *cipher,
return SSH_OK;
}
-/* Increment 64b integer in network byte order */
-static void
-uint64_inc(unsigned char *counter)
-{
- int i;
-
- for (i = 7; i >= 0; i--) {
- counter[i]++;
- if (counter[i])
- return;
- }
-}
-
static void
aes_gcm_encrypt(struct ssh_cipher_struct *cipher,
void *in,
diff --git a/src/libmbedcrypto.c b/src/libmbedcrypto.c
index 8a2a7d96..8c0f5b4c 100644
--- a/src/libmbedcrypto.c
+++ b/src/libmbedcrypto.c
@@ -26,9 +26,13 @@
#include "libssh/wrapper.h"
#include "libssh/crypto.h"
#include "libssh/priv.h"
+#include "libssh/misc.h"
#ifdef HAVE_LIBMBEDCRYPTO
#include <mbedtls/md.h>
+#ifdef MBEDTLS_GCM_C
+#include <mbedtls/gcm.h>
+#endif /* MBEDTLS_GCM_C */
static mbedtls_entropy_context ssh_mbedtls_entropy;
static mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
@@ -616,6 +620,37 @@ error:
return SSH_ERROR;
}
+#ifdef MBEDTLS_GCM_C
+static int
+cipher_set_key_gcm(struct ssh_cipher_struct *cipher,
+ void *key,
+ void *IV)
+{
+ const mbedtls_cipher_info_t *cipher_info = NULL;
+ int rc;
+
+ mbedtls_gcm_init(&cipher->gcm_ctx);
+ cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+ rc = mbedtls_gcm_setkey(&cipher->gcm_ctx,
+ MBEDTLS_CIPHER_ID_AES,
+ key,
+ cipher_info->key_bitlen);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_setkey failed");
+ goto error;
+ }
+
+ /* Store the IV so we can increment the packet counter later */
+ memcpy(cipher->last_iv, IV, AES_GCM_IVLEN);
+
+ return 0;
+error:
+ mbedtls_gcm_free(&cipher->gcm_ctx);
+ return 1;
+}
+#endif /* MBEDTLS_GCM_C */
+
static int
cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
void *key,
@@ -810,10 +845,104 @@ static void cipher_decrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void
}
+#ifdef MBEDTLS_GCM_C
+static int
+cipher_gcm_get_length(struct ssh_cipher_struct *cipher,
+ void *in,
+ uint8_t *out,
+ size_t len,
+ uint64_t seq)
+{
+ (void)seq;
+
+ /* The length is not encrypted: Copy it to the result buffer */
+ memcpy(out, in, len);
+
+ return SSH_OK;
+}
+
+static void
+cipher_encrypt_gcm(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ size_t len,
+ uint8_t *tag,
+ uint64_t seq)
+{
+ size_t authlen, aadlen;
+ int rc;
+
+ (void) seq;
+
+ aadlen = cipher->lenfield_blocksize;
+ authlen = cipher->tag_size;
+
+ /* The length is not encrypted */
+ memcpy(out, in, aadlen);
+ rc = mbedtls_gcm_crypt_and_tag(&cipher->gcm_ctx,
+ MBEDTLS_GCM_ENCRYPT,
+ len - aadlen, /* encrypted data len */
+ cipher->last_iv, /* IV */
+ AES_GCM_IVLEN,
+ in, /* aad */
+ aadlen,
+ (const unsigned char *)in + aadlen, /* input */
+ (unsigned char *)out + aadlen, /* output */
+ authlen,
+ tag); /* tag */
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_crypt_and_tag failed");
+ return;
+ }
+
+ /* Increment the IV for the next invocation */
+ uint64_inc(cipher->last_iv + 4);
+}
+
+static int
+cipher_decrypt_gcm(struct ssh_cipher_struct *cipher,
+ void *complete_packet,
+ uint8_t *out,
+ size_t encrypted_size,
+ uint64_t seq)
+{
+ size_t authlen, aadlen;
+ int rc;
+
+ (void) seq;
+
+ aadlen = cipher->lenfield_blocksize;
+ authlen = cipher->tag_size;
+
+ rc = mbedtls_gcm_auth_decrypt(&cipher->gcm_ctx,
+ encrypted_size, /* encrypted data len */
+ cipher->last_iv, /* IV */
+ AES_GCM_IVLEN,
+ complete_packet, /* aad */
+ aadlen,
+ (const u_char *)complete_packet + aadlen + encrypted_size, /* tag */
+ authlen,
+ (const u_char *)complete_packet + aadlen, /* input */
+ (unsigned char *)out); /* output */
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_auth_decrypt failed");
+ return SSH_ERROR;
+ }
+
+ /* Increment the IV for the next invocation */
+ uint64_inc(cipher->last_iv + 4);
+
+ return SSH_OK;
+}
+#endif /* MBEDTLS_GCM_C */
+
static void cipher_cleanup(struct ssh_cipher_struct *cipher)
{
mbedtls_cipher_free(&cipher->encrypt_ctx);
mbedtls_cipher_free(&cipher->decrypt_ctx);
+#ifdef MBEDTLS_GCM_C
+ mbedtls_gcm_free(&cipher->gcm_ctx);
+#endif /* MBEDTLS_GCM_C */
}
static struct ssh_cipher_struct ssh_ciphertab[] = {
@@ -894,6 +1023,36 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
.decrypt = cipher_decrypt_cbc,
.cleanup = cipher_cleanup
},
+#ifdef MBEDTLS_GCM_C
+ {
+ .name = "aes128-gcm@openssh.com",
+ .blocksize = 16,
+ .lenfield_blocksize = 4, /* not encrypted, but authenticated */
+ .keysize = 128,
+ .tag_size = AES_GCM_TAGLEN,
+ .type = MBEDTLS_CIPHER_AES_128_GCM,
+ .set_encrypt_key = cipher_set_key_gcm,
+ .set_decrypt_key = cipher_set_key_gcm,
+ .aead_encrypt = cipher_encrypt_gcm,
+ .aead_decrypt_length = cipher_gcm_get_length,
+ .aead_decrypt = cipher_decrypt_gcm,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "aes256-gcm@openssh.com",
+ .blocksize = 16,
+ .lenfield_blocksize = 4, /* not encrypted, but authenticated */
+ .keysize = 256,
+ .tag_size = AES_GCM_TAGLEN,
+ .type = MBEDTLS_CIPHER_AES_256_GCM,
+ .set_encrypt_key = cipher_set_key_gcm,
+ .set_decrypt_key = cipher_set_key_gcm,
+ .aead_encrypt = cipher_encrypt_gcm,
+ .aead_decrypt_length = cipher_gcm_get_length,
+ .aead_decrypt = cipher_decrypt_gcm,
+ .cleanup = cipher_cleanup
+ },
+#endif /* MBEDTLS_GCM_C */
{
.name = "3des-cbc",
.blocksize = 8,
diff --git a/src/misc.c b/src/misc.c
index cfd971c2..402ece41 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1105,4 +1105,17 @@ char *strndup(const char *s, size_t n)
}
#endif /* ! HAVE_STRNDUP */
+/* Increment 64b integer in network byte order */
+void
+uint64_inc(unsigned char *counter)
+{
+ int i;
+
+ for (i = 7; i >= 0; i--) {
+ counter[i]++;
+ if (counter[i])
+ return;
+ }
+}
+
/** @} */