[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.101 and 1.102

version 1.101, 2015/12/10 17:08:40 version 1.102, 2016/08/03 05:41:57
Line 53 
Line 53 
 extern int 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 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 {  struct sshcipher {
         char    *name;          char    *name;
         int     number;         /* for ssh1 only */          int     number;         /* for ssh1 only */
Line 192 
Line 201 
 }  }
   
 u_int  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)  cipher_mask_ssh1(int client)
 {  {
         u_int mask = 0;          u_int mask = 0;
Line 283 
Line 304 
 }  }
   
 int  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,      const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
     int do_encrypt)      int do_encrypt)
 {  {
 #ifdef WITH_OPENSSL          struct sshcipher_ctx *cc = NULL;
         int ret = SSH_ERR_INTERNAL_ERROR;          int ret = SSH_ERR_INTERNAL_ERROR;
   #ifdef WITH_OPENSSL
         const EVP_CIPHER *type;          const EVP_CIPHER *type;
         int klen;          int klen;
         u_char *junk, *discard;          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 (cipher->number == SSH_CIPHER_DES) {
                 if (keylen > 8)                  if (keylen > 8)
                         keylen = 8;                          keylen = 8;
         }          }
 #endif  
         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 ||
             (iv != NULL && ivlen < cipher_ivlen(cipher)))              (iv != NULL && ivlen < cipher_ivlen(cipher))) {
                 return SSH_ERR_INVALID_ARGUMENT;                  ret = SSH_ERR_INVALID_ARGUMENT;
                   goto out;
           }
   
         cc->cipher = cipher;          cc->cipher = cipher;
         if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {          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  #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 0;                  ret = 0;
                   goto out;
         }          }
         if ((cc->cipher->flags & CFLAG_NONE) != 0)          if ((cc->cipher->flags & CFLAG_NONE) != 0) {
                 return 0;                  ret = 0;
         return SSH_ERR_INVALID_ARGUMENT;                  goto out;
 #else          }
           ret = SSH_ERR_INVALID_ARGUMENT;
           goto out;
   #else /* WITH_OPENSSL */
         type = (*cipher->evptype)();          type = (*cipher->evptype)();
         EVP_CIPHER_CTX_init(&cc->evp);          if ((cc->evp = EVP_CIPHER_CTX_new()) == NULL) {
         if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,                  ret = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv,
             (do_encrypt == CIPHER_ENCRYPT)) == 0) {              (do_encrypt == CIPHER_ENCRYPT)) == 0) {
                 ret = SSH_ERR_LIBCRYPTO_ERROR;                  ret = SSH_ERR_LIBCRYPTO_ERROR;
                 goto bad;                  goto out;
         }          }
         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)) {
                 ret = SSH_ERR_LIBCRYPTO_ERROR;                  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 (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;                          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;                  ret = SSH_ERR_LIBCRYPTO_ERROR;
                 goto bad;                  goto out;
         }          }
   
         if (cipher->discard_len > 0) {          if (cipher->discard_len > 0) {
Line 349 
Line 386 
                     (discard = malloc(cipher->discard_len)) == NULL) {                      (discard = malloc(cipher->discard_len)) == NULL) {
                         free(junk);                          free(junk);
                         ret = SSH_ERR_ALLOC_FAIL;                          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);                  explicit_bzero(discard, cipher->discard_len);
                 free(junk);                  free(junk);
                 free(discard);                  free(discard);
                 if (ret != 1) {                  if (ret != 1) {
                         ret = SSH_ERR_LIBCRYPTO_ERROR;                          ret = SSH_ERR_LIBCRYPTO_ERROR;
  bad:                          goto out;
                         EVP_CIPHER_CTX_cleanup(&cc->evp);  
                         return ret;  
                 }                  }
         }          }
 #endif          ret = 0;
         return 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;
 }  }
   
 /*  /*
Line 404 
Line 454 
                 if (authlen != cipher_authlen(cc->cipher))                  if (authlen != cipher_authlen(cc->cipher))
                         return SSH_ERR_INVALID_ARGUMENT;                          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))
                         return SSH_ERR_LIBCRYPTO_ERROR;                          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))
                         return SSH_ERR_LIBCRYPTO_ERROR;                          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)
                         return SSH_ERR_LIBCRYPTO_ERROR;                          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)
                 return SSH_ERR_INVALID_ARGUMENT;                  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)
                 return SSH_ERR_LIBCRYPTO_ERROR;                  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)
                         return cc->encrypt ?                          return cc->encrypt ?
                             SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;                              SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
                 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))
                         return SSH_ERR_LIBCRYPTO_ERROR;                          return SSH_ERR_LIBCRYPTO_ERROR;
         }          }
Line 452 
Line 502 
         return 0;          return 0;
 }  }
   
 int  void
 cipher_cleanup(struct sshcipher_ctx *cc)  cipher_free(struct sshcipher_ctx *cc)
 {  {
         if (cc == NULL || cc->cipher == NULL)          if (cc == NULL)
                 return 0;                  return;
         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)          if (cc->evp != NULL) {
                 return SSH_ERR_LIBCRYPTO_ERROR;                  EVP_CIPHER_CTX_free(cc->evp);
                   cc->evp = NULL;
           }
 #endif  #endif
         return 0;          explicit_bzero(cc, sizeof(*cc));
           free(cc);
 }  }
   
 /*  /*
Line 473 
Line 526 
  * passphrase and using the resulting 16 bytes as the key.   * passphrase and using the resulting 16 bytes as the key.
  */   */
 int  int
 cipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher,  cipher_set_key_string(struct sshcipher_ctx **ccp,
     const char *passphrase, int do_encrypt)      const struct sshcipher *cipher, const char *passphrase, int do_encrypt)
 {  {
         u_char digest[16];          u_char digest[16];
         int r = SSH_ERR_INTERNAL_ERROR;          int r = SSH_ERR_INTERNAL_ERROR;
Line 484 
Line 537 
             digest, sizeof(digest))) != 0)              digest, sizeof(digest))) != 0)
                 goto out;                  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:   out:
         explicit_bzero(digest, sizeof(digest));          explicit_bzero(digest, sizeof(digest));
         return r;          return r;
