diff options
author | Jakub Jelen <jjelen@redhat.com> | 2018-10-04 15:21:36 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2018-10-09 13:05:38 +0200 |
commit | 72bd2fe1972673ca173cba635472d6e7ad5783d1 (patch) | |
tree | 2638bdacd54eab4db36b38ccb2004e1e8792b905 | |
parent | a2120e168b70218a82617b630e2030ff126a21ec (diff) | |
download | libssh-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.h | 6 | ||||
-rw-r--r-- | include/libssh/misc.h | 2 | ||||
-rw-r--r-- | src/kex.c | 8 | ||||
-rw-r--r-- | src/libgcrypt.c | 14 | ||||
-rw-r--r-- | src/libmbedcrypto.c | 159 | ||||
-rw-r--r-- | src/misc.c | 13 |
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_ */ @@ -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, @@ -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; + } +} + /** @} */ |