Skip to content

Commit

Permalink
upstream commit
Browse files Browse the repository at this point in the history
small refactor of cipher.c: make ciphercontext opaque to
callers feedback and ok markus@

Upstream-ID: 094849f8be68c3bdad2c0f3dee551ecf7be87f6f
  • Loading branch information
djmdjm authored and daztucker committed Aug 8, 2016
1 parent e600348 commit 4706c1d
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 139 deletions.
5 changes: 3 additions & 2 deletions cipher-chachapoly.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/* $OpenBSD: cipher-chachapoly.c,v 1.7 2015/01/14 10:24:42 markus Exp $ */
/* $OpenBSD: cipher-chachapoly.c,v 1.8 2016/08/03 05:41:57 djm Exp $ */

#include "includes.h"

Expand All @@ -28,7 +28,8 @@
#include "ssherr.h"
#include "cipher-chachapoly.h"

int chachapoly_init(struct chachapoly_ctx *ctx,
int
chachapoly_init(struct chachapoly_ctx *ctx,
const u_char *key, u_int keylen)
{
if (keylen != (32 + 32)) /* 2 x 256 bit keys */
Expand Down
165 changes: 109 additions & 56 deletions cipher.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: cipher.c,v 1.101 2015/12/10 17:08:40 mmcc Exp $ */
/* $OpenBSD: cipher.c,v 1.102 2016/08/03 05:41:57 djm Exp $ */
/*
* Author: Tatu Ylonen <[email protected]>
* Copyright (c) 1995 Tatu Ylonen <[email protected]>, Espoo, Finland
Expand Down Expand Up @@ -57,6 +57,15 @@ 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;
int encrypt;
EVP_CIPHER_CTX *evp;
struct chachapoly_ctx cp_ctx; /* XXX union with evp? */
struct aesctr_ctx ac_ctx; /* XXX union with evp? */
const struct sshcipher *cipher;
};

struct sshcipher {
char *name;
int number; /* for ssh1 only */
Expand Down Expand Up @@ -205,6 +214,18 @@ cipher_is_cbc(const struct sshcipher *c)
return (c->flags & CFLAG_CBC) != 0;
}

u_int
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)
{
Expand Down Expand Up @@ -297,87 +318,116 @@ cipher_warning_message(const struct sshcipher_ctx *cc)
}

int
cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
int do_encrypt)
{
#ifdef WITH_OPENSSL
struct sshcipher_ctx *cc = NULL;
int ret = SSH_ERR_INTERNAL_ERROR;
#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;
}
#endif

cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
cc->encrypt = do_encrypt;

if (keylen < cipher->key_len ||
(iv != NULL && ivlen < cipher_ivlen(cipher)))
return SSH_ERR_INVALID_ARGUMENT;
(iv != NULL && ivlen < cipher_ivlen(cipher))) {
ret = SSH_ERR_INVALID_ARGUMENT;
goto out;
}

cc->cipher = cipher;
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
return chachapoly_init(&cc->cp_ctx, key, keylen);
ret = chachapoly_init(&cc->cp_ctx, key, keylen);
goto out;
}
#ifndef WITH_OPENSSL
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
aesctr_ivsetup(&cc->ac_ctx, iv);
return 0;
ret = 0;
goto out;
}
if ((cc->cipher->flags & CFLAG_NONE) != 0)
return 0;
return SSH_ERR_INVALID_ARGUMENT;
#else
if ((cc->cipher->flags & CFLAG_NONE) != 0) {
ret = 0;
goto out;
}
ret = SSH_ERR_INVALID_ARGUMENT;
goto out;
#else /* WITH_OPENSSL */
type = (*cipher->evptype)();
EVP_CIPHER_CTX_init(&cc->evp);
if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
if ((cc->evp = EVP_CIPHER_CTX_new()) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv,
(do_encrypt == CIPHER_ENCRYPT)) == 0) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto bad;
goto out;
}
if (cipher_authlen(cipher) &&
!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
-1, (u_char *)iv)) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto bad;
goto out;
}
klen = EVP_CIPHER_CTX_key_length(&cc->evp);
klen = EVP_CIPHER_CTX_key_length(cc->evp);
if (klen > 0 && keylen != (u_int)klen) {
if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) {
if (EVP_CIPHER_CTX_set_key_length(cc->evp, keylen) == 0) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto bad;
goto out;
}
}
if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
if (EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto bad;
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 bad;
goto out;
}
ret = EVP_Cipher(&cc->evp, discard, junk, cipher->discard_len);
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;
bad:
EVP_CIPHER_CTX_cleanup(&cc->evp);
return ret;
goto out;
}
}
#endif
return 0;
ret = 0;
#endif /* WITH_OPENSSL */
out:
if (ret == 0) {
/* success */
*ccp = cc;
} else {
if (cc != NULL) {
#ifdef WITH_OPENSSL
if (cc->evp != NULL)
EVP_CIPHER_CTX_free(cc->evp);
#endif /* WITH_OPENSSL */
explicit_bzero(cc, sizeof(*cc));
free(cc);
}
}
return ret;
}

