[BACK]Return to cipher.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/cipher.c between version 1.98 and 1.99

version 1.98, 2014/04/29 18:01:49 version 1.99, 2014/06/24 01:13:21
Line 41 
Line 41 
 #include <stdarg.h>  #include <stdarg.h>
 #include <stdio.h>  #include <stdio.h>
   
 #include "xmalloc.h"  
 #include "log.h"  
 #include "misc.h"  
 #include "cipher.h"  #include "cipher.h"
 #include "buffer.h"  #include "misc.h"
   #include "sshbuf.h"
   #include "ssherr.h"
 #include "digest.h"  #include "digest.h"
   
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
 extern const EVP_CIPHER *evp_ssh1_bf(void);  extern const EVP_CIPHER *evp_ssh1_bf(void);
 extern const EVP_CIPHER *evp_ssh1_3des(void);  extern const EVP_CIPHER *evp_ssh1_3des(void);
 extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);  extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
 #endif  #endif
   
 struct Cipher {  struct sshcipher {
         char    *name;          char    *name;
         int     number;         /* for ssh1 only */          int     number;         /* for ssh1 only */
         u_int   block_size;          u_int   block_size;
Line 74 
Line 73 
 #endif  #endif
 };  };
   
 static const struct Cipher ciphers[] = {  static const struct sshcipher ciphers[] = {
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
         { "des",        SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },          { "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 },          { "3des",       SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
Line 116 
Line 115 
   
 /*--*/  /*--*/
   
 /* Returns a list of supported ciphers separated by the specified char. */  /* Returns a comma-separated list of supported ciphers. */
 char *  char *
 cipher_alg_list(char sep, int auth_only)  cipher_alg_list(char sep, int auth_only)
 {  {
         char *ret = NULL;          char *tmp, *ret = NULL;
         size_t nlen, rlen = 0;          size_t nlen, rlen = 0;
         const Cipher *c;          const struct sshcipher *c;
   
         for (c = ciphers; c->name != NULL; c++) {          for (c = ciphers; c->name != NULL; c++) {
                 if (c->number != SSH_CIPHER_SSH2)                  if (c->number != SSH_CIPHER_SSH2)
Line 132 
Line 131 
                 if (ret != NULL)                  if (ret != NULL)
                         ret[rlen++] = sep;                          ret[rlen++] = sep;
                 nlen = strlen(c->name);                  nlen = strlen(c->name);
                 ret = xrealloc(ret, 1, rlen + nlen + 2);                  if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
                           free(ret);
                           return NULL;
                   }
                   ret = tmp;
                 memcpy(ret + rlen, c->name, nlen + 1);                  memcpy(ret + rlen, c->name, nlen + 1);
                 rlen += nlen;                  rlen += nlen;
         }          }
Line 140 
Line 143 
 }  }
   
 u_int  u_int
 cipher_blocksize(const Cipher *c)  cipher_blocksize(const struct sshcipher *c)
 {  {
         return (c->block_size);          return (c->block_size);
 }  }
   
 u_int  u_int
 cipher_keylen(const Cipher *c)  cipher_keylen(const struct sshcipher *c)
 {  {
         return (c->key_len);          return (c->key_len);
 }  }
   
 u_int  u_int
 cipher_seclen(const Cipher *c)  cipher_seclen(const struct sshcipher *c)
 {  {
         if (strcmp("3des-cbc", c->name) == 0)          if (strcmp("3des-cbc", c->name) == 0)
                 return 14;                  return 14;
Line 160 
Line 163 
 }  }
   
 u_int  u_int
 cipher_authlen(const Cipher *c)  cipher_authlen(const struct sshcipher *c)
 {  {
         return (c->auth_len);          return (c->auth_len);
 }  }
   
 u_int  u_int
 cipher_ivlen(const Cipher *c)  cipher_ivlen(const struct sshcipher *c)
 {  {
         /*          /*
          * Default is cipher block size, except for chacha20+poly1305 that           * Default is cipher block size, except for chacha20+poly1305 that
Line 177 
Line 180 
 }  }
   
 u_int  u_int
 cipher_get_number(const Cipher *c)  cipher_get_number(const struct sshcipher *c)
 {  {
         return (c->number);          return (c->number);
 }  }
   
 u_int  u_int
 cipher_is_cbc(const Cipher *c)  cipher_is_cbc(const struct sshcipher *c)
 {  {
         return (c->flags & CFLAG_CBC) != 0;          return (c->flags & CFLAG_CBC) != 0;
 }  }
Line 200 
Line 203 
         return mask;          return mask;
 }  }
   
 const Cipher *  const struct sshcipher *
 cipher_by_name(const char *name)  cipher_by_name(const char *name)
 {  {
         const Cipher *c;          const struct sshcipher *c;
         for (c = ciphers; c->name != NULL; c++)          for (c = ciphers; c->name != NULL; c++)
                 if (strcmp(c->name, name) == 0)                  if (strcmp(c->name, name) == 0)
                         return c;                          return c;
         return NULL;          return NULL;
 }  }
   
 const Cipher *  const struct sshcipher *
 cipher_by_number(int id)  cipher_by_number(int id)
 {  {
         const Cipher *c;          const struct sshcipher *c;
         for (c = ciphers; c->name != NULL; c++)          for (c = ciphers; c->name != NULL; c++)
                 if (c->number == id)                  if (c->number == id)
                         return c;                          return c;
Line 224 
Line 227 
 int  int
 ciphers_valid(const char *names)  ciphers_valid(const char *names)
 {  {
         const Cipher *c;          const struct sshcipher *c;
         char *cipher_list, *cp;          char *cipher_list, *cp;
         char *p;          char *p;
   
         if (names == NULL || strcmp(names, "") == 0)          if (names == NULL || strcmp(names, "") == 0)
                 return 0;                  return 0;
         cipher_list = cp = xstrdup(names);          if ((cipher_list = cp = strdup(names)) == NULL)
                   return 0;
         for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';          for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
             (p = strsep(&cp, CIPHER_SEP))) {              (p = strsep(&cp, CIPHER_SEP))) {
                 c = cipher_by_name(p);                  c = cipher_by_name(p);
                 if (c == NULL || c->number != SSH_CIPHER_SSH2) {                  if (c == NULL || c->number != SSH_CIPHER_SSH2) {
                         debug("bad cipher %s [%s]", p, names);  
                         free(cipher_list);                          free(cipher_list);
                         return 0;                          return 0;
                 }                  }
         }          }
         debug3("ciphers ok: [%s]", names);  
         free(cipher_list);          free(cipher_list);
         return 1;          return 1;
 }  }
Line 253 
Line 255 
 int  int
 cipher_number(const char *name)  cipher_number(const char *name)
 {  {
         const Cipher *c;          const struct sshcipher *c;
         if (name == NULL)          if (name == NULL)
                 return -1;                  return -1;
         for (c = ciphers; c->name != NULL; c++)          for (c = ciphers; c->name != NULL; c++)
Line 265 
Line 267 
 char *  char *
 cipher_name(int id)  cipher_name(int id)
 {  {
         const Cipher *c = cipher_by_number(id);          const struct sshcipher *c = cipher_by_number(id);
         return (c==NULL) ? "<unknown>" : c->name;          return (c==NULL) ? "<unknown>" : c->name;
 }  }
   
 void  const char *
 cipher_init(CipherContext *cc, const Cipher *cipher,  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";
           return NULL;
   }
   
   int
   cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
     const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,      const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
     int do_encrypt)      int do_encrypt)
 {  {
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         static int dowarn = 1;          int ret = SSH_ERR_INTERNAL_ERROR;
         const EVP_CIPHER *type;          const EVP_CIPHER *type;
         int klen;          int klen;
         u_char *junk, *discard;          u_char *junk, *discard;
   
         if (cipher->number == SSH_CIPHER_DES) {          if (cipher->number == SSH_CIPHER_DES) {
                 if (dowarn) {  
                         error("Warning: use of DES is strongly discouraged "  
                             "due to cryptographic weaknesses");  
                         dowarn = 0;  
                 }  
                 if (keylen > 8)                  if (keylen > 8)
                         keylen = 8;                          keylen = 8;
         }          }
Line 293 
Line 301 
         cc->plaintext = (cipher->number == SSH_CIPHER_NONE);          cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
         cc->encrypt = do_encrypt;          cc->encrypt = do_encrypt;
   
         if (keylen < cipher->key_len)          if (keylen < cipher->key_len ||
                 fatal("cipher_init: key length %d is insufficient for %s.",              (iv != NULL && ivlen < cipher_ivlen(cipher)))
                     keylen, cipher->name);                  return SSH_ERR_INVALID_ARGUMENT;
         if (iv != NULL && ivlen < cipher_ivlen(cipher))  
                 fatal("cipher_init: iv length %d is insufficient for %s.",  
                     ivlen, cipher->name);  
         cc->cipher = cipher;  
   
           cc->cipher = cipher;
         if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {          if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
                 chachapoly_init(&cc->cp_ctx, key, keylen);                  return chachapoly_init(&cc->cp_ctx, key, keylen);
                 return;  
         }          }
 #ifndef WITH_OPENSSL  #ifndef WITH_OPENSSL
         if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {          if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
                 aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);                  aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
                 aesctr_ivsetup(&cc->ac_ctx, iv);                  aesctr_ivsetup(&cc->ac_ctx, iv);
                 return;                  return 0;
         }          }
         if ((cc->cipher->flags & CFLAG_NONE) != 0)          if ((cc->cipher->flags & CFLAG_NONE) != 0)
                 return;                  return 0;
         fatal("unsupported cipher");          return SSH_ERR_INVALID_ARGUMENT;
 #else  #else
         type = (*cipher->evptype)();          type = (*cipher->evptype)();
         EVP_CIPHER_CTX_init(&cc->evp);          EVP_CIPHER_CTX_init(&cc->evp);
         if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,          if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
             (do_encrypt == CIPHER_ENCRYPT)) == 0)              (do_encrypt == CIPHER_ENCRYPT)) == 0) {
                 fatal("cipher_init: EVP_CipherInit failed for %s",                  ret = SSH_ERR_LIBCRYPTO_ERROR;
                     cipher->name);                  goto bad;
           }
         if (cipher_authlen(cipher) &&          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))              -1, (u_char *)iv)) {
                 fatal("cipher_init: EVP_CTRL_GCM_SET_IV_FIXED failed for %s",                  ret = SSH_ERR_LIBCRYPTO_ERROR;
                     cipher->name);                  goto bad;
           }
         klen = EVP_CIPHER_CTX_key_length(&cc->evp);          klen = EVP_CIPHER_CTX_key_length(&cc->evp);
         if (klen > 0 && keylen != (u_int)klen) {          if (klen > 0 && keylen != (u_int)klen) {
                 debug2("cipher_init: set keylen (%d -> %d)", klen, keylen);                  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;
                         fatal("cipher_init: set keylen failed (%d -> %d)",                          goto bad;
                             klen, keylen);                  }
         }          }
         if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0)          if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
                 fatal("cipher_init: EVP_CipherInit: set key failed for %s",                  ret = SSH_ERR_LIBCRYPTO_ERROR;
                     cipher->name);                  goto bad;
           }
   
         if (cipher->discard_len > 0) {          if (cipher->discard_len > 0) {
                 junk = xmalloc(cipher->discard_len);                  if ((junk = malloc(cipher->discard_len)) == NULL ||
                 discard = xmalloc(cipher->discard_len);                      (discard = malloc(cipher->discard_len)) == NULL) {
                 if (EVP_Cipher(&cc->evp, discard, junk,                          if (junk != NULL)
                     cipher->discard_len) == 0)                                  free(junk);
                         fatal("evp_crypt: EVP_Cipher failed during discard");                          ret = SSH_ERR_ALLOC_FAIL;
                           goto bad;
                   }
                   ret = EVP_Cipher(&cc->evp, discard, junk, cipher->discard_len);
                 explicit_bzero(discard, cipher->discard_len);                  explicit_bzero(discard, cipher->discard_len);
                 free(junk);                  free(junk);
                 free(discard);                  free(discard);
                   if (ret != 1) {
                           ret = SSH_ERR_LIBCRYPTO_ERROR;
    bad:
                           EVP_CIPHER_CTX_cleanup(&cc->evp);
                           return ret;
                   }
         }          }
 #endif  #endif
           return 0;
 }  }
   
 /*  /*
Line 359 
Line 376 
  * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.   * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
  * This tag is written on encryption and verified on decryption.   * This tag is written on encryption and verified on decryption.
  * Both 'aadlen' and 'authlen' can be set to 0.   * Both 'aadlen' and 'authlen' can be set to 0.
  * cipher_crypt() returns 0 on success and -1 if the decryption integrity  
  * check fails.  
  */   */
 int  int
 cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src,  cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
     u_int len, u_int aadlen, u_int authlen)     const u_char *src, u_int len, u_int aadlen, u_int authlen)
 {  {
         if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)          if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
                 return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len,                  return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src,
                     aadlen, authlen, cc->encrypt);                      len, aadlen, authlen, cc->encrypt);
           }
 #ifndef WITH_OPENSSL  #ifndef WITH_OPENSSL
         if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {          if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
                 if (aadlen)                  if (aadlen)
Line 381 
Line 397 
                 memcpy(dest, src, aadlen + len);                  memcpy(dest, src, aadlen + len);
                 return 0;                  return 0;
         }          }
         fatal("unsupported cipher");          return SSH_ERR_INVALID_ARGUMENT;
 #else  #else
         if (authlen) {          if (authlen) {
                 u_char lastiv[1];                  u_char lastiv[1];
   
                 if (authlen != cipher_authlen(cc->cipher))                  if (authlen != cipher_authlen(cc->cipher))
                         fatal("%s: authlen mismatch %d", __func__, authlen);                          return SSH_ERR_INVALID_ARGUMENT;
                 /* increment IV */                  /* 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))                      1, lastiv))
                         fatal("%s: EVP_CTRL_GCM_IV_GEN", __func__);                          return SSH_ERR_LIBCRYPTO_ERROR;
                 /* set tag on decyption */                  /* set tag on decyption */
                 if (!cc->encrypt &&                  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))                      authlen, (u_char *)src + aadlen + len))
                         fatal("%s: EVP_CTRL_GCM_SET_TAG", __func__);                          return SSH_ERR_LIBCRYPTO_ERROR;
         }          }
         if (aadlen) {          if (aadlen) {
                 if (authlen &&                  if (authlen &&
                     EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0)                      EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0)
                         fatal("%s: EVP_Cipher(aad) failed", __func__);                          return SSH_ERR_LIBCRYPTO_ERROR;
                 memcpy(dest, src, aadlen);                  memcpy(dest, src, aadlen);
         }          }
         if (len % cc->cipher->block_size)          if (len % cc->cipher->block_size)
                 fatal("%s: bad plaintext length %d", __func__, len);                  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)              len) < 0)
                 fatal("%s: EVP_Cipher failed", __func__);                  return SSH_ERR_LIBCRYPTO_ERROR;
         if (authlen) {          if (authlen) {
                 /* compute tag (on encrypt) or verify tag (on decrypt) */                  /* 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)
                         if (cc->encrypt)                          return cc->encrypt ?
                                 fatal("%s: EVP_Cipher(final) failed", __func__);                              SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
                         else  
                                 return -1;  
                 }  
                 if (cc->encrypt &&                  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))                      authlen, dest + aadlen + len))
                         fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__);                          return SSH_ERR_LIBCRYPTO_ERROR;
         }          }
         return 0;          return 0;
 #endif  #endif
Line 428 
Line 441 
   
 /* Extract the packet length, including any decryption necessary beforehand */  /* Extract the packet length, including any decryption necessary beforehand */
 int  int
 cipher_get_length(CipherContext *cc, u_int *plenp, u_int seqnr,  cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
     const u_char *cp, u_int len)      const u_char *cp, u_int len)
 {  {
         if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)          if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
                 return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr,                  return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr,
                     cp, len);                      cp, len);
         if (len < 4)          if (len < 4)
                 return -1;                  return SSH_ERR_MESSAGE_INCOMPLETE;
         *plenp = get_u32(cp);          *plenp = get_u32(cp);
         return 0;          return 0;
 }  }
   
 void  int
 cipher_cleanup(CipherContext *cc)  cipher_cleanup(struct sshcipher_ctx *cc)
 {  {
           if (cc == NULL || cc->cipher == NULL)
                   return 0;
         if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)          if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
                 explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx));                  explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx));
         else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)          else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
                 explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));                  explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)          else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
                 error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed");                  return SSH_ERR_LIBCRYPTO_ERROR;
 #endif  #endif
           return 0;
 }  }
   
 /*  /*
  * Selects the cipher, and keys if by computing the MD5 checksum of the   * Selects the cipher, and keys if by computing the MD5 checksum of the
  * passphrase and using the resulting 16 bytes as the key.   * passphrase and using the resulting 16 bytes as the key.
  */   */
   int
 void  cipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
 cipher_set_key_string(CipherContext *cc, const Cipher *cipher,  
     const char *passphrase, int do_encrypt)      const char *passphrase, int do_encrypt)
 {  {
         u_char digest[16];          u_char digest[16];
           int r = SSH_ERR_INTERNAL_ERROR;
   
         if (ssh_digest_memory(SSH_DIGEST_MD5, passphrase, strlen(passphrase),          if ((r = ssh_digest_memory(SSH_DIGEST_MD5,
             digest, sizeof(digest)) < 0)              passphrase, strlen(passphrase),
                 fatal("%s: md5 failed", __func__);              digest, sizeof(digest))) != 0)
                   goto out;
   
         cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);          r = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
    out:
         explicit_bzero(digest, sizeof(digest));          explicit_bzero(digest, sizeof(digest));
           return r;
 }  }
   
 /*  /*
  * Exports an IV from the CipherContext required to export the key   * Exports an IV from the sshcipher_ctx required to export the key
  * state back from the unprivileged child to the privileged parent   * state back from the unprivileged child to the privileged parent
  * process.   * process.
  */   */
   
 int  int
 cipher_get_keyiv_len(const CipherContext *cc)  cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
 {  {
         const Cipher *c = cc->cipher;          const struct sshcipher *c = cc->cipher;
         int ivlen = 0;          int ivlen = 0;
   
         if (c->number == SSH_CIPHER_3DES)          if (c->number == SSH_CIPHER_3DES)
Line 492 
Line 509 
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         else          else
                 ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);                  ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
 #endif  #endif /* WITH_OPENSSL */
         return (ivlen);          return (ivlen);
 }  }
   
 void  int
 cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)  cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
 {  {
         const Cipher *c = cc->cipher;          const struct sshcipher *c = cc->cipher;
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         int evplen;          int evplen;
 #endif  #endif
   
         if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {          if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
                 if (len != 0)                  if (len != 0)
                         fatal("%s: wrong iv length %d != %d", __func__, len, 0);                          return SSH_ERR_INVALID_ARGUMENT;
                 return;                  return 0;
         }          }
         if ((cc->cipher->flags & CFLAG_NONE) != 0)          if ((cc->cipher->flags & CFLAG_NONE) != 0)
                 return;                  return 0;
   
         switch (c->number) {          switch (c->number) {
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
Line 518 
Line 535 
         case SSH_CIPHER_DES:          case SSH_CIPHER_DES:
         case SSH_CIPHER_BLOWFISH:          case SSH_CIPHER_BLOWFISH:
                 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);                  evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
                 if (evplen <= 0)                  if (evplen == 0)
                         return;                          return 0;
                   else if (evplen < 0)
                           return SSH_ERR_LIBCRYPTO_ERROR;
                 if ((u_int)evplen != len)                  if ((u_int)evplen != len)
                         fatal("%s: wrong iv length %d != %d", __func__,                          return SSH_ERR_INVALID_ARGUMENT;
                             evplen, len);  
                 if (cipher_authlen(c)) {                  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))                             len, iv))
                                fatal("%s: EVP_CTRL_GCM_IV_GEN", __func__);                                 return SSH_ERR_LIBCRYPTO_ERROR;
                 } else                  } else
                         memcpy(iv, cc->evp.iv, len);                          memcpy(iv, cc->evp.iv, len);
                 break;                  break;
 #endif  #endif
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
         case SSH_CIPHER_3DES:          case SSH_CIPHER_3DES:
                 ssh1_3des_iv(&cc->evp, 0, iv, 24);                  return ssh1_3des_iv(&cc->evp, 0, iv, 24);
                 break;  
 #endif  #endif
         default:          default:
                 fatal("%s: bad cipher %d", __func__, c->number);                  return SSH_ERR_INVALID_ARGUMENT;
         }          }
           return 0;
 }  }
   
 void  int
 cipher_set_keyiv(CipherContext *cc, u_char *iv)  cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
 {  {
         const Cipher *c = cc->cipher;          const struct sshcipher *c = cc->cipher;
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         int evplen = 0;          int evplen = 0;
 #endif  #endif
   
         if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)          if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
                 return;                  return 0;
         if ((cc->cipher->flags & CFLAG_NONE) != 0)          if ((cc->cipher->flags & CFLAG_NONE) != 0)
                 return;                  return 0;
   
         switch (c->number) {          switch (c->number) {
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
Line 560 
Line 578 
         case SSH_CIPHER_DES:          case SSH_CIPHER_DES:
         case SSH_CIPHER_BLOWFISH:          case SSH_CIPHER_BLOWFISH:
                 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);                  evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
                 if (evplen == 0)                  if (evplen <= 0)
                         return;                          return SSH_ERR_LIBCRYPTO_ERROR;
                 if (cipher_authlen(c)) {                  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, iv))                              EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
                                 fatal("%s: EVP_CTRL_GCM_SET_IV_FIXED failed",                                  return SSH_ERR_LIBCRYPTO_ERROR;
                                     __func__);  
                 } else                  } else
                         memcpy(cc->evp.iv, iv, evplen);                          memcpy(cc->evp.iv, iv, evplen);
                 break;                  break;
 #endif  #endif
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
         case SSH_CIPHER_3DES:          case SSH_CIPHER_3DES:
                 ssh1_3des_iv(&cc->evp, 1, iv, 24);                  return ssh1_3des_iv(&cc->evp, 1, (u_char *)iv, 24);
                 break;  
 #endif  #endif
         default:          default:
                 fatal("%s: bad cipher %d", __func__, c->number);                  return SSH_ERR_INVALID_ARGUMENT;
         }          }
           return 0;
 }  }
   
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
Line 587 
Line 605 
 #endif  #endif
   
 int  int
 cipher_get_keycontext(const CipherContext *cc, u_char *dat)  cipher_get_keycontext(const struct sshcipher_ctx *cc, u_char *dat)
 {  {
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         const Cipher *c = cc->cipher;          const struct sshcipher *c = cc->cipher;
         int plen = 0;          int plen = 0;
   
         if (c->evptype == EVP_rc4) {          if (c->evptype == EVP_rc4) {
Line 601 
Line 619 
         }          }
         return (plen);          return (plen);
 #else  #else
         return (0);          return 0;
 #endif  #endif
 }  }
   
 void  void
 cipher_set_keycontext(CipherContext *cc, u_char *dat)  cipher_set_keycontext(struct sshcipher_ctx *cc, const u_char *dat)
 {  {
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
         const Cipher *c = cc->cipher;          const struct sshcipher *c = cc->cipher;
         int plen;          int plen;
   
         if (c->evptype == EVP_rc4) {          if (c->evptype == EVP_rc4) {

Legend:
Removed from v.1.98  
changed lines
  Added in v.1.99