Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
970b919e76 | ||
|
|
d49bfc76c0 | ||
|
|
dea5692a68 | ||
|
|
46325ab0f9 | ||
|
|
917e85b9cc | ||
|
|
a9b364ae91 | ||
|
|
8d9a043966 | ||
|
|
afd88a7d03 | ||
|
|
7fc4e7cd73 |
No files matched your search
@@ -28,6 +28,7 @@ ssh-keyscan
|
||||
ssh-keysign
|
||||
ssh-pkcs11-helper
|
||||
ssh-sk-helper
|
||||
sshd-session
|
||||
sshd
|
||||
!regress/misc/fuzz-harness/Makefile
|
||||
!regress/unittests/sshsig/Makefile
|
||||
|
||||
+2
-2
@@ -99,7 +99,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
||||
canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \
|
||||
cleanup.o \
|
||||
compat.o fatal.o hostfile.o \
|
||||
log.o match.o moduli.o nchan.o packet.o \
|
||||
log.o match.o moduli.o nchan.o kem.o packet.o \
|
||||
readpass.o ttymodes.o xmalloc.o addr.o addrmatch.o \
|
||||
atomicio.o dispatch.o mac.o misc.o utf8.o \
|
||||
monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \
|
||||
@@ -117,7 +117,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
||||
|
||||
SKOBJS= ssh-sk-client.o
|
||||
|
||||
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
|
||||
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o kem.o \
|
||||
sshconnect.o sshconnect2.o mux.o $(SKOBJS)
|
||||
|
||||
SSHDOBJS=sshd.o \
|
||||
|
||||
@@ -27803,3 +27803,4 @@ if test "$AUDIT_MODULE" = "bsm" ; then
|
||||
echo "WARNING: BSM audit support is currently considered EXPERIMENTAL."
|
||||
echo "See the Solaris section in README.platform for details."
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,635 @@
|
||||
#include <sys/types.h>
|
||||
#include "packet.h"
|
||||
#include "kem.h"
|
||||
#include "log.h"
|
||||
#include "ssh2.h"
|
||||
#include "sshbuf.h"
|
||||
#include <openssl/core_names.h>
|
||||
|
||||
|
||||
static void dec2buf(char *, size_t, size_t);
|
||||
static size_t buf2dec(const unsigned char *, size_t);
|
||||
static int pubkey2sshbuf(struct sshbuf *, struct rsa_keys *);
|
||||
static int kem_rsa_keypair(struct kex *);
|
||||
static int kem_rsa_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **);
|
||||
|
||||
|
||||
void print_ossl_error(){
|
||||
unsigned long err = ERR_get_error();
|
||||
char e[256];
|
||||
ERR_error_string(err, e);
|
||||
debug("Error: %s", e);
|
||||
}
|
||||
|
||||
static int kem_rsa_keypair(struct kex *kex){
|
||||
int r;
|
||||
struct sshbuf *buf = NULL;
|
||||
struct rsa_keys *keys = NULL;
|
||||
|
||||
if ((buf = sshbuf_new()) == NULL){
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
}
|
||||
|
||||
kex->keys_peer = NULL;
|
||||
//kex->keys_mine = keys;
|
||||
r = init_rsa_keys(&kex->keys_peer);
|
||||
if (r != 0)
|
||||
fatal_r(r, "init_rsa_keys");
|
||||
|
||||
keys = kex->keys_mine;
|
||||
debug("Modulus: %s", keys->n);
|
||||
debug("Exponent: %s", keys->e);
|
||||
debug("Decryption: %s", keys->d);
|
||||
|
||||
/*
|
||||
* Send KEM packet to the peer
|
||||
* This packet contains our public key and the exponent e
|
||||
* Structure of the packet:
|
||||
* size_t len_n
|
||||
* unsigned char *n
|
||||
* size_t len_e
|
||||
* unsigned char *e
|
||||
*/
|
||||
if((r = pubkey2sshbuf(buf, keys)) != 0){
|
||||
sshbuf_free(buf);
|
||||
buf = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
kex->client_pub = buf;
|
||||
buf = NULL;
|
||||
r = 0;
|
||||
sshbuf_free(buf);
|
||||
return r;
|
||||
|
||||
}
|
||||
int kem_rsa1024_keypair(struct kex *kex) {
|
||||
struct rsa_keys *keys = NULL;
|
||||
int r;
|
||||
|
||||
r = init_rsa_keys(&kex->keys_mine);
|
||||
if (r != 0)
|
||||
fatal_r(r, "init_rsa_keys");
|
||||
|
||||
keys = kex->keys_mine;
|
||||
|
||||
/* Generate RSA keys */
|
||||
r = kem_gen_keys(keys, 1024);
|
||||
if (r != 0)
|
||||
fatal_r(r, "kem_gen_keys");
|
||||
|
||||
debug("Modulus: %s", keys->n);
|
||||
debug("Exponent: %s", keys->e);
|
||||
debug("Decryption: %s", keys->d);
|
||||
|
||||
return kem_rsa_keypair(kex);
|
||||
}
|
||||
int kem_rsa2048_keypair(struct kex *kex) {
|
||||
struct rsa_keys *keys = NULL;
|
||||
int r;
|
||||
|
||||
r = init_rsa_keys(&kex->keys_mine);
|
||||
if (r != 0)
|
||||
fatal_r(r, "init_rsa_keys");
|
||||
|
||||
keys = kex->keys_mine;
|
||||
|
||||
/* Generate RSA keys */
|
||||
r = kem_gen_keys(keys, 2048);
|
||||
if (r != 0)
|
||||
fatal_r(r, "kem_gen_keys");
|
||||
|
||||
return kem_rsa_keypair(kex);
|
||||
}
|
||||
/*
|
||||
* This function put the public key and the exponent e
|
||||
* in the buf which will be send to the peer
|
||||
*/
|
||||
static int pubkey2sshbuf(struct sshbuf *buf, struct rsa_keys *keys){
|
||||
int r = 0;
|
||||
char b[sizeof(size_t)];
|
||||
dec2buf(b, 0, keys->len_n);
|
||||
if ((r = sshbuf_put(buf, b, sizeof(size_t))) != 0)
|
||||
return r;
|
||||
if ((r = sshbuf_put(buf, keys->n, keys->len_n)) != 0)
|
||||
return r;
|
||||
memset(b, 0, sizeof(size_t));
|
||||
dec2buf(b, 0, keys->len_e);
|
||||
if ((r = sshbuf_put(buf, b, sizeof(size_t))) != 0)
|
||||
return r;
|
||||
if ((r = sshbuf_put(buf, keys->e, keys->len_e)) != 0)
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
static int kem_rsa_enc(struct kex *kex, const struct sshbuf *client_pubkey, struct sshbuf **serverbuf, struct sshbuf **shared_secret) {
|
||||
struct sshbuf *buf = NULL;
|
||||
struct sshbuf *buf_kem = NULL;
|
||||
int r = 0;
|
||||
const u_char *clientpub;
|
||||
size_t len_n = 0, len_e = 0;
|
||||
char *rand = NULL;
|
||||
size_t randlen;
|
||||
struct rsa_keys *keys = NULL, *keys_peer = NULL;
|
||||
unsigned char *ciphertext = NULL;
|
||||
size_t clen;
|
||||
|
||||
*serverbuf = NULL;
|
||||
*shared_secret = NULL;
|
||||
|
||||
clientpub = sshbuf_ptr(client_pubkey);
|
||||
|
||||
/*
|
||||
* Extract the client's public key and store to the struct rsa_keys
|
||||
* The structure of client_pubkey is:
|
||||
* size_t len_n
|
||||
* unsigned char *n
|
||||
* size_t len_e
|
||||
* unsigned char *e
|
||||
*/
|
||||
kex->keys_peer = NULL;
|
||||
if ((r = init_rsa_keys(&kex->keys_peer)) != 0){
|
||||
fatal_r(r, "init_rsa_keys");
|
||||
}
|
||||
|
||||
keys_peer = kex->keys_peer;
|
||||
|
||||
len_n = buf2dec(clientpub, 0);
|
||||
|
||||
if (!(keys_peer->n = (unsigned char*)malloc(len_n))){
|
||||
debug("failed to allocate modulus n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(keys_peer->n, 0, len_n);
|
||||
memcpy(keys_peer->n, clientpub + sizeof(size_t), len_n);
|
||||
|
||||
// Get the exponent e
|
||||
len_e = buf2dec(clientpub, sizeof(size_t) + len_n);
|
||||
if(!(keys_peer->e = (unsigned char *)malloc(len_e)))
|
||||
return -1;
|
||||
keys_peer->len_n = len_n;
|
||||
|
||||
memset(keys_peer->e, 0, len_e);
|
||||
memcpy(keys_peer->e, clientpub + sizeof(size_t) + len_n + sizeof(size_t), len_e);
|
||||
keys_peer->len_e = len_e;
|
||||
|
||||
/* Generate the random key, then encrypt it with the client's pubkey */
|
||||
if ((r = generate_rand_key(&rand, &randlen)) != 0){
|
||||
debug("Failed to generate rand key");
|
||||
fatal_r(r, "generate_rand_key");
|
||||
}
|
||||
|
||||
/* Allocate buffer for the shared key */
|
||||
if((buf = sshbuf_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
debug("Failed init sshbuf");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate buffer for KEM which contains the encrypted random value key
|
||||
* and the server's public key
|
||||
*/
|
||||
if((buf_kem = sshbuf_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
debug("Failed init sshbuf");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Encrypt the data with the peer's public key
|
||||
* Structure of the message
|
||||
* size_t len_n
|
||||
* unsigned char *pubkey
|
||||
* size_t len_e
|
||||
* unsigned char *e
|
||||
* size_t len_rand
|
||||
* unsigned char *rand -> encrypted with client's pubkey
|
||||
*/
|
||||
keys = kex->keys_mine;
|
||||
if((r = pubkey2sshbuf(buf_kem, keys)) != 0){
|
||||
sshbuf_free(buf);
|
||||
sshbuf_free(buf_kem);
|
||||
buf = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt the random key value with the client's public key
|
||||
* and put to buf_kem
|
||||
*/
|
||||
if((r = build_pkey(kex->keys_peer)) != 0)
|
||||
goto clean;
|
||||
if((r = encrypt_key(rand, randlen, kex->keys_peer, &ciphertext, &clen)) != 0)
|
||||
goto clean;
|
||||
|
||||
if ((r = sshbuf_put(buf_kem, ciphertext, clen)) != 0)
|
||||
goto clean;
|
||||
|
||||
if ((r = sshbuf_put_string(buf, rand, randlen)) != 0)
|
||||
goto clean;
|
||||
|
||||
*serverbuf = buf_kem;
|
||||
*shared_secret = buf;
|
||||
buf_kem = NULL;
|
||||
buf = NULL;
|
||||
|
||||
clean:
|
||||
sshbuf_free(buf);
|
||||
sshbuf_free(buf_kem);
|
||||
/* We don't use it anymore, we clean it */
|
||||
EVP_PKEY_free(keys->pkey);
|
||||
EVP_PKEY_free(kex->keys_peer->pkey);
|
||||
free(kex->keys_mine);
|
||||
free(kex->keys_peer);
|
||||
return r;
|
||||
}
|
||||
int kem_rsa2048_enc(struct kex *kex, const struct sshbuf *client_pubkey, struct sshbuf **serverbuf, struct sshbuf **shared_secret) {
|
||||
int r;
|
||||
struct rsa_keys *keys = NULL;
|
||||
|
||||
kex->keys_mine = NULL;
|
||||
r = init_rsa_keys(&kex->keys_mine);
|
||||
if (r != 0){
|
||||
debug("Failed to init rsa");
|
||||
fatal_r(r, "init_rsa_keys");
|
||||
}
|
||||
keys = kex->keys_mine;
|
||||
r = kem_gen_keys(keys, 2048);
|
||||
if (r != 0)
|
||||
fatal_r(r, "kem_gen_keys");
|
||||
|
||||
debug("Modulus server: %s", keys->n);
|
||||
debug("Exponent server: %s", keys->e);
|
||||
debug("Decryption server: %s", keys->d);
|
||||
|
||||
return kem_rsa_enc(kex, client_pubkey, serverbuf, shared_secret);
|
||||
}
|
||||
int kem_rsa1024_enc(struct kex *kex, const struct sshbuf *client_pubkey, struct sshbuf **serverbuf, struct sshbuf **shared_secret) {
|
||||
int r;
|
||||
struct rsa_keys *keys = NULL;
|
||||
|
||||
kex->keys_mine = NULL;
|
||||
r = init_rsa_keys(&kex->keys_mine);
|
||||
if (r != 0){
|
||||
debug("Failed to init rsa");
|
||||
fatal_r(r, "init_rsa_keys");
|
||||
}
|
||||
keys = kex->keys_mine;
|
||||
r = kem_gen_keys(keys, 1024);
|
||||
if (r != 0)
|
||||
fatal_r(r, "kem_gen_keys");
|
||||
|
||||
debug("Modulus server: %s", keys->n);
|
||||
debug("Exponent server: %s", keys->e);
|
||||
debug("Decryption server: %s", keys->d);
|
||||
|
||||
return kem_rsa_enc(kex, client_pubkey, serverbuf, shared_secret);
|
||||
}
|
||||
|
||||
int kem_rsa_dec(struct kex *kex, struct sshbuf *serverbuf, struct sshbuf **shared_secret) {
|
||||
struct sshbuf *buf = NULL;
|
||||
const u_char *serverpub;
|
||||
size_t len_n = 0, len_e = 0;
|
||||
unsigned char *n = NULL;
|
||||
unsigned char *e = NULL;
|
||||
unsigned char *ctext = NULL;
|
||||
size_t pos_ctext = 0;
|
||||
size_t bufsize = 0;
|
||||
size_t clen = 0;
|
||||
int r = 0;
|
||||
struct rsa_keys *keys = kex->keys_mine;
|
||||
unsigned char *ptext = NULL;
|
||||
size_t plen = 0;
|
||||
|
||||
*shared_secret = NULL;
|
||||
bufsize = sshbuf_max_size(serverbuf);
|
||||
/* Extract the server's pubkey and the ciphertext
|
||||
* Structure of the message
|
||||
* size_t len_n
|
||||
* unsigned char *pubkey
|
||||
* size_t len_e
|
||||
* unsigned char *e
|
||||
* size_t len_rand
|
||||
* unsigned char *rand -> encrypted with client's pubkey
|
||||
*/
|
||||
serverpub = sshbuf_ptr(serverbuf);
|
||||
len_n = buf2dec(serverpub, 0);
|
||||
|
||||
n = (unsigned char *)malloc(len_n);
|
||||
if (!n)
|
||||
return -1;
|
||||
memset(n, 0, len_n);
|
||||
memcpy(n, serverpub + sizeof(size_t), len_n);
|
||||
|
||||
len_e = buf2dec(serverpub + sizeof(size_t) + len_n, 0);
|
||||
e = (unsigned char *)malloc(len_e);
|
||||
if (!e){
|
||||
free(n);
|
||||
return -1;
|
||||
}
|
||||
memcpy(e, serverpub + sizeof(size_t) + len_n + sizeof(size_t), len_e);
|
||||
pos_ctext = (sizeof(size_t) * 2) + len_n + len_e;
|
||||
|
||||
clen = bufsize - pos_ctext;
|
||||
ctext = (unsigned char*)malloc(clen);
|
||||
if (!ctext){
|
||||
free(n);
|
||||
free(e);
|
||||
return -1;
|
||||
}
|
||||
memset(ctext, 0, clen);
|
||||
memcpy(ctext, serverpub + pos_ctext, clen);
|
||||
|
||||
/* Decrypt key with our private key */
|
||||
if ((r = decrypt_key(ctext, clen, keys, &ptext, &plen)) != 0)
|
||||
goto clean;
|
||||
|
||||
if ((buf = sshbuf_new()) == NULL){
|
||||
r = -1;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
sshbuf_reset(buf);
|
||||
//if ((r = sshbuf_put(buf, ptext, plen)) != 0)
|
||||
if ((r = sshbuf_put_string(buf, ptext, plen)) != 0)
|
||||
goto clean;
|
||||
debug("shared secret: %s %ld", sshbuf_ptr(buf), sshbuf_len(buf));
|
||||
*shared_secret = buf;
|
||||
|
||||
clean:
|
||||
free(n);
|
||||
free(e);
|
||||
free(ctext);
|
||||
n = NULL;
|
||||
e = NULL;
|
||||
ctext = NULL;
|
||||
buf = NULL;
|
||||
sshbuf_free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
static size_t buf2dec(const unsigned char *buffer, size_t offset) {
|
||||
size_t r = 0;
|
||||
for(size_t i = 0; i < sizeof(size_t); i++)
|
||||
r += buffer[offset++] << (i * 8);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int generate_rand_key(char **key, size_t *keylen){
|
||||
int r;
|
||||
BIGNUM *rnd = BN_new();
|
||||
BIGNUM *range = BN_new();
|
||||
char end[10];
|
||||
int i;
|
||||
for (i = 0; i < 10; i++)
|
||||
end[i] = '0' + i;
|
||||
BN_dec2bn(&range, end);
|
||||
|
||||
r = BN_rand_range(rnd, range);
|
||||
|
||||
BN_free(range);
|
||||
if (r == 0){
|
||||
BN_free(rnd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*key = BN_bn2dec(rnd);
|
||||
*keylen = strlen(*key);
|
||||
|
||||
BN_free(rnd);
|
||||
return 0;
|
||||
}
|
||||
int build_pkey(struct rsa_keys *keys){
|
||||
int r;
|
||||
|
||||
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
|
||||
|
||||
BIGNUM *n = BN_new();
|
||||
BIGNUM *e = BN_new();
|
||||
|
||||
BN_hex2bn(&n, keys->n);
|
||||
BN_hex2bn(&e, keys->e);
|
||||
|
||||
OSSL_PARAM_BLD *params = OSSL_PARAM_BLD_new();
|
||||
|
||||
if((r = OSSL_PARAM_BLD_push_BN(params, OSSL_PKEY_PARAM_RSA_N, n)) != 1)
|
||||
fatal_r(r, "OSSL_PARAM_BLD_push_BN");
|
||||
if((r = OSSL_PARAM_BLD_push_BN(params, OSSL_PKEY_PARAM_RSA_E, e)) != 1)
|
||||
fatal_r(r, "OSSL_PARAM_BLD_push_BN");
|
||||
|
||||
OSSL_PARAM *p = OSSL_PARAM_BLD_to_param(params);
|
||||
if(!p){
|
||||
OSSL_PARAM_BLD_free(params);
|
||||
OSSL_PARAM_free(p);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_PKEY_fromdata_init(ctx);
|
||||
|
||||
keys->pkey = NULL;
|
||||
|
||||
if((r = EVP_PKEY_fromdata(ctx, &keys->pkey, EVP_PKEY_PUBLIC_KEY, p)) != 1){
|
||||
logit("Failed to build PKEY");
|
||||
OSSL_PARAM_BLD_free(params);
|
||||
OSSL_PARAM_free(p);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
fatal_r(r, "EVP_PKEY_fromdata");
|
||||
}
|
||||
|
||||
OSSL_PARAM_BLD_free(params);
|
||||
OSSL_PARAM_free(p);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int decrypt_key(const char *ciphertext, const size_t clen, struct rsa_keys *keys, unsigned char **ptext, size_t *plen) {
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
int r;
|
||||
size_t outlen = 0;
|
||||
BIGNUM *bntmp = NULL;
|
||||
unsigned char *bin = NULL;
|
||||
|
||||
ctx = EVP_PKEY_CTX_new(keys->pkey, NULL);
|
||||
if (!ctx){
|
||||
logit("Failed to init pkey ctx");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = EVP_PKEY_decrypt_init(ctx);
|
||||
if (r != 1){
|
||||
logit("Failed to init pkey decrypt");
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
|
||||
EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256());
|
||||
EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256());
|
||||
|
||||
/*
|
||||
* For decrypting, we need the binary
|
||||
*/
|
||||
/* Convert hex to bin */
|
||||
bntmp = BN_new();
|
||||
BN_hex2bn(&bntmp, ciphertext);
|
||||
|
||||
size_t l = BN_num_bytes(bntmp);
|
||||
bin = (unsigned char *)OPENSSL_malloc(l);
|
||||
|
||||
if(!bin) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
BN_free(bntmp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BN_bn2bin(bntmp, bin);
|
||||
BN_free(bntmp);
|
||||
|
||||
/* We identify the buffer size */
|
||||
r = EVP_PKEY_decrypt(ctx, NULL, &outlen, bin, l);
|
||||
if (r != 1) {
|
||||
logit("Failed to get the size");
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OPENSSL_free(bin);
|
||||
print_ossl_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ptext = (unsigned char *)OPENSSL_malloc(outlen);
|
||||
|
||||
if (!*ptext) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OPENSSL_free(bin);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//r = EVP_PKEY_decrypt(ctx, out, &outlen, bin, l);
|
||||
r = EVP_PKEY_decrypt(ctx, *ptext, &outlen, bin, l);
|
||||
if (r != 1) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
OPENSSL_free(bin);
|
||||
logit("Failed to decrypt the ciphertext");
|
||||
print_ossl_error();
|
||||
fatal_r(r, "EVP_PKEY_decrypt");
|
||||
}
|
||||
//*plen = strlen(ptext);
|
||||
*plen = outlen;
|
||||
|
||||
OPENSSL_free(bin);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int encrypt_key(const char *rand, const size_t randlen, const struct rsa_keys *keys, unsigned char **ctext, size_t *clen) {
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
int r;
|
||||
size_t outlen;
|
||||
unsigned char *out;
|
||||
BIGNUM *tmp = NULL;
|
||||
|
||||
ctx = EVP_PKEY_CTX_new(keys->pkey, NULL);
|
||||
logit("Pkey: %p", keys->pkey);
|
||||
if (!ctx){
|
||||
logit("Failed to init pkey ctx");
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("Pkey size: %d", EVP_PKEY_get_size(keys->pkey));
|
||||
|
||||
r = EVP_PKEY_encrypt_init(ctx);
|
||||
if (r != 1){
|
||||
logit("Failed to init pkey encrypt");
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
|
||||
EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256());
|
||||
EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256());
|
||||
|
||||
/* We identify the buffer size */
|
||||
r = EVP_PKEY_encrypt(ctx, NULL, &outlen, rand, randlen);
|
||||
debug("Encrypted len: %ld", outlen);
|
||||
|
||||
out = (unsigned char *)OPENSSL_malloc(outlen);
|
||||
|
||||
if (!out) {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = EVP_PKEY_encrypt(ctx, out, &outlen, rand, randlen);
|
||||
|
||||
tmp = BN_new();
|
||||
BN_bin2bn(out, outlen, tmp);
|
||||
*ctext = BN_bn2hex(tmp);
|
||||
*clen = strlen(*ctext);
|
||||
|
||||
OPENSSL_free(out);
|
||||
BN_free(tmp);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int derive_key(const char *rand, const size_t randlen, char *out){
|
||||
return PKCS5_PBKDF2_HMAC(rand, randlen, NULL, 0, 5, EVP_sha256(), KEY_SIZE, out);
|
||||
}
|
||||
|
||||
int kem_gen_keys(struct rsa_keys *keys, size_t ksize){
|
||||
keys->pkey = EVP_RSA_gen(ksize);
|
||||
|
||||
if (!keys->pkey) {
|
||||
logit("Failed to gen RSA keys");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* I must extract the modulus n, the exponent and the exponent d */
|
||||
BIGNUM *n = NULL;
|
||||
BIGNUM *e = NULL;
|
||||
BIGNUM *d = NULL;
|
||||
EVP_PKEY_get_bn_param(keys->pkey, OSSL_PKEY_PARAM_RSA_N, &n);
|
||||
EVP_PKEY_get_bn_param(keys->pkey, OSSL_PKEY_PARAM_RSA_E, &e);
|
||||
EVP_PKEY_get_bn_param(keys->pkey, OSSL_PKEY_PARAM_RSA_D, &d);
|
||||
|
||||
keys->n = BN_bn2hex(n);
|
||||
debug("Hex: %s", keys->n);
|
||||
debug("strlen: %ld", strlen(keys->n));
|
||||
debug("size: %ld", sizeof(keys->n));
|
||||
keys->e = BN_bn2hex(e);
|
||||
keys->d = BN_bn2dec(d);
|
||||
|
||||
keys->len_n = strlen(keys->n);
|
||||
keys->len_e = strlen(keys->e);
|
||||
keys->len_d = strlen(keys->d);
|
||||
|
||||
/* We don't use it anymore, freeing them */
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
BN_free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_rsa_keys(struct rsa_keys **keys) {
|
||||
*keys = (struct rsa_keys*)malloc(sizeof(struct rsa_keys));
|
||||
if (!*keys) {
|
||||
logit("Failed to init RSA keys");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dec2buf(char *buffer, size_t offset, size_t in){
|
||||
size_t pos = offset;
|
||||
for (size_t i = 0; i < sizeof(size_t); i++)
|
||||
buffer[pos++] = (in >> (i * 8)) & 0xFF;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef KEM_H
|
||||
#define KEM_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/param_build.h>
|
||||
#include "kex.h"
|
||||
|
||||
struct kex;
|
||||
|
||||
#define MAX_KEM 32
|
||||
#define KEY_SIZE 32
|
||||
|
||||
|
||||
struct rsa_keys {
|
||||
EVP_PKEY *pkey;
|
||||
unsigned char *n;
|
||||
size_t len_n;
|
||||
unsigned char *e;
|
||||
size_t len_e;
|
||||
unsigned char *d;
|
||||
size_t len_d;
|
||||
};
|
||||
|
||||
struct ssh;
|
||||
|
||||
int kem_rsa1024_keypair(struct kex *);
|
||||
int kem_rsa2048_keypair(struct kex *);
|
||||
int kem_rsa1024_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **);
|
||||
int kem_rsa2048_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **);
|
||||
int kem_rsa_dec(struct kex *, struct sshbuf *, struct sshbuf **);
|
||||
int init_rsa_keys(struct rsa_keys **);
|
||||
int kem_gen_keys(struct rsa_keys *, size_t);
|
||||
int generate_rand_key(char **, size_t *);
|
||||
int build_pkey(struct rsa_keys *);
|
||||
int decrypt_key(const char *, const size_t, struct rsa_keys *, unsigned char **, size_t *);
|
||||
int encrypt_key(const char *, const size_t, const struct rsa_keys *, unsigned char **, size_t *);
|
||||
int derive_key(const char *, const size_t, char *);
|
||||
|
||||
#endif
|
||||
@@ -59,6 +59,8 @@ static const struct kexalg kexalgs[] = {
|
||||
{ KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 },
|
||||
{ KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 },
|
||||
{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
|
||||
{ KEX_KEMRSA1024, KEX_KEM_KEMRSA1024, 0, SSH_DIGEST_SHA512 },
|
||||
{ KEX_KEMRSA2048, KEX_KEM_KEMRSA2048, 0, SSH_DIGEST_SHA512 },
|
||||
#ifdef HAVE_EVP_SHA256
|
||||
{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
|
||||
#endif /* HAVE_EVP_SHA256 */
|
||||
|
||||
@@ -65,6 +65,8 @@
|
||||
#define KEX_SNTRUP761X25519_SHA512 "sntrup761x25519-sha512"
|
||||
#define KEX_SNTRUP761X25519_SHA512_OLD "[email protected]"
|
||||
#define KEX_MLKEM768X25519_SHA256 "mlkem768x25519-sha256"
|
||||
#define KEX_KEMRSA1024 "kem-rsa-1024"
|
||||
#define KEX_KEMRSA2048 "kem-rsa-2048"
|
||||
|
||||
#define COMP_NONE 0
|
||||
#define COMP_DELAYED 2
|
||||
@@ -97,6 +99,8 @@ enum kex_exchange {
|
||||
KEX_DH_GRP14_SHA256,
|
||||
KEX_DH_GRP16_SHA512,
|
||||
KEX_DH_GRP18_SHA512,
|
||||
KEX_KEM_KEMRSA1024,
|
||||
KEX_KEM_KEMRSA2048,
|
||||
KEX_DH_GEX_SHA1,
|
||||
KEX_DH_GEX_SHA256,
|
||||
KEX_ECDH_SHA2,
|
||||
@@ -138,6 +142,7 @@ struct newkeys {
|
||||
|
||||
struct ssh;
|
||||
struct sshbuf;
|
||||
struct rsa_keys;
|
||||
|
||||
struct kex {
|
||||
struct newkeys *newkeys[MODE_MAX];
|
||||
@@ -183,6 +188,8 @@ struct kex {
|
||||
u_char sntrup761_client_key[crypto_kem_sntrup761_SECRETKEYBYTES]; /* KEM */
|
||||
u_char mlkem768_client_key[crypto_kem_mlkem768_SECRETKEYBYTES]; /* KEM */
|
||||
struct sshbuf *client_pub;
|
||||
struct rsa_keys *keys_mine;
|
||||
struct rsa_keys *keys_peer;
|
||||
};
|
||||
|
||||
int kex_name_valid(const char *);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "sshbuf.h"
|
||||
#include "digest.h"
|
||||
#include "ssherr.h"
|
||||
#include "kem.h"
|
||||
|
||||
static int input_kex_gen_init(int, u_int32_t, struct ssh *);
|
||||
static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
|
||||
@@ -123,6 +124,12 @@ kex_gen_client(struct ssh *ssh)
|
||||
case KEX_KEM_MLKEM768X25519_SHA256:
|
||||
r = kex_kem_mlkem768x25519_keypair(kex);
|
||||
break;
|
||||
case KEX_KEM_KEMRSA1024:
|
||||
r = kem_rsa1024_keypair(kex);
|
||||
break;
|
||||
case KEX_KEM_KEMRSA2048:
|
||||
r = kem_rsa2048_keypair(kex);
|
||||
break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
break;
|
||||
@@ -199,6 +206,10 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
|
||||
r = kex_kem_mlkem768x25519_dec(kex, server_blob,
|
||||
&shared_secret);
|
||||
break;
|
||||
case KEX_KEM_KEMRSA1024:
|
||||
case KEX_KEM_KEMRSA2048:
|
||||
r = kem_rsa_dec(kex, server_blob, &shared_secret);
|
||||
break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
break;
|
||||
@@ -323,6 +334,14 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
|
||||
r = kex_kem_mlkem768x25519_enc(kex, client_pubkey,
|
||||
&server_pubkey, &shared_secret);
|
||||
break;
|
||||
case KEX_KEM_KEMRSA1024:
|
||||
r = kem_rsa1024_enc(kex, client_pubkey, &server_pubkey,
|
||||
&shared_secret);
|
||||
break;
|
||||
case KEX_KEM_KEMRSA2048:
|
||||
r = kem_rsa2048_enc(kex, client_pubkey, &server_pubkey,
|
||||
&shared_secret);
|
||||
break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
break;
|
||||
|
||||
@@ -268,6 +268,8 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
|
||||
ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client;
|
||||
ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
|
||||
ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
|
||||
ssh->kex->kex[KEX_KEM_KEMRSA1024] = kex_gen_client;
|
||||
ssh->kex->kex[KEX_KEM_KEMRSA2048] = kex_gen_client;
|
||||
# ifdef OPENSSL_HAS_ECC
|
||||
ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
|
||||
# endif
|
||||
|
||||
@@ -1459,6 +1459,8 @@ do_ssh2_kex(struct ssh *ssh)
|
||||
kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server;
|
||||
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
|
||||
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
|
||||
kex->kex[KEX_KEM_KEMRSA1024] = kex_gen_server;
|
||||
kex->kex[KEX_KEM_KEMRSA2048] = kex_gen_server;
|
||||
#ifdef OPENSSL_HAS_ECC
|
||||
kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user