mirror of
https://github.com/PowerShell/Win32-OpenSSH.git
synced 2025-07-23 14:04:59 +02:00
Prototype KEX crypto interface and kexdhc changes based on this interface
This commit is contained in:
parent
66426d7369
commit
732f0444ff
@ -258,6 +258,7 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)uuencode.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)verify.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c" />
|
||||
<ClCompile Include="..\..\..\kexdh-openssl.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -288,5 +288,8 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\kexdh-openssl.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
28
kex.h
28
kex.h
@ -121,6 +121,26 @@ struct newkeys {
|
||||
|
||||
struct ssh;
|
||||
|
||||
//KEX DH interface start
|
||||
struct sshbuf;
|
||||
typedef struct kexdhi_
|
||||
{
|
||||
//consume p and g from "in"
|
||||
int(*read_p_g)(struct kexdhi_*, struct sshbuf* in);
|
||||
//encode p and g in "out"
|
||||
int(*get_p_g)(struct kexdhi_*, struct sshbuf* out);
|
||||
//encode public key in pub
|
||||
int(*get_pub_key)(struct kexdhi_*, struct sshbuf* pub);
|
||||
//read other public key from other_pub and encode secretagreement in secret
|
||||
int(*get_secret)(struct kexdhi_*, struct sshbuf* other_pub, struct sshbuf* secret);
|
||||
void(*done)(struct kexdhi_*);
|
||||
}kexdhi;
|
||||
|
||||
kexdhi* kexdh_openssl_init(struct ssh* ssh);
|
||||
//KEX DH interface end
|
||||
|
||||
|
||||
|
||||
struct kex {
|
||||
u_char *session_id;
|
||||
size_t session_id_len;
|
||||
@ -150,6 +170,8 @@ struct kex {
|
||||
u_char **, size_t *, const u_char *, size_t, u_int);
|
||||
int (*kex[KEX_MAX])(struct ssh *);
|
||||
/* kex specific state */
|
||||
kexdhi* kexdh;
|
||||
|
||||
DH *dh; /* DH */
|
||||
u_int min, max, nbits; /* GEX */
|
||||
EC_KEY *ec_client_key; /* ECDH */
|
||||
@ -191,6 +213,12 @@ int kex_dh_hash(const char *, const char *,
|
||||
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
|
||||
const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *);
|
||||
|
||||
//version of kex_dh_hash with public keys and secret passed as sshbuf instead of BIGNUM
|
||||
int kex_dh_hash_(
|
||||
const char *, const char *, const u_char *, size_t , const u_char *, size_t ,
|
||||
const u_char *, size_t , const struct sshbuf *, const struct sshbuf *, const struct sshbuf *,
|
||||
u_char *hash, size_t *);
|
||||
|
||||
int kexgex_hash(int, const char *, const char *,
|
||||
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
|
||||
int, int, int,
|
||||
|
152
kexdh-openssl.c
Normal file
152
kexdh-openssl.c
Normal file
@ -0,0 +1,152 @@
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <openssl/dh.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "kex.h"
|
||||
#include "log.h"
|
||||
#include "packet.h"
|
||||
#include "dh.h"
|
||||
#include "ssh2.h"
|
||||
#include "dispatch.h"
|
||||
#include "compat.h"
|
||||
#include "ssherr.h"
|
||||
#include "sshbuf.h"
|
||||
|
||||
typedef struct kexdh_openssl_
|
||||
{
|
||||
kexdhi dhi;
|
||||
struct ssh* ssh;
|
||||
DH* dh;
|
||||
}kexdh_openssl;
|
||||
|
||||
|
||||
static int kexdh_get_pub_key(kexdhi* dh_, struct sshbuf* pub)
|
||||
{
|
||||
int r = 0;
|
||||
kexdh_openssl* dh = (kexdh_openssl*)dh_;
|
||||
struct kex* kex = dh->ssh->kex;
|
||||
|
||||
/* generate and send 'e', client DH public key */
|
||||
switch (kex->kex_type) {
|
||||
case KEX_DH_GRP1_SHA1:
|
||||
dh->dh = dh_new_group1();
|
||||
break;
|
||||
case KEX_DH_GRP14_SHA1:
|
||||
dh->dh = dh_new_group14();
|
||||
break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = dh_gen_key(dh->dh, kex->we_need * 8)) != 0 ||
|
||||
(r = sshpkt_put_bignum2(pub, dh->dh->pub_key)) != 0)
|
||||
goto out;
|
||||
#ifdef DEBUG_KEXDH
|
||||
DHparams_print_fp(stderr, dh->dh);
|
||||
fprintf(stderr, "pub= ");
|
||||
BN_print_fp(stderr, dh->dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
return 0;
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int kexdh_get_secret(kexdhi* dh_, struct sshbuf* other_pub, struct sshbuf* secret)
|
||||
{
|
||||
int r = 0, kout;
|
||||
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
|
||||
kexdh_openssl* dh = (kexdh_openssl*)dh_;
|
||||
struct kex* kex = dh->ssh->kex;
|
||||
size_t klen = 0;
|
||||
u_char *kbuf = NULL;
|
||||
|
||||
/* DH parameter f, server public DH key */
|
||||
if ((dh_server_pub = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = sshbuf_get_bignum2(other_pub, dh_server_pub)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "dh_server_pub= ");
|
||||
BN_print_fp(stderr, dh_server_pub);
|
||||
fprintf(stderr, "\n");
|
||||
debug("bits %d", BN_num_bits(dh_server_pub));
|
||||
#endif
|
||||
if (!dh_pub_is_valid(dh->dh, dh_server_pub)) {
|
||||
sshpkt_disconnect(dh->ssh, "bad server public DH value");
|
||||
r = SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
klen = DH_size(kex->dh);
|
||||
if ((kbuf = malloc(klen)) == NULL ||
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
|
||||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
#ifdef DEBUG_KEXDH
|
||||
dump_digest("shared secret", kbuf, kout);
|
||||
#endif
|
||||
|
||||
if ((r == sshbuf_put_bignum2(secret, shared_secret)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
if (dh_server_pub)
|
||||
BN_clear_free(dh_server_pub);
|
||||
if (kbuf) {
|
||||
explicit_bzero(kbuf, klen);
|
||||
free(kbuf);
|
||||
}
|
||||
if (shared_secret)
|
||||
BN_clear_free(shared_secret);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kexdh_done(kexdhi* dh_)
|
||||
{
|
||||
kexdh_openssl* dh = (kexdh_openssl*)dh_;
|
||||
|
||||
if (dh->dh)
|
||||
DH_free(dh->dh);
|
||||
free(dh_);
|
||||
}
|
||||
|
||||
|
||||
kexdhi* kexdh_openssl_init(struct ssh* ssh)
|
||||
{
|
||||
|
||||
kexdh_openssl *dh = malloc(sizeof(kexdh_openssl));
|
||||
|
||||
if (dh)
|
||||
{
|
||||
dh->ssh = ssh;
|
||||
dh->dhi.get_pub_key = kexdh_get_pub_key;
|
||||
dh->dhi.get_secret = kexdh_get_secret;
|
||||
dh->dhi.done = kexdh_done;
|
||||
dh->dhi.get_p_g = NULL;
|
||||
dh->dhi.read_p_g = NULL;
|
||||
}
|
||||
|
||||
return dh;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
48
kexdh.c
48
kexdh.c
@ -90,4 +90,52 @@ kex_dh_hash(
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
kex_dh_hash_(
|
||||
const char *client_version_string,
|
||||
const char *server_version_string,
|
||||
const u_char *ckexinit, size_t ckexinitlen,
|
||||
const u_char *skexinit, size_t skexinitlen,
|
||||
const u_char *serverhostkeyblob, size_t sbloblen,
|
||||
const struct sshbuf *client_dh_pub,
|
||||
const struct sshbuf *server_dh_pub,
|
||||
const struct sshbuf *shared_secret,
|
||||
u_char *hash, size_t *hashlen)
|
||||
{
|
||||
struct sshbuf *b;
|
||||
int r;
|
||||
|
||||
if (*hashlen < ssh_digest_bytes(SSH_DIGEST_SHA1))
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((b = sshbuf_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, server_version_string)) != 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_b(b, client_dh_pub)) != 0 ||
|
||||
(r = sshbuf_put_b(b, server_dh_pub)) != 0 ||
|
||||
(r = sshbuf_put_b(b, shared_secret)) != 0) {
|
||||
sshbuf_free(b);
|
||||
return r;
|
||||
}
|
||||
#ifdef DEBUG_KEX
|
||||
sshbuf_dump(b, stderr);
|
||||
#endif
|
||||
if (ssh_digest_buffer(SSH_DIGEST_SHA1, b, hash, *hashlen) != 0) {
|
||||
sshbuf_free(b);
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
}
|
||||
sshbuf_free(b);
|
||||
*hashlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
|
||||
#ifdef DEBUG_KEX
|
||||
dump_digest("hash", hash, *hashlen);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
126
kexdhc.c
126
kexdhc.c
@ -56,39 +56,29 @@ kexdh_client(struct ssh *ssh)
|
||||
{
|
||||
struct kex *kex = ssh->kex;
|
||||
int r;
|
||||
struct sshbuf *client_pub = NULL;
|
||||
|
||||
kex->kexdh = kexdh_openssl_init(ssh);
|
||||
|
||||
/* generate and send 'e', client DH public key */
|
||||
switch (kex->kex_type) {
|
||||
case KEX_DH_GRP1_SHA1:
|
||||
kex->dh = dh_new_group1();
|
||||
break;
|
||||
case KEX_DH_GRP14_SHA1:
|
||||
kex->dh = dh_new_group14();
|
||||
break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
if (kex->dh == NULL) {
|
||||
if (kex->kexdh == NULL ||
|
||||
(client_pub = sshbuf_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
debug("sending SSH2_MSG_KEXDH_INIT");
|
||||
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
|
||||
(r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
|
||||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
|
||||
(r = kex->kexdh->get_pub_key(kex->kexdh, client_pub)) != 0 ||
|
||||
(r = sshpkt_putb(ssh, client_pub)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
goto out;
|
||||
#ifdef DEBUG_KEXDH
|
||||
DHparams_print_fp(stderr, kex->dh);
|
||||
fprintf(stderr, "pub= ");
|
||||
BN_print_fp(stderr, kex->dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
debug("expecting SSH2_MSG_KEXDH_REPLY");
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh);
|
||||
r = 0;
|
||||
out:
|
||||
|
||||
out:
|
||||
if (client_pub)
|
||||
sshbuf_free(client_pub);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -97,12 +87,14 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
|
||||
struct sshkey *server_host_key = NULL;
|
||||
u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL;
|
||||
u_char *server_host_key_blob = NULL, *signature = NULL;
|
||||
u_char hash[SSH_DIGEST_MAX_LENGTH];
|
||||
size_t klen = 0, slen, sbloblen, hashlen;
|
||||
int kout, r;
|
||||
size_t slen, sbloblen, hashlen;
|
||||
const u_char* server_pub_ptr = NULL;
|
||||
size_t server_pub_len = 0;
|
||||
struct sshbuf *server_pub = NULL, *client_pub = NULL, *secret = NULL;
|
||||
int r;
|
||||
|
||||
if (kex->verify_host_key == NULL) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
@ -110,13 +102,13 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
/* key, cert */
|
||||
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
|
||||
&sbloblen)) != 0 ||
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
&sbloblen)) != 0 ||
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
goto out;
|
||||
if (server_host_key->type != kex->hostkey_type ||
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
r = SSH_ERR_KEY_TYPE_MISMATCH;
|
||||
goto out;
|
||||
}
|
||||
@ -124,54 +116,38 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
r = SSH_ERR_SIGNATURE_INVALID;
|
||||
goto out;
|
||||
}
|
||||
/* DH parameter f, server public DH key */
|
||||
if ((dh_server_pub = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* signed H */
|
||||
if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
if ((r = sshpkt_get_string_direct(ssh, &server_pub_ptr, &server_pub_len)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "dh_server_pub= ");
|
||||
BN_print_fp(stderr, dh_server_pub);
|
||||
fprintf(stderr, "\n");
|
||||
debug("bits %d", BN_num_bits(dh_server_pub));
|
||||
#endif
|
||||
if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
|
||||
sshpkt_disconnect(ssh, "bad server public DH value");
|
||||
r = SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
klen = DH_size(kex->dh);
|
||||
if ((kbuf = malloc(klen)) == NULL ||
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
if ((server_pub = sshbuf_from(server_pub_ptr - 4, server_pub_len + 4)) == NULL ||
|
||||
(secret = sshbuf_new()) == NULL ||
|
||||
(client_pub = sshbuf_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
|
||||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
|
||||
|
||||
if ((r = kex->kexdh->get_secret(kex->kexdh, server_pub, secret)) != 0 ||
|
||||
(r = kex->kexdh->get_pub_key(kex->kexdh, client_pub)) != 0)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
#ifdef DEBUG_KEXDH
|
||||
dump_digest("shared secret", kbuf, kout);
|
||||
#endif
|
||||
|
||||
|
||||
/* calc and verify H */
|
||||
hashlen = sizeof(hash);
|
||||
if ((r = kex_dh_hash(
|
||||
if ((r = kex_dh_hash_(
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
server_host_key_blob, sbloblen,
|
||||
kex->dh->pub_key,
|
||||
dh_server_pub,
|
||||
shared_secret,
|
||||
client_pub,
|
||||
server_pub,
|
||||
secret,
|
||||
hash, &hashlen)) != 0)
|
||||
goto out;
|
||||
|
||||
@ -190,20 +166,18 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
memcpy(kex->session_id, hash, kex->session_id_len);
|
||||
}
|
||||
|
||||
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
|
||||
if ((r = kex_derive_keys(ssh, hash, hashlen, secret)) == 0)
|
||||
r = kex_send_newkeys(ssh);
|
||||
out:
|
||||
explicit_bzero(hash, sizeof(hash));
|
||||
DH_free(kex->dh);
|
||||
kex->dh = NULL;
|
||||
if (dh_server_pub)
|
||||
BN_clear_free(dh_server_pub);
|
||||
if (kbuf) {
|
||||
explicit_bzero(kbuf, klen);
|
||||
free(kbuf);
|
||||
}
|
||||
if (shared_secret)
|
||||
BN_clear_free(shared_secret);
|
||||
if (client_pub)
|
||||
sshbuf_free(client_pub);
|
||||
if (server_pub)
|
||||
sshbuf_free(server_pub);
|
||||
if (secret)
|
||||
sshbuf_free(secret);
|
||||
kex->kexdh->done(kex->kexdh);
|
||||
kex->kexdh = NULL;
|
||||
sshkey_free(server_host_key);
|
||||
free(server_host_key_blob);
|
||||
free(signature);
|
||||
|
Loading…
x
Reference in New Issue
Block a user