Line 509 
Line 562 
                 ivlen = sizeof(cc->ac_ctx.ctr);                  ivlen = sizeof(cc->ac_ctx.ctr);
 #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 /* WITH_OPENSSL */  #endif /* WITH_OPENSSL */
         return (ivlen);          return (ivlen);
 }  }
Line 541 
Line 594 
         case SSH_CIPHER_SSH2:          case SSH_CIPHER_SSH2:
         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 0;                          return 0;
                 else if (evplen < 0)                  else if (evplen < 0)
Line 549 
Line 602 
                 if ((u_int)evplen != len)                  if ((u_int)evplen != len)
                         return SSH_ERR_INVALID_ARGUMENT;                          return SSH_ERR_INVALID_ARGUMENT;
                 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))
                                return SSH_ERR_LIBCRYPTO_ERROR;                                 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:
                 return ssh1_3des_iv(&cc->evp, 0, iv, 24);                  return ssh1_3des_iv(cc->evp, 0, iv, 24);
 #endif  #endif
         default:          default:
                 return SSH_ERR_INVALID_ARGUMENT;                  return SSH_ERR_INVALID_ARGUMENT;
Line 584 
Line 637 
         case SSH_CIPHER_SSH2:          case SSH_CIPHER_SSH2:
         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 SSH_ERR_LIBCRYPTO_ERROR;                          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 */                          /* 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))                              EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
                                 return SSH_ERR_LIBCRYPTO_ERROR;                                  return SSH_ERR_LIBCRYPTO_ERROR;
                 } 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:
                 return ssh1_3des_iv(&cc->evp, 1, (u_char *)iv, 24);                  return ssh1_3des_iv(cc->evp, 1, (u_char *)iv, 24);
 #endif  #endif
         default:          default:
                 return SSH_ERR_INVALID_ARGUMENT;                  return SSH_ERR_INVALID_ARGUMENT;
Line 607 
Line 660 
 }  }
   
 #ifdef WITH_OPENSSL  #ifdef WITH_OPENSSL
 #define EVP_X_STATE(evp)        (evp).cipher_data  #define EVP_X_STATE(evp)        (evp)->cipher_data
 #define EVP_X_STATE_LEN(evp)    (evp).cipher->ctx_size  #define EVP_X_STATE_LEN(evp)    (evp)->cipher->ctx_size
 #endif  #endif
   
 int  int

Legend:
Removed from v.1.101  
changed lines
  Added in v.1.102