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

Diff for /src/usr.bin/ssh/kexecdh.c between version 1.7 and 1.8

version 1.7, 2018/12/27 03:25:25 version 1.8, 2019/01/21 10:29:56
Line 1 
Line 1 
 /* $OpenBSD$ */  /* $OpenBSD$ */
 /*  /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.  
  * Copyright (c) 2010 Damien Miller.  All rights reserved.   * Copyright (c) 2010 Damien Miller.  All rights reserved.
    * Copyright (c) 2019 Markus Friedl.  All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 26 
Line 26 
   
 #include <sys/types.h>  #include <sys/types.h>
   
 #include <signal.h>  #include <stdio.h>
 #include <string.h>  #include <string.h>
   #include <signal.h>
   
 #include <openssl/bn.h>  
 #include <openssl/evp.h>  
 #include <openssl/ec.h>  
 #include <openssl/ecdh.h>  #include <openssl/ecdh.h>
   
 #include "ssh2.h"  
 #include "sshkey.h"  #include "sshkey.h"
 #include "cipher.h"  
 #include "kex.h"  #include "kex.h"
 #include "sshbuf.h"  #include "sshbuf.h"
 #include "digest.h"  #include "digest.h"
 #include "ssherr.h"  #include "ssherr.h"
   
   static int
   kex_ecdh_dec_key_group(struct kex *, const u_char *, size_t, EC_KEY *key,
       const EC_GROUP *, struct sshbuf **);
   
 int  int
 kex_ecdh_hash(  kex_ecdh_keypair(struct kex *kex)
     int hash_alg,  
     const EC_GROUP *ec_group,  
     const struct sshbuf *client_version,  
     const struct sshbuf *server_version,  
     const u_char *ckexinit, size_t ckexinitlen,  
     const u_char *skexinit, size_t skexinitlen,  
     const u_char *serverhostkeyblob, size_t sbloblen,  
     const EC_POINT *client_dh_pub,  
     const EC_POINT *server_dh_pub,  
     const BIGNUM *shared_secret,  
     u_char *hash, size_t *hashlen)  
 {  {
         struct sshbuf *b;          EC_KEY *client_key = NULL;
           const EC_GROUP *group;
           const EC_POINT *public_key;
           struct sshbuf *buf = NULL;
         int r;          int r;
   
         if (*hashlen < ssh_digest_bytes(hash_alg))          if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
                 return SSH_ERR_INVALID_ARGUMENT;                  r = SSH_ERR_ALLOC_FAIL;
         if ((b = sshbuf_new()) == NULL)                  goto out;
                 return SSH_ERR_ALLOC_FAIL;  
         if ((r = sshbuf_put_stringb(b, client_version)) < 0 ||  
             (r = sshbuf_put_stringb(b, server_version)) < 0 ||  
             /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */  
             (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 ||  
             (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||  
             (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||  
             (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 ||  
             (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||  
             (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||  
             (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||  
             (r = sshbuf_put_ec(b, client_dh_pub, ec_group)) != 0 ||  
             (r = sshbuf_put_ec(b, server_dh_pub, ec_group)) != 0 ||  
             (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {  
                 sshbuf_free(b);  
                 return r;  
         }          }
 #ifdef DEBUG_KEX          if (EC_KEY_generate_key(client_key) != 1) {
         sshbuf_dump(b, stderr);                  r = SSH_ERR_LIBCRYPTO_ERROR;
                   goto out;
           }
           group = EC_KEY_get0_group(client_key);
           public_key = EC_KEY_get0_public_key(client_key);
   
           if ((buf = sshbuf_new()) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           if ((r = sshbuf_put_ec(buf, public_key, group)) != 0 ||
               (r = sshbuf_get_u32(buf, NULL)) != 0)
                   goto out;
   #ifdef DEBUG_KEXECDH
           fputs("client private key:\n", stderr);
           sshkey_dump_ec_key(client_key);
 #endif  #endif
         if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {          kex->ec_client_key = client_key;
                 sshbuf_free(b);          kex->ec_group = group;
                 return SSH_ERR_LIBCRYPTO_ERROR;          client_key = NULL;      /* owned by the kex */
           kex->kem_client_pub = buf;
           buf = NULL;
    out:
           EC_KEY_free(client_key);
           sshbuf_free(buf);
           return r;
   }
   
   int
   kex_ecdh_enc(struct kex *kex, const u_char *pkblob, size_t pklen,
       struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
   {
           const EC_GROUP *group;
           const EC_POINT *pub_key;
           EC_KEY *server_key = NULL;
           struct sshbuf *server_blob = NULL;
           int r;
   
           *server_blobp = NULL;
           *shared_secretp = NULL;
   
           if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
         }          }
         sshbuf_free(b);          if (EC_KEY_generate_key(server_key) != 1) {
         *hashlen = ssh_digest_bytes(hash_alg);                  r = SSH_ERR_LIBCRYPTO_ERROR;
 #ifdef DEBUG_KEX                  goto out;
         dump_digest("hash", hash, *hashlen);          }
           group = EC_KEY_get0_group(server_key);
   
   #ifdef DEBUG_KEXECDH
           fputs("server private key:\n", stderr);
           sshkey_dump_ec_key(server_key);
 #endif  #endif
         return 0;          pub_key = EC_KEY_get0_public_key(server_key);
           if ((server_blob = sshbuf_new()) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           if ((r = sshbuf_put_ec(server_blob, pub_key, group)) != 0 ||
               (r = sshbuf_get_u32(server_blob, NULL)) != 0)
                   goto out;
           if ((r = kex_ecdh_dec_key_group(kex, pkblob, pklen, server_key, group,
               shared_secretp)) != 0)
                   goto out;
           *server_blobp = server_blob;
           server_blob = NULL;
    out:
           EC_KEY_free(server_key);
           sshbuf_free(server_blob);
           return r;
   }
   
   static int
   kex_ecdh_dec_key_group(struct kex *kex, const u_char *pkblob, size_t pklen,
       EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp)
   {
           struct sshbuf *buf = NULL;
           BIGNUM *shared_secret = NULL;
           EC_POINT *dh_pub = NULL;
           u_char *kbuf = NULL;
           size_t klen = 0;
           int r;
   
           *shared_secretp = NULL;
   
           if ((buf = sshbuf_new()) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           if ((r = sshbuf_put_u32(buf, pklen)) != 0 ||
               (r = sshbuf_put(buf, pkblob, pklen)) != 0) {
                   goto out;
           }
           if ((dh_pub = EC_POINT_new(group)) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) {
                   goto out;
           }
           sshbuf_reset(buf);
   
   #ifdef DEBUG_KEXECDH
           fputs("public key:\n", stderr);
           sshkey_dump_ec_point(group, dh_pub);
   #endif
           if (sshkey_ec_validate_public(group, dh_pub) != 0) {
                   r = SSH_ERR_MESSAGE_INCOMPLETE;
                   goto out;
           }
           klen = (EC_GROUP_get_degree(group) + 7) / 8;
           if ((kbuf = malloc(klen)) == NULL ||
               (shared_secret = BN_new()) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen ||
               BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
                   r = SSH_ERR_LIBCRYPTO_ERROR;
                   goto out;
           }
   #ifdef DEBUG_KEXECDH
           dump_digest("shared secret", kbuf, klen);
   #endif
           if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0)
                   goto out;
           *shared_secretp = buf;
           buf = NULL;
    out:
           EC_POINT_clear_free(dh_pub);
           BN_clear_free(shared_secret);
           freezero(kbuf, klen);
           sshbuf_free(buf);
           return r;
   }
   
   int
   kex_ecdh_dec(struct kex *kex, const u_char *pkblob, size_t pklen,
       struct sshbuf **shared_secretp)
   {
           int r;
   
           r = kex_ecdh_dec_key_group(kex, pkblob, pklen, kex->ec_client_key,
               kex->ec_group, shared_secretp);
           EC_KEY_free(kex->ec_client_key);
           kex->ec_client_key = NULL;
           return r;
 }  }

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8