mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-05-31 16:21:13 +03:00
[crypto] initial support for ecdh-sha2-nistp256
Works with openssl Still requires work for libgcrypt and other modes
This commit is contained in:
parent
3b72bf0880
commit
c5a998f47a
@ -35,6 +35,10 @@
|
|||||||
/* Define to 1 if you have the <openssl/des.h> header file. */
|
/* Define to 1 if you have the <openssl/des.h> header file. */
|
||||||
#cmakedefine HAVE_OPENSSL_DES_H 1
|
#cmakedefine HAVE_OPENSSL_DES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <openssl/ecdh.h> header file. */
|
||||||
|
#cmakedefine HAVE_OPENSSL_ECDH_H 1
|
||||||
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <pthread.h> header file. */
|
/* Define to 1 if you have the <pthread.h> header file. */
|
||||||
#cmakedefine HAVE_PTHREAD_H 1
|
#cmakedefine HAVE_PTHREAD_H 1
|
||||||
|
|
||||||
|
@ -40,18 +40,31 @@
|
|||||||
#undef cbc_decrypt
|
#undef cbc_decrypt
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENSSL_ECDH_H
|
||||||
|
#include <openssl/ecdh.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum ssh_key_exchange_e {
|
||||||
|
/* diffie-hellman-group1-sha1 */
|
||||||
|
SSH_KEX_DH_GROUP1_SHA1=1,
|
||||||
|
/* ecdh-sha2-nistp256 */
|
||||||
|
SSH_KEX_ECDH_SHA2_NISTP256
|
||||||
|
};
|
||||||
|
|
||||||
struct ssh_crypto_struct {
|
struct ssh_crypto_struct {
|
||||||
bignum e,f,x,k,y;
|
bignum e,f,x,k,y;
|
||||||
unsigned char session_id[SHA_DIGEST_LEN];
|
EC_KEY *ecdh_privkey;
|
||||||
|
ssh_string ecdh_client_pubkey;
|
||||||
unsigned char encryptIV[SHA_DIGEST_LEN*2];
|
ssh_string ecdh_server_pubkey;
|
||||||
unsigned char decryptIV[SHA_DIGEST_LEN*2];
|
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
||||||
|
size_t digest_len; /* len of all the fields below */
|
||||||
unsigned char decryptkey[SHA_DIGEST_LEN*2];
|
unsigned char *session_id;
|
||||||
unsigned char encryptkey[SHA_DIGEST_LEN*2];
|
unsigned char *encryptIV;
|
||||||
|
unsigned char *decryptIV;
|
||||||
unsigned char encryptMAC[SHA_DIGEST_LEN];
|
unsigned char *decryptkey;
|
||||||
unsigned char decryptMAC[SHA_DIGEST_LEN];
|
unsigned char *encryptkey;
|
||||||
|
unsigned char *encryptMAC;
|
||||||
|
unsigned char *decryptMAC;
|
||||||
unsigned char hmacbuf[EVP_MAX_MD_SIZE];
|
unsigned char hmacbuf[EVP_MAX_MD_SIZE];
|
||||||
struct crypto_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
|
struct crypto_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
|
||||||
ssh_string server_pubkey;
|
ssh_string server_pubkey;
|
||||||
@ -62,6 +75,8 @@ struct ssh_crypto_struct {
|
|||||||
int delayed_compress_out;
|
int delayed_compress_out;
|
||||||
void *compress_out_ctx; /* don't touch it */
|
void *compress_out_ctx; /* don't touch it */
|
||||||
void *compress_in_ctx; /* really, don't */
|
void *compress_in_ctx; /* really, don't */
|
||||||
|
enum ssh_key_exchange_e kex_type;
|
||||||
|
enum ssh_mac_e mac_type; /* Mac operations to use for key gen */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct crypto_struct {
|
struct crypto_struct {
|
||||||
|
@ -41,6 +41,9 @@ int dh_import_f(ssh_session session,ssh_string f_string);
|
|||||||
int dh_import_e(ssh_session session, ssh_string e_string);
|
int dh_import_e(ssh_session session, ssh_string e_string);
|
||||||
void dh_import_pubkey(ssh_session session,ssh_string pubkey_string);
|
void dh_import_pubkey(ssh_session session,ssh_string pubkey_string);
|
||||||
int dh_build_k(ssh_session session);
|
int dh_build_k(ssh_session session);
|
||||||
|
int ssh_client_dh_init(ssh_session session);
|
||||||
|
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet);
|
||||||
|
|
||||||
int make_sessionid(ssh_session session);
|
int make_sessionid(ssh_session session);
|
||||||
/* add data for the final cookie */
|
/* add data for the final cookie */
|
||||||
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||||
|
39
include/libssh/ecdh.h
Normal file
39
include/libssh/ecdh.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SSH Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 by Aris Adamantiadis
|
||||||
|
*
|
||||||
|
* The SSH Library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The SSH Library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with the SSH Library; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ECDH_H_
|
||||||
|
#define ECDH_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCRYPTO
|
||||||
|
#ifdef HAVE_OPENSSL_ECDH_H
|
||||||
|
|
||||||
|
#define HAVE_ECDH
|
||||||
|
|
||||||
|
#endif /* HAVE_OPENSSL_ECDH_H */
|
||||||
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
|
|
||||||
|
int ssh_client_ecdh_init(ssh_session session);
|
||||||
|
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ECDH_H_ */
|
@ -32,6 +32,7 @@
|
|||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
typedef SHA_CTX* SHACTX;
|
typedef SHA_CTX* SHACTX;
|
||||||
|
typedef SHA256_CTX* SHA256CTX;
|
||||||
typedef MD5_CTX* MD5CTX;
|
typedef MD5_CTX* MD5CTX;
|
||||||
typedef HMAC_CTX* HMACCTX;
|
typedef HMAC_CTX* HMACCTX;
|
||||||
|
|
||||||
@ -67,6 +68,10 @@ typedef BN_CTX* bignum_CTX;
|
|||||||
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
|
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
|
||||||
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
|
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
|
||||||
|
|
||||||
|
SHA256CTX sha256_init(void);
|
||||||
|
void sha256_update(SHA256CTX c, const void *data, unsigned long len);
|
||||||
|
void sha256_final(unsigned char *md, SHA256CTX c);
|
||||||
|
|
||||||
struct crypto_struct *ssh_get_ciphertab(void);
|
struct crypto_struct *ssh_get_ciphertab(void);
|
||||||
|
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
|
@ -30,8 +30,13 @@
|
|||||||
typedef gcry_md_hd_t SHACTX;
|
typedef gcry_md_hd_t SHACTX;
|
||||||
typedef gcry_md_hd_t MD5CTX;
|
typedef gcry_md_hd_t MD5CTX;
|
||||||
typedef gcry_md_hd_t HMACCTX;
|
typedef gcry_md_hd_t HMACCTX;
|
||||||
#define SHA_DIGEST_LEN 20
|
#define SHA_DIGEST_LENGTH 20
|
||||||
|
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||||
#define MD5_DIGEST_LEN 16
|
#define MD5_DIGEST_LEN 16
|
||||||
|
#define SHA256_DIGEST_LENGTH 32
|
||||||
|
#define SHA384_DIGEST_LENGTH 48
|
||||||
|
#define SHA512_DIGEST_LENGTH 64
|
||||||
|
|
||||||
#define EVP_MAX_MD_SIZE 36
|
#define EVP_MAX_MD_SIZE 36
|
||||||
|
|
||||||
typedef gcry_mpi_t bignum;
|
typedef gcry_mpi_t bignum;
|
||||||
|
@ -103,7 +103,7 @@ struct ssh_session_struct {
|
|||||||
enum ssh_auth_service_state_e auth_service_state;
|
enum ssh_auth_service_state_e auth_service_state;
|
||||||
enum ssh_auth_state_e auth_state;
|
enum ssh_auth_state_e auth_state;
|
||||||
enum ssh_channel_request_state_e global_req_state;
|
enum ssh_channel_request_state_e global_req_state;
|
||||||
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
|
||||||
KEX server_kex;
|
KEX server_kex;
|
||||||
KEX client_kex;
|
KEX client_kex;
|
||||||
ssh_buffer in_hashbuf;
|
ssh_buffer in_hashbuf;
|
||||||
|
@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
#define SSH2_MSG_KEXDH_INIT 30
|
#define SSH2_MSG_KEXDH_INIT 30
|
||||||
#define SSH2_MSG_KEXDH_REPLY 31
|
#define SSH2_MSG_KEXDH_REPLY 31
|
||||||
|
#define SSH2_MSG_KEX_ECDH_INIT 30
|
||||||
|
#define SSH2_MSG_KEX_ECDH_REPLY 31
|
||||||
|
#define SSH2_MSG_ECMQV_INIT 30
|
||||||
|
#define SSH2_MSG_ECMQV_REPLY 31
|
||||||
|
|
||||||
#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
||||||
#define SSH2_MSG_KEX_DH_GEX_GROUP 31
|
#define SSH2_MSG_KEX_DH_GEX_GROUP 31
|
||||||
|
@ -25,7 +25,21 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "libssh/libcrypto.h"
|
#include "libssh/libcrypto.h"
|
||||||
#include "libssh/libgcrypt.h"
|
#include "libssh/libgcrypt.h"
|
||||||
|
#include "libssh/crypto.h"
|
||||||
|
|
||||||
|
enum ssh_mac_e {
|
||||||
|
SSH_MAC_SHA1=1,
|
||||||
|
SSH_MAC_SHA256,
|
||||||
|
SSH_MAC_SHA384,
|
||||||
|
SSH_MAC_SHA512
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ssh_hmac_e {
|
||||||
|
SSH_HMAC_SHA1 = 1,
|
||||||
|
SSH_HMAC_MD5
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ssh_mac_ctx_struct *ssh_mac_ctx;
|
||||||
MD5CTX md5_init(void);
|
MD5CTX md5_init(void);
|
||||||
void md5_update(MD5CTX c, const void *data, unsigned long len);
|
void md5_update(MD5CTX c, const void *data, unsigned long len);
|
||||||
void md5_final(unsigned char *md,MD5CTX c);
|
void md5_final(unsigned char *md,MD5CTX c);
|
||||||
@ -33,9 +47,13 @@ SHACTX sha1_init(void);
|
|||||||
void sha1_update(SHACTX c, const void *data, unsigned long len);
|
void sha1_update(SHACTX c, const void *data, unsigned long len);
|
||||||
void sha1_final(unsigned char *md,SHACTX c);
|
void sha1_final(unsigned char *md,SHACTX c);
|
||||||
void sha1(unsigned char *digest,int len,unsigned char *hash);
|
void sha1(unsigned char *digest,int len,unsigned char *hash);
|
||||||
#define HMAC_SHA1 1
|
void sha256(unsigned char *digest, int len, unsigned char *hash);
|
||||||
#define HMAC_MD5 2
|
|
||||||
HMACCTX hmac_init(const void *key,int len,int type);
|
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type);
|
||||||
|
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len);
|
||||||
|
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx);
|
||||||
|
|
||||||
|
HMACCTX hmac_init(const void *key,int len, enum ssh_hmac_e type);
|
||||||
void hmac_update(HMACCTX c, const void *data, unsigned long len);
|
void hmac_update(HMACCTX c, const void *data, unsigned long len);
|
||||||
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
|
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
|
||||||
|
|
||||||
|
@ -85,6 +85,7 @@ set(libssh_SRCS
|
|||||||
crc32.c
|
crc32.c
|
||||||
crypt.c
|
crypt.c
|
||||||
dh.c
|
dh.c
|
||||||
|
ecdh.c
|
||||||
error.c
|
error.c
|
||||||
getpass.c
|
getpass.c
|
||||||
gzip.c
|
gzip.c
|
||||||
|
77
src/client.c
77
src/client.c
@ -36,6 +36,7 @@
|
|||||||
#include "libssh/socket.h"
|
#include "libssh/socket.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
#include "libssh/dh.h"
|
#include "libssh/dh.h"
|
||||||
|
#include "libssh/ecdh.h"
|
||||||
#include "libssh/threads.h"
|
#include "libssh/threads.h"
|
||||||
#include "libssh/misc.h"
|
#include "libssh/misc.h"
|
||||||
|
|
||||||
@ -176,12 +177,8 @@ end:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
|
SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
|
||||||
ssh_string f = NULL;
|
int rc;
|
||||||
ssh_string pubkey = NULL;
|
|
||||||
ssh_string signature = NULL;
|
|
||||||
(void)type;
|
(void)type;
|
||||||
(void)user;
|
(void)user;
|
||||||
ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY");
|
ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY");
|
||||||
@ -191,48 +188,23 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
|
|||||||
session->session_state,session->dh_handshake_state);
|
session->session_state,session->dh_handshake_state);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
switch(session->next_crypto->kex_type){
|
||||||
pubkey = buffer_get_ssh_string(packet);
|
case SSH_KEX_DH_GROUP1_SHA1:
|
||||||
if (pubkey == NULL){
|
rc=ssh_client_dh_reply(session, packet);
|
||||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
break;
|
||||||
|
#ifdef HAVE_ECDH
|
||||||
|
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||||
|
rc = ssh_client_ecdh_reply(session, packet);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_dh_reply");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
dh_import_pubkey(session, pubkey);
|
if(rc==SSH_OK) {
|
||||||
|
|
||||||
f = buffer_get_ssh_string(packet);
|
|
||||||
if (f == NULL) {
|
|
||||||
ssh_set_error(session,SSH_FATAL, "No F number in packet");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (dh_import_f(session, f) < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL, "Cannot import f number");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
ssh_string_burn(f);
|
|
||||||
ssh_string_free(f);
|
|
||||||
f=NULL;
|
|
||||||
signature = buffer_get_ssh_string(packet);
|
|
||||||
if (signature == NULL) {
|
|
||||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
session->dh_server_signature = signature;
|
|
||||||
signature=NULL; /* ownership changed */
|
|
||||||
if (dh_build_k(session) < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send the MSG_NEWKEYS */
|
|
||||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
packet_send(session);
|
|
||||||
ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
|
||||||
|
|
||||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||||
return SSH_PACKET_USED;
|
return SSH_PACKET_USED;
|
||||||
|
}
|
||||||
error:
|
error:
|
||||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||||
return SSH_PACKET_USED;
|
return SSH_PACKET_USED;
|
||||||
@ -274,12 +246,12 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Verify the host's signature. FIXME do it sooner */
|
/* Verify the host's signature. FIXME do it sooner */
|
||||||
signature = session->dh_server_signature;
|
signature = session->next_crypto->dh_server_signature;
|
||||||
session->dh_server_signature = NULL;
|
session->next_crypto->dh_server_signature = NULL;
|
||||||
if (signature_verify(session, signature)) {
|
if (signature_verify(session, signature)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
ssh_log(session,SSH_LOG_PROTOCOL,"Signature verified and valid");
|
||||||
/* forget it for now ... */
|
/* forget it for now ... */
|
||||||
ssh_string_burn(signature);
|
ssh_string_burn(signature);
|
||||||
ssh_string_free(signature);
|
ssh_string_free(signature);
|
||||||
@ -325,7 +297,20 @@ static int dh_handshake(ssh_session session) {
|
|||||||
|
|
||||||
switch (session->dh_handshake_state) {
|
switch (session->dh_handshake_state) {
|
||||||
case DH_STATE_INIT:
|
case DH_STATE_INIT:
|
||||||
|
switch(session->next_crypto->kex_type){
|
||||||
|
case SSH_KEX_DH_GROUP1_SHA1:
|
||||||
rc = ssh_client_dh_init(session);
|
rc = ssh_client_dh_init(session);
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_ECDH
|
||||||
|
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||||
|
rc = ssh_client_ecdh_init(session);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
rc=SSH_ERROR;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (session->version == 2) {
|
if (session->version == 2) {
|
||||||
ctx = hmac_init(session->current_crypto->encryptMAC,20,HMAC_SHA1);
|
ctx = hmac_init(session->current_crypto->encryptMAC,20,SSH_HMAC_SHA1);
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
SAFE_FREE(out);
|
SAFE_FREE(out);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -190,7 +190,7 @@ int packet_hmac_verify(ssh_session session, ssh_buffer buffer,
|
|||||||
unsigned int len;
|
unsigned int len;
|
||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
|
|
||||||
ctx = hmac_init(session->current_crypto->decryptMAC, 20, HMAC_SHA1);
|
ctx = hmac_init(session->current_crypto->decryptMAC, 20, SSH_HMAC_SHA1);
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
215
src/dh.c
215
src/dh.c
@ -521,6 +521,56 @@ int ssh_client_dh_init(ssh_session session){
|
|||||||
leave_function();
|
leave_function();
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){
|
||||||
|
ssh_string f = NULL;
|
||||||
|
ssh_string pubkey = NULL;
|
||||||
|
ssh_string signature = NULL;
|
||||||
|
int rc;
|
||||||
|
pubkey = buffer_get_ssh_string(packet);
|
||||||
|
if (pubkey == NULL){
|
||||||
|
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
dh_import_pubkey(session, pubkey);
|
||||||
|
|
||||||
|
f = buffer_get_ssh_string(packet);
|
||||||
|
if (f == NULL) {
|
||||||
|
ssh_set_error(session,SSH_FATAL, "No F number in packet");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (dh_import_f(session, f) < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Cannot import f number");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ssh_string_burn(f);
|
||||||
|
ssh_string_free(f);
|
||||||
|
f=NULL;
|
||||||
|
signature = buffer_get_ssh_string(packet);
|
||||||
|
if (signature == NULL) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
session->next_crypto->dh_server_signature = signature;
|
||||||
|
signature=NULL; /* ownership changed */
|
||||||
|
if (dh_build_k(session) < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the MSG_NEWKEYS */
|
||||||
|
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc=packet_send(session);
|
||||||
|
ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||||
|
return rc;
|
||||||
|
error:
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static void sha_add(ssh_string str,SHACTX ctx){
|
static void sha_add(ssh_string str,SHACTX ctx){
|
||||||
sha1_update(ctx,str,string_len(str)+4);
|
sha1_update(ctx,str,string_len(str)+4);
|
||||||
@ -531,7 +581,6 @@ static void sha_add(ssh_string str,SHACTX ctx){
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int make_sessionid(ssh_session session) {
|
int make_sessionid(ssh_session session) {
|
||||||
SHACTX ctx;
|
|
||||||
ssh_string num = NULL;
|
ssh_string num = NULL;
|
||||||
ssh_string str = NULL;
|
ssh_string str = NULL;
|
||||||
ssh_buffer server_hash = NULL;
|
ssh_buffer server_hash = NULL;
|
||||||
@ -542,11 +591,6 @@ int make_sessionid(ssh_session session) {
|
|||||||
|
|
||||||
enter_function();
|
enter_function();
|
||||||
|
|
||||||
ctx = sha1_init();
|
|
||||||
if (ctx == NULL) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = ssh_buffer_new();
|
buf = ssh_buffer_new();
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
return rc;
|
return rc;
|
||||||
@ -614,7 +658,7 @@ int make_sessionid(ssh_session session) {
|
|||||||
if (buffer_add_data(buf, session->next_crypto->server_pubkey, len) < 0) {
|
if (buffer_add_data(buf, session->next_crypto->server_pubkey, len) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if(session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1){
|
||||||
num = make_bignum_string(session->next_crypto->e);
|
num = make_bignum_string(session->next_crypto->e);
|
||||||
if (num == NULL) {
|
if (num == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
@ -637,6 +681,10 @@ int make_sessionid(ssh_session session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ssh_string_free(num);
|
ssh_string_free(num);
|
||||||
|
} else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256){
|
||||||
|
buffer_add_ssh_string(buf,session->next_crypto->ecdh_client_pubkey);
|
||||||
|
buffer_add_ssh_string(buf,session->next_crypto->ecdh_server_pubkey);
|
||||||
|
}
|
||||||
num = make_bignum_string(session->next_crypto->k);
|
num = make_bignum_string(session->next_crypto->k);
|
||||||
if (num == NULL) {
|
if (num == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
@ -651,8 +699,31 @@ int make_sessionid(ssh_session session) {
|
|||||||
ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
|
ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sha1_update(ctx, buffer_get_rest(buf), buffer_get_rest_len(buf));
|
switch(session->next_crypto->kex_type){
|
||||||
sha1_final(session->next_crypto->session_id, ctx);
|
case SSH_KEX_DH_GROUP1_SHA1:
|
||||||
|
session->next_crypto->digest_len = SHA_DIGEST_LENGTH;
|
||||||
|
session->next_crypto->mac_type = SSH_MAC_SHA1;
|
||||||
|
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
|
||||||
|
if(session->next_crypto->session_id == NULL){
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
|
||||||
|
session->next_crypto->session_id);
|
||||||
|
break;
|
||||||
|
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||||
|
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
|
||||||
|
session->next_crypto->mac_type = SSH_MAC_SHA256;
|
||||||
|
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
|
||||||
|
if(session->next_crypto->session_id == NULL){
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
|
||||||
|
session->next_crypto->session_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
printf("Session hash: ");
|
printf("Session hash: ");
|
||||||
@ -723,126 +794,134 @@ int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int generate_one_key(ssh_string k,
|
static int generate_one_key(ssh_string k,
|
||||||
unsigned char session_id[SHA_DIGEST_LEN],
|
struct ssh_crypto_struct *crypto, unsigned char *output, char letter) {
|
||||||
unsigned char output[SHA_DIGEST_LEN],
|
ssh_mac_ctx ctx;
|
||||||
char letter) {
|
ctx=ssh_mac_ctx_init(crypto->mac_type);
|
||||||
SHACTX ctx = NULL;
|
|
||||||
|
|
||||||
ctx = sha1_init();
|
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sha1_update(ctx, k, ssh_string_len(k) + 4);
|
ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
|
||||||
sha1_update(ctx, session_id, SHA_DIGEST_LEN);
|
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
|
||||||
sha1_update(ctx, &letter, 1);
|
ssh_mac_update(ctx, &letter, 1);
|
||||||
sha1_update(ctx, session_id, SHA_DIGEST_LEN);
|
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
|
||||||
sha1_final(output, ctx);
|
ssh_mac_final(output, ctx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int generate_session_keys(ssh_session session) {
|
int generate_session_keys(ssh_session session) {
|
||||||
ssh_string k_string = NULL;
|
ssh_string k_string = NULL;
|
||||||
SHACTX ctx = NULL;
|
ssh_mac_ctx ctx = NULL;
|
||||||
|
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
enter_function();
|
enter_function();
|
||||||
|
|
||||||
k_string = make_bignum_string(session->next_crypto->k);
|
k_string = make_bignum_string(crypto->k);
|
||||||
if (k_string == NULL) {
|
if (k_string == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto->encryptIV = malloc(crypto->digest_len);
|
||||||
|
crypto->decryptIV = malloc(crypto->digest_len);
|
||||||
|
crypto->encryptkey = malloc(crypto->digest_len);
|
||||||
|
crypto->decryptkey = malloc(crypto->digest_len);
|
||||||
|
crypto->encryptMAC = malloc(crypto->digest_len);
|
||||||
|
crypto->decryptMAC = malloc(crypto->digest_len);
|
||||||
|
if(crypto->encryptIV == NULL || crypto->decryptIV == NULL ||
|
||||||
|
crypto->encryptkey == NULL || crypto->decryptkey == NULL ||
|
||||||
|
crypto->encryptMAC == NULL || crypto->decryptMAC == NULL){
|
||||||
|
ssh_set_error_oom(session);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IV */
|
/* IV */
|
||||||
if (session->client) {
|
if (session->client) {
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->encryptIV, 'A') < 0) {
|
||||||
session->next_crypto->encryptIV, 'A') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->decryptIV, 'B') < 0) {
|
||||||
session->next_crypto->decryptIV, 'B') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->decryptIV, 'A') < 0) {
|
||||||
session->next_crypto->decryptIV, 'A') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->encryptIV, 'B') < 0) {
|
||||||
session->next_crypto->encryptIV, 'B') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (session->client) {
|
if (session->client) {
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->encryptkey, 'C') < 0) {
|
||||||
session->next_crypto->encryptkey, 'C') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->decryptkey, 'D') < 0) {
|
||||||
session->next_crypto->decryptkey, 'D') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->decryptkey, 'C') < 0) {
|
||||||
session->next_crypto->decryptkey, 'C') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->encryptkey, 'D') < 0) {
|
||||||
session->next_crypto->encryptkey, 'D') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some ciphers need more than 20 bytes of input key */
|
/* some ciphers need more than DIGEST_LEN bytes of input key */
|
||||||
/* XXX verify it's ok for server implementation */
|
if (crypto->out_cipher->keysize > crypto->digest_len * 8) {
|
||||||
if (session->next_crypto->out_cipher->keysize > SHA_DIGEST_LEN * 8) {
|
crypto->encryptkey = realloc(crypto->encryptkey, crypto->digest_len * 2);
|
||||||
ctx = sha1_init();
|
if(crypto->encryptkey == NULL)
|
||||||
|
goto error;
|
||||||
|
ctx = ssh_mac_ctx_init(crypto->mac_type);
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
sha1_update(ctx, k_string, ssh_string_len(k_string) + 4);
|
ssh_mac_update(ctx, k_string, ssh_string_len(k_string) + 4);
|
||||||
sha1_update(ctx, session->next_crypto->session_id, SHA_DIGEST_LEN);
|
ssh_mac_update(ctx, crypto->session_id,
|
||||||
sha1_update(ctx, session->next_crypto->encryptkey, SHA_DIGEST_LEN);
|
crypto->digest_len);
|
||||||
sha1_final(session->next_crypto->encryptkey + SHA_DIGEST_LEN, ctx);
|
ssh_mac_update(ctx, crypto->encryptkey, crypto->digest_len);
|
||||||
|
ssh_mac_final(crypto->encryptkey + crypto->digest_len, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->next_crypto->in_cipher->keysize > SHA_DIGEST_LEN * 8) {
|
if (crypto->in_cipher->keysize > crypto->digest_len * 8) {
|
||||||
ctx = sha1_init();
|
crypto->decryptkey = realloc(crypto->decryptkey, crypto->digest_len *2);
|
||||||
sha1_update(ctx, k_string, ssh_string_len(k_string) + 4);
|
if(crypto->decryptkey == NULL)
|
||||||
sha1_update(ctx, session->next_crypto->session_id, SHA_DIGEST_LEN);
|
goto error;
|
||||||
sha1_update(ctx, session->next_crypto->decryptkey, SHA_DIGEST_LEN);
|
ctx = ssh_mac_ctx_init(crypto->mac_type);
|
||||||
sha1_final(session->next_crypto->decryptkey + SHA_DIGEST_LEN, ctx);
|
ssh_mac_update(ctx, k_string, ssh_string_len(k_string) + 4);
|
||||||
|
ssh_mac_update(ctx, crypto->session_id,
|
||||||
|
crypto->digest_len);
|
||||||
|
ssh_mac_update(ctx, crypto->decryptkey, crypto->digest_len);
|
||||||
|
ssh_mac_final(crypto->decryptkey + crypto->digest_len, ctx);
|
||||||
}
|
}
|
||||||
if(session->client) {
|
if(session->client) {
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->encryptMAC, 'E') < 0) {
|
||||||
session->next_crypto->encryptMAC, 'E') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->decryptMAC, 'F') < 0) {
|
||||||
session->next_crypto->decryptMAC, 'F') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->decryptMAC, 'E') < 0) {
|
||||||
session->next_crypto->decryptMAC, 'E') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
if (generate_one_key(k_string, crypto, crypto->encryptMAC, 'F') < 0) {
|
||||||
session->next_crypto->encryptMAC, 'F') < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
ssh_print_hexa("Encrypt IV", session->next_crypto->encryptIV, SHA_DIGEST_LEN);
|
ssh_print_hexa("Encrypt IV", crypto->encryptIV, SHA_DIGEST_LEN);
|
||||||
ssh_print_hexa("Decrypt IV", session->next_crypto->decryptIV, SHA_DIGEST_LEN);
|
ssh_print_hexa("Decrypt IV", crypto->decryptIV, SHA_DIGEST_LEN);
|
||||||
ssh_print_hexa("Encryption key", session->next_crypto->encryptkey,
|
ssh_print_hexa("Encryption key", crypto->encryptkey,
|
||||||
session->next_crypto->out_cipher->keysize);
|
crypto->out_cipher->keysize);
|
||||||
ssh_print_hexa("Decryption key", session->next_crypto->decryptkey,
|
ssh_print_hexa("Decryption key", crypto->decryptkey,
|
||||||
session->next_crypto->in_cipher->keysize);
|
crypto->in_cipher->keysize);
|
||||||
ssh_print_hexa("Encryption MAC", session->next_crypto->encryptMAC, SHA_DIGEST_LEN);
|
ssh_print_hexa("Encryption MAC", crypto->encryptMAC, SHA_DIGEST_LEN);
|
||||||
ssh_print_hexa("Decryption MAC", session->next_crypto->decryptMAC, 20);
|
ssh_print_hexa("Decryption MAC", crypto->decryptMAC, 20);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
@ -1090,7 +1169,7 @@ int signature_verify(ssh_session session, ssh_string signature) {
|
|||||||
"Going to verify a %s type signature", pubkey->type_c);
|
"Going to verify a %s type signature", pubkey->type_c);
|
||||||
|
|
||||||
err = sig_verify(session,pubkey,sign,
|
err = sig_verify(session,pubkey,sign,
|
||||||
session->next_crypto->session_id,SHA_DIGEST_LEN);
|
session->next_crypto->session_id, session->next_crypto->digest_len);
|
||||||
signature_free(sign);
|
signature_free(sign);
|
||||||
session->next_crypto->server_pubkey_type = pubkey->type_c;
|
session->next_crypto->server_pubkey_type = pubkey->type_c;
|
||||||
publickey_free(pubkey);
|
publickey_free(pubkey);
|
||||||
|
167
src/ecdh.c
Normal file
167
src/ecdh.c
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SSH Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 by Aris Adamantiadis
|
||||||
|
*
|
||||||
|
* The SSH Library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The SSH Library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with the SSH Library; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "libssh/session.h"
|
||||||
|
#include "libssh/ecdh.h"
|
||||||
|
#include "libssh/buffer.h"
|
||||||
|
#include "libssh/ssh2.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_ECDH
|
||||||
|
#include <openssl/ecdh.h>
|
||||||
|
|
||||||
|
#define NISTP256 NID_X9_62_prime256v1
|
||||||
|
#define NISTP384 NID_secp384r1
|
||||||
|
#define NISTP521 NID_secp521r1
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief Starts ecdh-sha2-nistp256 key exchange
|
||||||
|
*/
|
||||||
|
int ssh_client_ecdh_init(ssh_session session){
|
||||||
|
ssh_string e = NULL;
|
||||||
|
EC_KEY *key=NULL;
|
||||||
|
const EC_GROUP *group;
|
||||||
|
const EC_POINT *pubkey;
|
||||||
|
ssh_string client_pubkey;
|
||||||
|
int len;
|
||||||
|
int rc;
|
||||||
|
bignum_CTX ctx=BN_CTX_new();
|
||||||
|
enter_function();
|
||||||
|
if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
key = EC_KEY_new_by_curve_name(NISTP256);
|
||||||
|
group = EC_KEY_get0_group(key);
|
||||||
|
EC_KEY_generate_key(key);
|
||||||
|
pubkey=EC_KEY_get0_public_key(key);
|
||||||
|
len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||||
|
NULL,0,ctx);
|
||||||
|
client_pubkey=ssh_string_new(len);
|
||||||
|
|
||||||
|
EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||||
|
ssh_string_data(client_pubkey),len,ctx);
|
||||||
|
buffer_add_ssh_string(session->out_buffer,client_pubkey);
|
||||||
|
BN_CTX_free(ctx);
|
||||||
|
session->next_crypto->ecdh_privkey = key;
|
||||||
|
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||||
|
rc = packet_send(session);
|
||||||
|
return rc;
|
||||||
|
error:
|
||||||
|
if(e != NULL){
|
||||||
|
ssh_string_burn(e);
|
||||||
|
ssh_string_free(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
leave_function();
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ecdh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
|
||||||
|
session->next_crypto->server_pubkey = pubkey_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ecdh_build_k(ssh_session session) {
|
||||||
|
const EC_GROUP *group = EC_KEY_get0_group(session->next_crypto->ecdh_privkey);
|
||||||
|
EC_POINT *pubkey=EC_POINT_new(group);
|
||||||
|
void *buffer;
|
||||||
|
int len = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||||
|
#ifdef HAVE_LIBCRYPTO
|
||||||
|
bignum_CTX ctx = bignum_ctx_new();
|
||||||
|
if (ctx == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
session->next_crypto->k = bignum_new();
|
||||||
|
if (session->next_crypto->k == NULL) {
|
||||||
|
#ifdef HAVE_LIBCRYPTO
|
||||||
|
bignum_ctx_free(ctx);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EC_POINT_oct2point(group,pubkey,ssh_string_data(session->next_crypto->ecdh_server_pubkey),
|
||||||
|
ssh_string_len(session->next_crypto->ecdh_server_pubkey),ctx);
|
||||||
|
buffer = malloc(len);
|
||||||
|
ECDH_compute_key(buffer,len,pubkey,session->next_crypto->ecdh_privkey,NULL);
|
||||||
|
BN_bin2bn(buffer,len,session->next_crypto->k);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
#ifdef DEBUG_CRYPTO
|
||||||
|
ssh_print_hexa("Session server cookie", session->server_kex.cookie, 16);
|
||||||
|
ssh_print_hexa("Session client cookie", session->client_kex.cookie, 16);
|
||||||
|
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBCRYPTO
|
||||||
|
bignum_ctx_free(ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
|
||||||
|
* a SSH_MSG_NEWKEYS
|
||||||
|
*/
|
||||||
|
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
|
||||||
|
ssh_string q_s_string = NULL;
|
||||||
|
ssh_string pubkey = NULL;
|
||||||
|
ssh_string signature = NULL;
|
||||||
|
int rc;
|
||||||
|
pubkey = buffer_get_ssh_string(packet);
|
||||||
|
if (pubkey == NULL){
|
||||||
|
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ecdh_import_pubkey(session, pubkey);
|
||||||
|
|
||||||
|
q_s_string = buffer_get_ssh_string(packet);
|
||||||
|
if (q_s_string == NULL) {
|
||||||
|
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
session->next_crypto->ecdh_server_pubkey = q_s_string;
|
||||||
|
signature = buffer_get_ssh_string(packet);
|
||||||
|
if (signature == NULL) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
session->next_crypto->dh_server_signature = signature;
|
||||||
|
signature=NULL; /* ownership changed */
|
||||||
|
if (ecdh_build_k(session) < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the MSG_NEWKEYS */
|
||||||
|
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc=packet_send(session);
|
||||||
|
ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||||
|
return rc;
|
||||||
|
error:
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_ECDH */
|
18
src/kex.c
18
src/kex.c
@ -42,6 +42,7 @@
|
|||||||
#include "libssh/dh.h"
|
#include "libssh/dh.h"
|
||||||
#include "libssh/kex.h"
|
#include "libssh/kex.h"
|
||||||
#include "libssh/string.h"
|
#include "libssh/string.h"
|
||||||
|
#include "libssh/ecdh.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
#define BLOWFISH "blowfish-cbc,"
|
#define BLOWFISH "blowfish-cbc,"
|
||||||
@ -72,8 +73,14 @@
|
|||||||
#define ZLIB "none"
|
#define ZLIB "none"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ECDH
|
||||||
|
#define KEY_EXCHANGE "ecdh-sha2-nistp256,diffie-hellman-group1-sha1"
|
||||||
|
#else
|
||||||
|
#define KEY_EXCHANGE "diffie-hellman-group1-sha1"
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *default_methods[] = {
|
const char *default_methods[] = {
|
||||||
"diffie-hellman-group1-sha1",
|
KEY_EXCHANGE,
|
||||||
"ssh-rsa,ssh-dss",
|
"ssh-rsa,ssh-dss",
|
||||||
AES BLOWFISH DES,
|
AES BLOWFISH DES,
|
||||||
AES BLOWFISH DES,
|
AES BLOWFISH DES,
|
||||||
@ -87,7 +94,7 @@ const char *default_methods[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const char *supported_methods[] = {
|
const char *supported_methods[] = {
|
||||||
"diffie-hellman-group1-sha1",
|
KEY_EXCHANGE,
|
||||||
"ssh-rsa,ssh-dss",
|
"ssh-rsa,ssh-dss",
|
||||||
AES BLOWFISH DES,
|
AES BLOWFISH DES,
|
||||||
AES BLOWFISH DES,
|
AES BLOWFISH DES,
|
||||||
@ -370,7 +377,7 @@ int set_kex(ssh_session session){
|
|||||||
ssh_get_random(client->cookie,16,0);
|
ssh_get_random(client->cookie,16,0);
|
||||||
client->methods=malloc(10 * sizeof(char **));
|
client->methods=malloc(10 * sizeof(char **));
|
||||||
if (client->methods == NULL) {
|
if (client->methods == NULL) {
|
||||||
ssh_set_error(session, SSH_FATAL, "No space left");
|
ssh_set_error_oom(session);
|
||||||
leave_function();
|
leave_function();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -394,6 +401,11 @@ int set_kex(ssh_session session){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(strcmp(client->methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
|
||||||
|
session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
|
||||||
|
} else if(strcmp(client->methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
|
||||||
|
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
|
||||||
|
}
|
||||||
leave_function();
|
leave_function();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -346,7 +346,7 @@ static int match_hashed_host(ssh_session session, const char *host,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mac = hmac_init(buffer_get_rest(salt), buffer_get_rest_len(salt), HMAC_SHA1);
|
mac = hmac_init(buffer_get_rest(salt), buffer_get_rest_len(salt), SSH_HMAC_SHA1);
|
||||||
if (mac == NULL) {
|
if (mac == NULL) {
|
||||||
ssh_buffer_free(salt);
|
ssh_buffer_free(salt);
|
||||||
ssh_buffer_free(hash);
|
ssh_buffer_free(hash);
|
||||||
|
@ -57,6 +57,14 @@
|
|||||||
|
|
||||||
#include "libssh/crypto.h"
|
#include "libssh/crypto.h"
|
||||||
|
|
||||||
|
struct ssh_mac_ctx_struct {
|
||||||
|
enum ssh_mac_e mac_type;
|
||||||
|
union {
|
||||||
|
SHACTX sha1_ctx;
|
||||||
|
SHA256CTX sha256_ctx;
|
||||||
|
} ctx;
|
||||||
|
};
|
||||||
|
|
||||||
static int alloc_key(struct crypto_struct *cipher) {
|
static int alloc_key(struct crypto_struct *cipher) {
|
||||||
cipher->key = malloc(cipher->keylen);
|
cipher->key = malloc(cipher->keylen);
|
||||||
if (cipher->key == NULL) {
|
if (cipher->key == NULL) {
|
||||||
@ -89,6 +97,29 @@ void sha1(unsigned char *digest, int len, unsigned char *hash) {
|
|||||||
SHA1(digest, len, hash);
|
SHA1(digest, len, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHA256CTX sha256_init(void){
|
||||||
|
SHA256CTX c = malloc(sizeof(*c));
|
||||||
|
if (c == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SHA256_Init(c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha256_update(SHA256CTX c, const void *data, unsigned long len){
|
||||||
|
SHA256_Update(c,data,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha256_final(unsigned char *md, SHA256CTX c) {
|
||||||
|
SHA256_Final(md, c);
|
||||||
|
SAFE_FREE(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sha256(unsigned char *digest, int len, unsigned char *hash) {
|
||||||
|
SHA256(digest, len, hash);
|
||||||
|
}
|
||||||
|
|
||||||
MD5CTX md5_init(void) {
|
MD5CTX md5_init(void) {
|
||||||
MD5CTX c = malloc(sizeof(*c));
|
MD5CTX c = malloc(sizeof(*c));
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
@ -109,7 +140,56 @@ void md5_final(unsigned char *md, MD5CTX c) {
|
|||||||
SAFE_FREE(c);
|
SAFE_FREE(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
HMACCTX hmac_init(const void *key, int len, int type) {
|
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||||
|
ssh_mac_ctx ctx=malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||||
|
ctx->mac_type=type;
|
||||||
|
switch(type){
|
||||||
|
case SSH_MAC_SHA1:
|
||||||
|
ctx->ctx.sha1_ctx = sha1_init();
|
||||||
|
return ctx;
|
||||||
|
case SSH_MAC_SHA256:
|
||||||
|
ctx->ctx.sha256_ctx = sha256_init();
|
||||||
|
return ctx;
|
||||||
|
case SSH_MAC_SHA384:
|
||||||
|
case SSH_MAC_SHA512:
|
||||||
|
default:
|
||||||
|
SAFE_FREE(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) {
|
||||||
|
switch(ctx->mac_type){
|
||||||
|
case SSH_MAC_SHA1:
|
||||||
|
sha1_update(ctx->ctx.sha1_ctx, data, len);
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA256:
|
||||||
|
sha256_update(ctx->ctx.sha256_ctx, data, len);
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA384:
|
||||||
|
case SSH_MAC_SHA512:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||||
|
switch(ctx->mac_type){
|
||||||
|
case SSH_MAC_SHA1:
|
||||||
|
sha1_final(md,ctx->ctx.sha1_ctx);
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA256:
|
||||||
|
sha256_final(md,ctx->ctx.sha256_ctx);
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA384:
|
||||||
|
case SSH_MAC_SHA512:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SAFE_FREE(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||||
HMACCTX ctx = NULL;
|
HMACCTX ctx = NULL;
|
||||||
|
|
||||||
ctx = malloc(sizeof(*ctx));
|
ctx = malloc(sizeof(*ctx));
|
||||||
@ -122,10 +202,10 @@ HMACCTX hmac_init(const void *key, int len, int type) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case HMAC_SHA1:
|
case SSH_HMAC_SHA1:
|
||||||
HMAC_Init(ctx, key, len, EVP_sha1());
|
HMAC_Init(ctx, key, len, EVP_sha1());
|
||||||
break;
|
break;
|
||||||
case HMAC_MD5:
|
case SSH_HMAC_MD5:
|
||||||
HMAC_Init(ctx, key, len, EVP_md5());
|
HMAC_Init(ctx, key, len, EVP_md5());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -31,6 +31,10 @@
|
|||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
|
||||||
|
struct ssh_mac_ctx_struct {
|
||||||
|
enum ssh_mac_e mac_type;
|
||||||
|
gcry_md_hd_t ctx;
|
||||||
|
};
|
||||||
|
|
||||||
static int alloc_key(struct crypto_struct *cipher) {
|
static int alloc_key(struct crypto_struct *cipher) {
|
||||||
cipher->key = malloc(cipher->keylen);
|
cipher->key = malloc(cipher->keylen);
|
||||||
@ -62,6 +66,10 @@ void sha1(unsigned char *digest, int len, unsigned char *hash) {
|
|||||||
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
|
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sha256(unsigned char *digest, int len, unsigned char *hash){
|
||||||
|
gcry_md_hash_buffer(GCRY_MD_SHA256, hash, digest, len);
|
||||||
|
}
|
||||||
|
|
||||||
MD5CTX md5_init(void) {
|
MD5CTX md5_init(void) {
|
||||||
MD5CTX c = NULL;
|
MD5CTX c = NULL;
|
||||||
gcry_md_open(&c, GCRY_MD_MD5, 0);
|
gcry_md_open(&c, GCRY_MD_MD5, 0);
|
||||||
@ -79,14 +87,63 @@ void md5_final(unsigned char *md, MD5CTX c) {
|
|||||||
gcry_md_close(c);
|
gcry_md_close(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
HMACCTX hmac_init(const void *key, int len, int type) {
|
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||||
|
ssh_mac_ctx ctx=malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||||
|
ctx->mac_type=type;
|
||||||
|
switch(type){
|
||||||
|
case SSH_MAC_SHA1:
|
||||||
|
gcry_md_open(&ctx->ctx, GCRY_MD_SHA1, 0);
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA256:
|
||||||
|
gcry_md_open(&ctx->ctx, GCRY_MD_SHA256, 0);
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA384:
|
||||||
|
gcry_md_open(&ctx->ctx, GCRY_MD_SHA384, 0);
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA512:
|
||||||
|
gcry_md_open(&ctx->ctx, GCRY_MD_SHA512, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SAFE_FREE(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) {
|
||||||
|
gcry_md_write(ctx->ctx,data,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||||
|
size_t len;
|
||||||
|
switch(ctx->mac_type){
|
||||||
|
case SSH_MAC_SHA1:
|
||||||
|
len=SHA_DIGEST_LEN;
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA256:
|
||||||
|
len=SHA256_DIGEST_LENGTH;
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA384:
|
||||||
|
len=SHA384_DIGEST_LENGTH;
|
||||||
|
break;
|
||||||
|
case SSH_MAC_SHA512:
|
||||||
|
len=SHA512_DIGEST_LENGTH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gcry_md_final(ctx->ctx);
|
||||||
|
memcpy(md, gcry_md_read(ctx->ctx, 0), len);
|
||||||
|
gcry_md_close(ctx->ctx);
|
||||||
|
SAFE_FREE(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||||
HMACCTX c = NULL;
|
HMACCTX c = NULL;
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case HMAC_SHA1:
|
case SSH_HMAC_SHA1:
|
||||||
gcry_md_open(&c, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
|
gcry_md_open(&c, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
|
||||||
break;
|
break;
|
||||||
case HMAC_MD5:
|
case SSH_HMAC_MD5:
|
||||||
gcry_md_open(&c, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
|
gcry_md_open(&c, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user