diff options
Diffstat (limited to 'cipher.c')
| -rw-r--r-- | cipher.c | 299 |
1 files changed, 70 insertions, 229 deletions
@@ -1,4 +1,4 @@ -/* $OpenBSD: cipher.c,v 1.102 2016/08/03 05:41:57 djm Exp $ */ +/* $OpenBSD: cipher.c,v 1.107 2017/05/07 23:12:57 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -51,11 +51,6 @@ #include "openbsd-compat/openssl-compat.h" -#ifdef WITH_SSH1 -extern const EVP_CIPHER *evp_ssh1_bf(void); -extern const EVP_CIPHER *evp_ssh1_3des(void); -extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); -#endif struct sshcipher_ctx { int plaintext; @@ -68,17 +63,16 @@ struct sshcipher_ctx { struct sshcipher { char *name; - int number; /* for ssh1 only */ u_int block_size; u_int key_len; u_int iv_len; /* defaults to block_size */ u_int auth_len; - u_int discard_len; u_int flags; #define CFLAG_CBC (1<<0) #define CFLAG_CHACHAPOLY (1<<1) #define CFLAG_AESCTR (1<<2) #define CFLAG_NONE (1<<3) +#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */ #ifdef WITH_OPENSSL const EVP_CIPHER *(*evptype)(void); #else @@ -87,53 +81,32 @@ struct sshcipher { }; static const struct sshcipher ciphers[] = { -#ifdef WITH_SSH1 - { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, - { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, -# ifndef OPENSSL_NO_BF - { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf }, -# endif /* OPENSSL_NO_BF */ -#endif /* WITH_SSH1 */ #ifdef WITH_OPENSSL - { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, - { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, -# ifndef OPENSSL_NO_BF - { "blowfish-cbc", - SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc }, -# endif /* OPENSSL_NO_BF */ -# ifndef OPENSSL_NO_CAST - { "cast128-cbc", - SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_cast5_cbc }, -# endif /* OPENSSL_NO_CAST */ -# ifndef OPENSSL_NO_RC4 - { "arcfour", SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 0, EVP_rc4 }, - { "arcfour128", SSH_CIPHER_SSH2, 8, 16, 0, 0, 1536, 0, EVP_rc4 }, - { "arcfour256", SSH_CIPHER_SSH2, 8, 32, 0, 0, 1536, 0, EVP_rc4 }, -# endif /* OPENSSL_NO_RC4 */ - { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc }, - { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc }, - { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, + { "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc }, + { "aes128-cbc", 16, 16, 0, 0, CFLAG_CBC, EVP_aes_128_cbc }, + { "aes192-cbc", 16, 24, 0, 0, CFLAG_CBC, EVP_aes_192_cbc }, + { "aes256-cbc", 16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc }, { "rijndael-cbc@lysator.liu.se", - SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, - { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, - { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, - { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, + 16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc }, + { "aes128-ctr", 16, 16, 0, 0, 0, EVP_aes_128_ctr }, + { "aes192-ctr", 16, 24, 0, 0, 0, EVP_aes_192_ctr }, + { "aes256-ctr", 16, 32, 0, 0, 0, EVP_aes_256_ctr }, # ifdef OPENSSL_HAVE_EVPGCM { "aes128-gcm@openssh.com", - SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, + 16, 16, 12, 16, 0, EVP_aes_128_gcm }, { "aes256-gcm@openssh.com", - SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, + 16, 32, 12, 16, 0, EVP_aes_256_gcm }, # endif /* OPENSSL_HAVE_EVPGCM */ -#else /* WITH_OPENSSL */ - { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL }, - { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL }, - { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, CFLAG_AESCTR, NULL }, - { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL }, -#endif /* WITH_OPENSSL */ +#else + { "aes128-ctr", 16, 16, 0, 0, CFLAG_AESCTR, NULL }, + { "aes192-ctr", 16, 24, 0, 0, CFLAG_AESCTR, NULL }, + { "aes256-ctr", 16, 32, 0, 0, CFLAG_AESCTR, NULL }, +#endif { "chacha20-poly1305@openssh.com", - SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL }, + 8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL }, + { "none", 8, 0, 0, 0, CFLAG_NONE, NULL }, - { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } + { NULL, 0, 0, 0, 0, 0, NULL } }; /*--*/ @@ -147,7 +120,7 @@ cipher_alg_list(char sep, int auth_only) const struct sshcipher *c; for (c = ciphers; c->name != NULL; c++) { - if (c->number != SSH_CIPHER_SSH2) + if ((c->flags & CFLAG_INTERNAL) != 0) continue; if (auth_only && c->auth_len == 0) continue; @@ -203,12 +176,6 @@ cipher_ivlen(const struct sshcipher *c) } u_int -cipher_get_number(const struct sshcipher *c) -{ - return (c->number); -} - -u_int cipher_is_cbc(const struct sshcipher *c) { return (c->flags & CFLAG_CBC) != 0; @@ -220,24 +187,6 @@ cipher_ctx_is_plaintext(struct sshcipher_ctx *cc) return cc->plaintext; } -u_int -cipher_ctx_get_number(struct sshcipher_ctx *cc) -{ - return cc->cipher->number; -} - -u_int -cipher_mask_ssh1(int client) -{ - u_int mask = 0; - mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ - mask |= 1 << SSH_CIPHER_BLOWFISH; - if (client) { - mask |= 1 << SSH_CIPHER_DES; - } - return mask; -} - const struct sshcipher * cipher_by_name(const char *name) { @@ -248,16 +197,6 @@ cipher_by_name(const char *name) return NULL; } -const struct sshcipher * -cipher_by_number(int id) -{ - const struct sshcipher *c; - for (c = ciphers; c->name != NULL; c++) - if (c->number == id) - return c; - return NULL; -} - #define CIPHER_SEP "," int ciphers_valid(const char *names) @@ -273,7 +212,7 @@ ciphers_valid(const char *names) for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; (p = strsep(&cp, CIPHER_SEP))) { c = cipher_by_name(p); - if (c == NULL || c->number != SSH_CIPHER_SSH2) { + if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0) { free(cipher_list); return 0; } @@ -282,38 +221,12 @@ ciphers_valid(const char *names) return 1; } -/* - * Parses the name of the cipher. Returns the number of the corresponding - * cipher, or -1 on error. - */ - -int -cipher_number(const char *name) -{ - const struct sshcipher *c; - if (name == NULL) - return -1; - for (c = ciphers; c->name != NULL; c++) - if (strcasecmp(c->name, name) == 0) - return c->number; - return -1; -} - -char * -cipher_name(int id) -{ - const struct sshcipher *c = cipher_by_number(id); - return (c==NULL) ? "<unknown>" : c->name; -} - const char * cipher_warning_message(const struct sshcipher_ctx *cc) { if (cc == NULL || cc->cipher == NULL) return NULL; - if (cc->cipher->number == SSH_CIPHER_DES) - return "use of DES is strongly discouraged due to " - "cryptographic weaknesses"; + /* XXX repurpose for CBC warning */ return NULL; } @@ -327,19 +240,13 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher, #ifdef WITH_OPENSSL const EVP_CIPHER *type; int klen; - u_char *junk, *discard; #endif *ccp = NULL; if ((cc = calloc(sizeof(*cc), 1)) == NULL) return SSH_ERR_ALLOC_FAIL; - if (cipher->number == SSH_CIPHER_DES) { - if (keylen > 8) - keylen = 8; - } - - cc->plaintext = (cipher->number == SSH_CIPHER_NONE); + cc->plaintext = (cipher->flags & CFLAG_NONE) != 0; cc->encrypt = do_encrypt; if (keylen < cipher->key_len || @@ -353,6 +260,10 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher, ret = chachapoly_init(&cc->cp_ctx, key, keylen); goto out; } + if ((cc->cipher->flags & CFLAG_NONE) != 0) { + ret = 0; + goto out; + } #ifndef WITH_OPENSSL if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen); @@ -360,10 +271,6 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher, ret = 0; goto out; } - if ((cc->cipher->flags & CFLAG_NONE) != 0) { - ret = 0; - goto out; - } ret = SSH_ERR_INVALID_ARGUMENT; goto out; #else /* WITH_OPENSSL */ @@ -394,23 +301,6 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher, ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - - if (cipher->discard_len > 0) { - if ((junk = malloc(cipher->discard_len)) == NULL || - (discard = malloc(cipher->discard_len)) == NULL) { - free(junk); - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - ret = EVP_Cipher(cc->evp, discard, junk, cipher->discard_len); - explicit_bzero(discard, cipher->discard_len); - free(junk); - free(discard); - if (ret != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - } ret = 0; #endif /* WITH_OPENSSL */ out: @@ -448,6 +338,10 @@ cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest, return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, authlen, cc->encrypt); } + if ((cc->cipher->flags & CFLAG_NONE) != 0) { + memcpy(dest, src, aadlen + len); + return 0; + } #ifndef WITH_OPENSSL if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { if (aadlen) @@ -456,10 +350,6 @@ cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest, dest + aadlen, len); return 0; } - if ((cc->cipher->flags & CFLAG_NONE) != 0) { - memcpy(dest, src, aadlen + len); - return 0; - } return SSH_ERR_INVALID_ARGUMENT; #else if (authlen) { @@ -536,28 +426,6 @@ cipher_free(struct sshcipher_ctx *cc) } /* - * Selects the cipher, and keys if by computing the MD5 checksum of the - * passphrase and using the resulting 16 bytes as the key. - */ -int -cipher_set_key_string(struct sshcipher_ctx **ccp, - const struct sshcipher *cipher, const char *passphrase, int do_encrypt) -{ - u_char digest[16]; - int r = SSH_ERR_INTERNAL_ERROR; - - if ((r = ssh_digest_memory(SSH_DIGEST_MD5, - passphrase, strlen(passphrase), - digest, sizeof(digest))) != 0) - goto out; - - r = cipher_init(ccp, cipher, digest, 16, NULL, 0, do_encrypt); - out: - explicit_bzero(digest, sizeof(digest)); - return r; -} - -/* * Exports an IV from the sshcipher_ctx required to export the key * state back from the unprivileged child to the privileged parent * process. @@ -566,19 +434,16 @@ int cipher_get_keyiv_len(const struct sshcipher_ctx *cc) { const struct sshcipher *c = cc->cipher; - int ivlen = 0; - if (c->number == SSH_CIPHER_3DES) - ivlen = 24; - else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) - ivlen = 0; - else if ((cc->cipher->flags & CFLAG_AESCTR) != 0) - ivlen = sizeof(cc->ac_ctx.ctr); + if ((c->flags & CFLAG_CHACHAPOLY) != 0) + return 0; + else if ((c->flags & CFLAG_AESCTR) != 0) + return sizeof(cc->ac_ctx.ctr); #ifdef WITH_OPENSSL - else - ivlen = EVP_CIPHER_CTX_iv_length(cc->evp); -#endif /* WITH_OPENSSL */ - return (ivlen); + return EVP_CIPHER_CTX_iv_length(cc->evp); +#else + return 0; +#endif } int @@ -603,38 +468,26 @@ cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len) if ((cc->cipher->flags & CFLAG_NONE) != 0) return 0; - switch (c->number) { #ifdef WITH_OPENSSL - case SSH_CIPHER_SSH2: - case SSH_CIPHER_DES: - case SSH_CIPHER_BLOWFISH: - evplen = EVP_CIPHER_CTX_iv_length(cc->evp); - if (evplen == 0) - return 0; - else if (evplen < 0) - return SSH_ERR_LIBCRYPTO_ERROR; - if ((u_int)evplen != len) - return SSH_ERR_INVALID_ARGUMENT; + evplen = EVP_CIPHER_CTX_iv_length(cc->evp); + if (evplen == 0) + return 0; + else if (evplen < 0) + return SSH_ERR_LIBCRYPTO_ERROR; + if ((u_int)evplen != len) + return SSH_ERR_INVALID_ARGUMENT; #ifndef OPENSSL_HAVE_EVPCTR - if (c->evptype == evp_aes_128_ctr) - ssh_aes_ctr_iv(cc->evp, 0, iv, len); - else -#endif - if (cipher_authlen(c)) { - if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN, - len, iv)) - return SSH_ERR_LIBCRYPTO_ERROR; - } else - memcpy(iv, cc->evp->iv, len); - break; + if (c->evptype == evp_aes_128_ctr) + ssh_aes_ctr_iv(cc->evp, 0, iv, len); + else #endif -#ifdef WITH_SSH1 - case SSH_CIPHER_3DES: - return ssh1_3des_iv(cc->evp, 0, iv, 24); + if (cipher_authlen(c)) { + if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN, + len, iv)) + return SSH_ERR_LIBCRYPTO_ERROR; + } else + memcpy(iv, cc->evp->iv, len); #endif - default: - return SSH_ERR_INVALID_ARGUMENT; - } return 0; } @@ -651,36 +504,24 @@ cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv) if ((cc->cipher->flags & CFLAG_NONE) != 0) return 0; - switch (c->number) { #ifdef WITH_OPENSSL - case SSH_CIPHER_SSH2: - case SSH_CIPHER_DES: - case SSH_CIPHER_BLOWFISH: - evplen = EVP_CIPHER_CTX_iv_length(cc->evp); - if (evplen <= 0) - return SSH_ERR_LIBCRYPTO_ERROR; + evplen = EVP_CIPHER_CTX_iv_length(cc->evp); + if (evplen <= 0) + return SSH_ERR_LIBCRYPTO_ERROR; #ifndef OPENSSL_HAVE_EVPCTR - /* XXX iv arg is const, but ssh_aes_ctr_iv isn't */ - if (c->evptype == evp_aes_128_ctr) - ssh_aes_ctr_iv(cc->evp, 1, (u_char *)iv, evplen); - else -#endif - if (cipher_authlen(c)) { - /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */ - if (!EVP_CIPHER_CTX_ctrl(cc->evp, - EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv)) - return SSH_ERR_LIBCRYPTO_ERROR; - } else - memcpy(cc->evp->iv, iv, evplen); - break; + /* XXX iv arg is const, but ssh_aes_ctr_iv isn't */ + if (c->evptype == evp_aes_128_ctr) + ssh_aes_ctr_iv(cc->evp, 1, (u_char *)iv, evplen); + else #endif -#ifdef WITH_SSH1 - case SSH_CIPHER_3DES: - return ssh1_3des_iv(cc->evp, 1, (u_char *)iv, 24); + if (cipher_authlen(c)) { + /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */ + if (!EVP_CIPHER_CTX_ctrl(cc->evp, + EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv)) + return SSH_ERR_LIBCRYPTO_ERROR; + } else + memcpy(cc->evp->iv, iv, evplen); #endif - default: - return SSH_ERR_INVALID_ARGUMENT; - } return 0; } |