/*
Expand Down Expand Up @@ -418,33 +468,33 @@ cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
if (authlen != cipher_authlen(cc->cipher))
return SSH_ERR_INVALID_ARGUMENT;
/* increment IV */
if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
1, lastiv))
return SSH_ERR_LIBCRYPTO_ERROR;
/* set tag on decyption */
if (!cc->encrypt &&
!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG,
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_TAG,
authlen, (u_char *)src + aadlen + len))
return SSH_ERR_LIBCRYPTO_ERROR;
}
if (aadlen) {
if (authlen &&
EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0)
EVP_Cipher(cc->evp, NULL, (u_char *)src, aadlen) < 0)
return SSH_ERR_LIBCRYPTO_ERROR;
memcpy(dest, src, aadlen);
}
if (len % cc->cipher->block_size)
return SSH_ERR_INVALID_ARGUMENT;
if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen,
if (EVP_Cipher(cc->evp, dest + aadlen, (u_char *)src + aadlen,
len) < 0)
return SSH_ERR_LIBCRYPTO_ERROR;
if (authlen) {
/* compute tag (on encrypt) or verify tag (on decrypt) */
if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0)
if (EVP_Cipher(cc->evp, NULL, NULL, 0) < 0)
return cc->encrypt ?
SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
if (cc->encrypt &&
!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG,
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_GET_TAG,
authlen, dest + aadlen + len))
return SSH_ERR_LIBCRYPTO_ERROR;
}
Expand All @@ -466,29 +516,32 @@ cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
return 0;
}

int
cipher_cleanup(struct sshcipher_ctx *cc)
void
cipher_free(struct sshcipher_ctx *cc)
{
if (cc == NULL || cc->cipher == NULL)
return 0;
if (cc == NULL)
return;
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx));
else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
#ifdef WITH_OPENSSL
else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
return SSH_ERR_LIBCRYPTO_ERROR;
if (cc->evp != NULL) {
EVP_CIPHER_CTX_free(cc->evp);
cc->evp = NULL;
}
#endif
return 0;
explicit_bzero(cc, sizeof(*cc));
free(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 *cc, const struct sshcipher *cipher,
const char *passphrase, int do_encrypt)
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;
Expand All @@ -498,7 +551,7 @@ cipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
digest, sizeof(digest))) != 0)
goto out;

r = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
r = cipher_init(ccp, cipher, digest, 16, NULL, 0, do_encrypt);
out:
explicit_bzero(digest, sizeof(digest));
return r;
Expand All @@ -523,7 +576,7 @@ cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
ivlen = sizeof(cc->ac_ctx.ctr);
#ifdef WITH_OPENSSL
else
ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
ivlen = EVP_CIPHER_CTX_iv_length(cc->evp);
#endif /* WITH_OPENSSL */
return (ivlen);
}
Expand Down Expand Up @@ -555,7 +608,7 @@ cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
case SSH_CIPHER_SSH2:
case SSH_CIPHER_DES:
case SSH_CIPHER_BLOWFISH:
evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
if (evplen == 0)
return 0;
else if (evplen < 0)
Expand All @@ -568,16 +621,16 @@ cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
else
#endif
if (cipher_authlen(c)) {
if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
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);
memcpy(iv, cc->evp->iv, len);
break;
#endif
#ifdef WITH_SSH1
case SSH_CIPHER_3DES:
return ssh1_3des_iv(&cc->evp, 0, iv, 24);
return ssh1_3des_iv(cc->evp, 0, iv, 24);
#endif
default:
return SSH_ERR_INVALID_ARGUMENT;
Expand All @@ -603,21 +656,21 @@ cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
case SSH_CIPHER_SSH2:
case SSH_CIPHER_DES:
case SSH_CIPHER_BLOWFISH:
evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
if (evplen <= 0)
return SSH_ERR_LIBCRYPTO_ERROR;
if (cipher_authlen(c)) {
/* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
if (!EVP_CIPHER_CTX_ctrl(&cc->evp,
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);
memcpy(cc->evp->iv, iv, evplen);
break;
#endif
#ifdef WITH_SSH1
case SSH_CIPHER_3DES:
return ssh1_3des_iv(&cc->evp, 1, (u_char *)iv, 24);
return ssh1_3des_iv(cc->evp, 1, (u_char *)iv, 24);
#endif
default:
return SSH_ERR_INVALID_ARGUMENT;
Expand All @@ -626,8 +679,8 @@ cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
}

#ifdef WITH_OPENSSL
#define EVP_X_STATE(evp) (evp).cipher_data
#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size
#define EVP_X_STATE(evp) (evp)->cipher_data
#define EVP_X_STATE_LEN(evp) (evp)->cipher->ctx_size
#endif

int
Expand Down
Loading

0 comments on commit 4706c1d

Please sign in to comment.