Unpatch Red Hat help message
This commit is contained in:
commit
bcbf9fa65f
987
openssh-10.0-mlkem-nist.patch
Normal file
987
openssh-10.0-mlkem-nist.patch
Normal file
@ -0,0 +1,987 @@
|
||||
diff --git a/crypto_api.h b/crypto_api.h
|
||||
index 8bbc3a08a..6940bbf0e 100644
|
||||
--- a/crypto_api.h
|
||||
+++ b/crypto_api.h
|
||||
@@ -58,4 +58,8 @@ int crypto_kem_sntrup761_keypair(unsigned char *pk, unsigned char *sk);
|
||||
#define crypto_kem_mlkem768_CIPHERTEXTBYTES 1088
|
||||
#define crypto_kem_mlkem768_BYTES 32
|
||||
|
||||
+#define crypto_kem_mlkem1024_PUBLICKEYBYTES 1568
|
||||
+#define crypto_kem_mlkem1024_SECRETKEYBYTES 3168
|
||||
+#define crypto_kem_mlkem1024_CIPHERTEXTBYTES 1568
|
||||
+
|
||||
#endif /* crypto_api_h */
|
||||
diff --git a/kex-names.c b/kex-names.c
|
||||
index 36a953ab2..a728e0b38 100644
|
||||
--- a/kex-names.c
|
||||
+++ b/kex-names.c
|
||||
@@ -90,6 +90,10 @@ static const struct kexalg kexalgs[] = {
|
||||
#ifdef USE_MLKEM768X25519
|
||||
{ KEX_MLKEM768X25519_SHA256, KEX_KEM_MLKEM768X25519_SHA256, 0,
|
||||
SSH_DIGEST_SHA256 },
|
||||
+ { KEX_MLKEM768NISTP256_SHA256, KEX_KEM_MLKEM768NISTP256_SHA256, 0,
|
||||
+ SSH_DIGEST_SHA256 },
|
||||
+ { KEX_MLKEM1024NISTP384_SHA384, KEX_KEM_MLKEM1024NISTP384_SHA384, 0,
|
||||
+ SSH_DIGEST_SHA384 },
|
||||
#endif
|
||||
#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
|
||||
{ NULL, 0, -1, -1},
|
||||
@@ -129,7 +133,9 @@ kex_alg_list_internal(char sep, const struct kexalg *algs)
|
||||
const struct kexalg *k;
|
||||
|
||||
for (k = algs; k->name != NULL; k++) {
|
||||
- if (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0
|
||||
+ if ( (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0
|
||||
+ || strcmp(k->name, KEX_MLKEM768NISTP256_SHA256) == 0
|
||||
+ || strcmp(k->name, KEX_MLKEM1024NISTP384_SHA384) == 0)
|
||||
&& !is_mlkem768_available())
|
||||
continue;
|
||||
if (ret != NULL)
|
||||
@@ -163,7 +169,9 @@ kex_alg_by_name(const char *name)
|
||||
{
|
||||
const struct kexalg *k;
|
||||
|
||||
- if (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0
|
||||
+ if ( (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0
|
||||
+ || strcmp(name, KEX_MLKEM768NISTP256_SHA256) == 0
|
||||
+ || strcmp(name, KEX_MLKEM1024NISTP384_SHA384) == 0)
|
||||
&& !is_mlkem768_available())
|
||||
return NULL;
|
||||
|
||||
diff --git a/kex.c b/kex.c
|
||||
index ce6a7b818..efaf5749c 100644
|
||||
--- a/kex.c
|
||||
+++ b/kex.c
|
||||
@@ -753,6 +753,7 @@ kex_free(struct kex *kex)
|
||||
#ifdef OPENSSL_HAS_ECC
|
||||
EC_KEY_free(kex->ec_client_key);
|
||||
#endif /* OPENSSL_HAS_ECC */
|
||||
+ EVP_PKEY_free(kex->ec_hybrid_client_key);
|
||||
#endif /* WITH_OPENSSL */
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
kex_free_newkeys(kex->newkeys[mode]);
|
||||
diff --git a/kex.h b/kex.h
|
||||
index 48f3bb875..50a461ddb 100644
|
||||
--- a/kex.h
|
||||
+++ b/kex.h
|
||||
@@ -72,6 +72,8 @@
|
||||
#define KEX_SNTRUP761X25519_SHA512 "sntrup761x25519-sha512"
|
||||
#define KEX_SNTRUP761X25519_SHA512_OLD "sntrup761x25519-sha512@openssh.com"
|
||||
#define KEX_MLKEM768X25519_SHA256 "mlkem768x25519-sha256"
|
||||
+#define KEX_MLKEM768NISTP256_SHA256 "mlkem768nistp256-sha256"
|
||||
+#define KEX_MLKEM1024NISTP384_SHA384 "mlkem1024nistp384-sha384"
|
||||
|
||||
#define COMP_NONE 0
|
||||
#define COMP_DELAYED 2
|
||||
@@ -110,6 +112,8 @@ enum kex_exchange {
|
||||
KEX_C25519_SHA256,
|
||||
KEX_KEM_SNTRUP761X25519_SHA512,
|
||||
KEX_KEM_MLKEM768X25519_SHA256,
|
||||
+ KEX_KEM_MLKEM768NISTP256_SHA256,
|
||||
+ KEX_KEM_MLKEM1024NISTP384_SHA384,
|
||||
#ifdef GSSAPI
|
||||
KEX_GSS_GRP1_SHA1,
|
||||
KEX_GSS_GRP14_SHA1,
|
||||
@@ -206,6 +210,9 @@ 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;
|
||||
+ /* FIXME */
|
||||
+ EVP_PKEY *ec_hybrid_client_key; /* NIST hybrids */
|
||||
+ u_char mlkem1024_client_key[crypto_kem_mlkem1024_SECRETKEYBYTES]; /* ML-KEM 1024 + NIST */
|
||||
};
|
||||
|
||||
int kex_name_valid(const char *);
|
||||
@@ -287,6 +294,18 @@ int kex_kem_mlkem768x25519_enc(struct kex *, const struct sshbuf *,
|
||||
int kex_kem_mlkem768x25519_dec(struct kex *, const struct sshbuf *,
|
||||
struct sshbuf **);
|
||||
|
||||
+int kex_kem_mlkem768nistp256_keypair(struct kex *);
|
||||
+int kex_kem_mlkem768nistp256_enc(struct kex *, const struct sshbuf *,
|
||||
+ struct sshbuf **, struct sshbuf **);
|
||||
+int kex_kem_mlkem768nistp256_dec(struct kex *, const struct sshbuf *,
|
||||
+ struct sshbuf **);
|
||||
+
|
||||
+int kex_kem_mlkem1024nistp384_keypair(struct kex *);
|
||||
+int kex_kem_mlkem1024nistp384_enc(struct kex *, const struct sshbuf *,
|
||||
+ struct sshbuf **, struct sshbuf **);
|
||||
+int kex_kem_mlkem1024nistp384_dec(struct kex *, const struct sshbuf *,
|
||||
+ struct sshbuf **);
|
||||
+
|
||||
int kex_dh_keygen(struct kex *);
|
||||
int kex_dh_compute_key(struct kex *, BIGNUM *, struct sshbuf *);
|
||||
|
||||
diff --git a/kexgen.c b/kexgen.c
|
||||
index eecdceba2..6e910f84f 100644
|
||||
--- a/kexgen.c
|
||||
+++ b/kexgen.c
|
||||
@@ -139,6 +139,22 @@ kex_gen_client(struct ssh *ssh)
|
||||
r = kex_kem_mlkem768x25519_keypair(kex);
|
||||
}
|
||||
break;
|
||||
+ case KEX_KEM_MLKEM768NISTP256_SHA256:
|
||||
+ if (FIPS_mode()) {
|
||||
+ logit_f("Key exchange type mlkem768nistp256 is not allowed in FIPS mode");
|
||||
+ r = SSH_ERR_INVALID_ARGUMENT;
|
||||
+ } else {
|
||||
+ r = kex_kem_mlkem768nistp256_keypair(kex);
|
||||
+ }
|
||||
+ break;
|
||||
+ case KEX_KEM_MLKEM1024NISTP384_SHA384:
|
||||
+ if (FIPS_mode()) {
|
||||
+ logit_f("Key exchange type mlkem1024nistp384 is not allowed in FIPS mode");
|
||||
+ r = SSH_ERR_INVALID_ARGUMENT;
|
||||
+ } else {
|
||||
+ r = kex_kem_mlkem1024nistp384_keypair(kex);
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
break;
|
||||
@@ -230,6 +246,24 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
|
||||
&shared_secret);
|
||||
}
|
||||
break;
|
||||
+ case KEX_KEM_MLKEM768NISTP256_SHA256:
|
||||
+ if (FIPS_mode()) {
|
||||
+ logit_f("Key exchange type mlkem768nistp256 is not allowed in FIPS mode");
|
||||
+ r = SSH_ERR_INVALID_ARGUMENT;
|
||||
+ } else {
|
||||
+ r = kex_kem_mlkem768nistp256_dec(kex, server_blob,
|
||||
+ &shared_secret);
|
||||
+ }
|
||||
+ break;
|
||||
+ case KEX_KEM_MLKEM1024NISTP384_SHA384:
|
||||
+ if (FIPS_mode()) {
|
||||
+ logit_f("Key exchange type mlkem1024nistp384 is not allowed in FIPS mode");
|
||||
+ r = SSH_ERR_INVALID_ARGUMENT;
|
||||
+ } else {
|
||||
+ r = kex_kem_mlkem1024nistp384_dec(kex, server_blob,
|
||||
+ &shared_secret);
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
break;
|
||||
@@ -283,6 +317,8 @@ out:
|
||||
sizeof(kex->sntrup761_client_key));
|
||||
explicit_bzero(kex->mlkem768_client_key,
|
||||
sizeof(kex->mlkem768_client_key));
|
||||
+ explicit_bzero(kex->mlkem1024_client_key,
|
||||
+ sizeof(kex->mlkem1024_client_key));
|
||||
sshbuf_free(server_host_key_blob);
|
||||
free(signature);
|
||||
sshbuf_free(tmp);
|
||||
@@ -369,6 +405,24 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
|
||||
&server_pubkey, &shared_secret);
|
||||
}
|
||||
break;
|
||||
+ case KEX_KEM_MLKEM768NISTP256_SHA256:
|
||||
+ if (FIPS_mode()) {
|
||||
+ logit_f("Key exchange type mlkem768nistp256 is not allowed in FIPS mode");
|
||||
+ r = SSH_ERR_INVALID_ARGUMENT;
|
||||
+ } else {
|
||||
+ r = kex_kem_mlkem768nistp256_enc(kex, client_pubkey,
|
||||
+ &server_pubkey, &shared_secret);
|
||||
+ }
|
||||
+ break;
|
||||
+ case KEX_KEM_MLKEM1024NISTP384_SHA384:
|
||||
+ if (FIPS_mode()) {
|
||||
+ logit_f("Key exchange type mlkem1024nistp384 is not allowed in FIPS mode");
|
||||
+ r = SSH_ERR_INVALID_ARGUMENT;
|
||||
+ } else {
|
||||
+ r = kex_kem_mlkem1024nistp384_enc(kex, client_pubkey,
|
||||
+ &server_pubkey, &shared_secret);
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
break;
|
||||
diff --git a/kexmlkem768x25519.c b/kexmlkem768x25519.c
|
||||
index 670049dcd..463d18771 100644
|
||||
--- a/kexmlkem768x25519.c
|
||||
+++ b/kexmlkem768x25519.c
|
||||
@@ -53,14 +53,15 @@
|
||||
#include <stdio.h>
|
||||
|
||||
static int
|
||||
-mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf)
|
||||
+mlkem_keypair_gen(const char *algname, unsigned char *pubkeybuf, size_t pubkey_size,
|
||||
+ unsigned char *privkeybuf, size_t privkey_size)
|
||||
{
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
int ret = SSH_ERR_INTERNAL_ERROR;
|
||||
- size_t pubkey_size = crypto_kem_mlkem768_PUBLICKEYBYTES, privkey_size = crypto_kem_mlkem768_SECRETKEYBYTES;
|
||||
+ size_t got_pub_size = pubkey_size, got_priv_size = privkey_size;
|
||||
|
||||
- ctx = EVP_PKEY_CTX_new_from_name(NULL, "mlkem768", NULL);
|
||||
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, algname, NULL);
|
||||
if (ctx == NULL) {
|
||||
ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto err;
|
||||
@@ -72,17 +73,23 @@ mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf)
|
||||
goto err;
|
||||
}
|
||||
|
||||
- if (EVP_PKEY_get_raw_public_key(pkey, pubkeybuf, &pubkey_size) <= 0
|
||||
- || EVP_PKEY_get_raw_private_key(pkey, privkeybuf, &privkey_size) <= 0) {
|
||||
+ if (EVP_PKEY_get_raw_public_key(pkey, NULL, &got_pub_size) <= 0
|
||||
+ || EVP_PKEY_get_raw_private_key(pkey, NULL, &got_priv_size) <= 0) {
|
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ if (privkey_size != got_priv_size || pubkey_size != got_pub_size) {
|
||||
ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
- if (privkey_size != crypto_kem_mlkem768_SECRETKEYBYTES
|
||||
- || pubkey_size != crypto_kem_mlkem768_PUBLICKEYBYTES) {
|
||||
+ if (EVP_PKEY_get_raw_public_key(pkey, pubkeybuf, &got_pub_size) <= 0
|
||||
+ || EVP_PKEY_get_raw_private_key(pkey, privkeybuf, &got_priv_size) <= 0) {
|
||||
ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto err;
|
||||
}
|
||||
+
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
@@ -94,16 +101,40 @@ mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf)
|
||||
}
|
||||
|
||||
static int
|
||||
-mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out)
|
||||
+mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf)
|
||||
+{
|
||||
+ return mlkem_keypair_gen("mlkem768", pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES,
|
||||
+ privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mlkem1024_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf)
|
||||
+{
|
||||
+ return mlkem_keypair_gen("mlkem1024", pubkeybuf, crypto_kem_mlkem1024_PUBLICKEYBYTES,
|
||||
+ privkeybuf, crypto_kem_mlkem1024_SECRETKEYBYTES);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mlkem_encap_secret(const char *mlkem_alg, const u_char *pubkeybuf, u_char *secret, u_char *out)
|
||||
{
|
||||
EVP_PKEY *pkey = NULL;
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
int r = SSH_ERR_INTERNAL_ERROR;
|
||||
- size_t outlen = crypto_kem_mlkem768_CIPHERTEXTBYTES,
|
||||
- secretlen = crypto_kem_mlkem768_BYTES;
|
||||
+ size_t outlen, expected_outlen, publen, secretlen = crypto_kem_mlkem768_BYTES;
|
||||
+
|
||||
+ if (strcmp(mlkem_alg, "mlkem768") == 0) {
|
||||
+ outlen = crypto_kem_mlkem768_CIPHERTEXTBYTES;
|
||||
+ publen = crypto_kem_mlkem768_PUBLICKEYBYTES;
|
||||
+ } else if (strcmp(mlkem_alg, "mlkem1024") == 0) {
|
||||
+ outlen = crypto_kem_mlkem1024_CIPHERTEXTBYTES;
|
||||
+ publen = crypto_kem_mlkem1024_PUBLICKEYBYTES;
|
||||
+ } else
|
||||
+ return r;
|
||||
|
||||
- pkey = EVP_PKEY_new_raw_public_key_ex(NULL, "mlkem768", NULL,
|
||||
- pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES);
|
||||
+ expected_outlen = outlen;
|
||||
+
|
||||
+ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, mlkem_alg, NULL,
|
||||
+ pubkeybuf, publen);
|
||||
if (pkey == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto err;
|
||||
@@ -112,9 +143,9 @@ mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out)
|
||||
ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL);
|
||||
if (ctx == NULL
|
||||
|| EVP_PKEY_encapsulate_init(ctx, NULL) <= 0
|
||||
- || EVP_PKEY_encapsulate(ctx, out, &outlen, secret, &secretlen) <= 0
|
||||
+ || EVP_PKEY_encapsulate(ctx, out, &expected_outlen, secret, &secretlen) <= 0
|
||||
|| secretlen != crypto_kem_mlkem768_BYTES
|
||||
- || outlen != crypto_kem_mlkem768_CIPHERTEXTBYTES) {
|
||||
+ || outlen != expected_outlen) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto err;
|
||||
}
|
||||
@@ -130,16 +161,30 @@ mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out)
|
||||
}
|
||||
|
||||
static int
|
||||
-mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret)
|
||||
+mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out)
|
||||
+{
|
||||
+ return mlkem_encap_secret("mlkem768", pubkeybuf, secret, out);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mlkem1024_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out)
|
||||
+{
|
||||
+ return mlkem_encap_secret("mlkem1024", pubkeybuf, secret, out);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mlkem_decap_secret(const char *algname,
|
||||
+ const u_char *privkeybuf, size_t privkey_len,
|
||||
+ const u_char *wrapped, size_t wrapped_len,
|
||||
+ u_char *secret)
|
||||
{
|
||||
EVP_PKEY *pkey = NULL;
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
int r = SSH_ERR_INTERNAL_ERROR;
|
||||
- size_t wrappedlen = crypto_kem_mlkem768_CIPHERTEXTBYTES,
|
||||
- secretlen = crypto_kem_mlkem768_BYTES;
|
||||
+ size_t secretlen = crypto_kem_mlkem768_BYTES;
|
||||
|
||||
- pkey = EVP_PKEY_new_raw_private_key_ex(NULL, "mlkem768", NULL,
|
||||
- privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES);
|
||||
+ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, algname,
|
||||
+ NULL, privkeybuf, privkey_len);
|
||||
if (pkey == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto err;
|
||||
@@ -148,7 +193,7 @@ mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *s
|
||||
ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL);
|
||||
if (ctx == NULL
|
||||
|| EVP_PKEY_decapsulate_init(ctx, NULL) <= 0
|
||||
- || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrappedlen) <= 0
|
||||
+ || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrapped_len) <= 0
|
||||
|| secretlen != crypto_kem_mlkem768_BYTES) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto err;
|
||||
@@ -165,6 +210,20 @@ mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *s
|
||||
return r;
|
||||
}
|
||||
|
||||
+static int
|
||||
+mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret)
|
||||
+{
|
||||
+ return mlkem_decap_secret("mlkem768", privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES,
|
||||
+ wrapped, crypto_kem_mlkem768_CIPHERTEXTBYTES, secret);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mlkem1024_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret)
|
||||
+{
|
||||
+ return mlkem_decap_secret("mlkem1024", privkeybuf, crypto_kem_mlkem1024_SECRETKEYBYTES,
|
||||
+ wrapped, crypto_kem_mlkem1024_CIPHERTEXTBYTES, secret);
|
||||
+}
|
||||
+
|
||||
int
|
||||
kex_kem_mlkem768x25519_keypair(struct kex *kex)
|
||||
{
|
||||
@@ -341,7 +400,7 @@ kex_kem_mlkem768x25519_enc(struct kex *kex,
|
||||
u_char hash[SSH_DIGEST_MAX_LENGTH];
|
||||
size_t need;
|
||||
int r = SSH_ERR_INTERNAL_ERROR;
|
||||
- struct libcrux_mlkem768_enc_result enc; /* FIXME */
|
||||
+ struct libcrux_mlkem768_enc_result enc;
|
||||
|
||||
*server_blobp = NULL;
|
||||
*shared_secretp = NULL;
|
||||
@@ -550,6 +609,468 @@ kex_kem_mlkem768x25519_dec(struct kex *kex,
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
+
|
||||
+#define NIST_P256_COMPRESSED_LEN 33
|
||||
+#define NIST_P256_UNCOMPRESSED_LEN 65
|
||||
+#define NIST_P384_COMPRESSED_LEN 49
|
||||
+#define NIST_P384_UNCOMPRESSED_LEN 97
|
||||
+#define NIST_BUF_MAX_SIZE NIST_P384_UNCOMPRESSED_LEN
|
||||
+
|
||||
+static const char ec256[] = "P-256";
|
||||
+static const char ec384[] = "P-384";
|
||||
+static const char *len2curve_name(size_t len)
|
||||
+{
|
||||
+ switch (len) {
|
||||
+ case NIST_P256_COMPRESSED_LEN:
|
||||
+ case NIST_P256_UNCOMPRESSED_LEN:
|
||||
+ return ec256;
|
||||
+ break;
|
||||
+ case NIST_P384_COMPRESSED_LEN:
|
||||
+ case NIST_P384_UNCOMPRESSED_LEN:
|
||||
+ return ec384;
|
||||
+ break;
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static EVP_PKEY *
|
||||
+buf2nist_key(const unsigned char *pub_key_buf, size_t pub_key_len)
|
||||
+{
|
||||
+ EVP_PKEY *pkey = NULL;
|
||||
+ EVP_PKEY_CTX *ctx = NULL;
|
||||
+ OSSL_PARAM params[3];
|
||||
+ const char *curve_name = len2curve_name(pub_key_len);
|
||||
+
|
||||
+ if (curve_name == NULL)
|
||||
+ return NULL;
|
||||
+
|
||||
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
|
||||
+ if (!ctx)
|
||||
+ goto err;
|
||||
+
|
||||
+ if (EVP_PKEY_fromdata_init(ctx) <= 0)
|
||||
+ goto err;
|
||||
+
|
||||
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, curve_name, 0);
|
||||
+ params[1] = OSSL_PARAM_construct_octet_string(
|
||||
+ OSSL_PKEY_PARAM_PUB_KEY, (void *)pub_key_buf, pub_key_len);
|
||||
+ params[2] = OSSL_PARAM_construct_end();
|
||||
+
|
||||
+ if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
|
||||
+ goto err;
|
||||
+
|
||||
+ EVP_PKEY_CTX_free(ctx);
|
||||
+ return pkey;
|
||||
+
|
||||
+err:
|
||||
+ EVP_PKEY_CTX_free(ctx);
|
||||
+ EVP_PKEY_free(pkey);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+kex_nist_shared_key_ext(EVP_PKEY *priv_key,
|
||||
+ const u_char *pub_key_buf, size_t pub_key_len, struct sshbuf *out)
|
||||
+{
|
||||
+ EVP_PKEY_CTX *ctx = NULL;
|
||||
+ unsigned char *shared_secret = NULL;
|
||||
+ size_t shared_secret_len = 0;
|
||||
+ EVP_PKEY *peer_key = buf2nist_key(pub_key_buf, pub_key_len);
|
||||
+ int r = SSH_ERR_INTERNAL_ERROR;
|
||||
+
|
||||
+ if (peer_key == NULL)
|
||||
+ return SSH_ERR_KEY_LENGTH;
|
||||
+
|
||||
+ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, priv_key, NULL);
|
||||
+ if (!ctx)
|
||||
+ goto end;
|
||||
+
|
||||
+ if ((EVP_PKEY_derive_init(ctx) <= 0)
|
||||
+ || EVP_PKEY_derive_set_peer(ctx, peer_key) <= 0
|
||||
+ || EVP_PKEY_derive(ctx, NULL, &shared_secret_len) <= 0)
|
||||
+ goto end;
|
||||
+
|
||||
+ shared_secret = OPENSSL_malloc(shared_secret_len);
|
||||
+ if (shared_secret == NULL)
|
||||
+ goto end;
|
||||
+
|
||||
+ if (EVP_PKEY_derive(ctx, shared_secret, &shared_secret_len) <= 0)
|
||||
+ goto end;
|
||||
+
|
||||
+ if ((r = sshbuf_put(out, shared_secret, shared_secret_len)) != 0)
|
||||
+ goto end;
|
||||
+
|
||||
+ r = 0;
|
||||
+
|
||||
+end:
|
||||
+ EVP_PKEY_free(peer_key);
|
||||
+ if (shared_secret)
|
||||
+ OPENSSL_clear_free(shared_secret, shared_secret_len);
|
||||
+ EVP_PKEY_CTX_free(ctx);
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+static EVP_PKEY *
|
||||
+nist_pkey_keygen(size_t pub_key_len)
|
||||
+{
|
||||
+ const char *curve_name = len2curve_name(pub_key_len);
|
||||
+ EVP_PKEY_CTX *pctx = NULL;
|
||||
+ EVP_PKEY *pkey = NULL;
|
||||
+ OSSL_PARAM params[2];
|
||||
+
|
||||
+ if (curve_name == NULL)
|
||||
+ return NULL;
|
||||
+
|
||||
+ pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
|
||||
+ if (!pctx)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (EVP_PKEY_keygen_init(pctx) <= 0) {
|
||||
+ EVP_PKEY_CTX_free(pctx);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, curve_name, 0);
|
||||
+ params[1] = OSSL_PARAM_construct_end();
|
||||
+
|
||||
+ if (EVP_PKEY_CTX_set_params(pctx, params) <= 0
|
||||
+ || EVP_PKEY_keygen(pctx, &pkey) <= 0) {
|
||||
+ EVP_PKEY_CTX_free(pctx);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ EVP_PKEY_CTX_free(pctx);
|
||||
+ return pkey;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+get_uncompressed_ec_pubkey(EVP_PKEY *pkey, unsigned char *buf, size_t buf_len)
|
||||
+{
|
||||
+ OSSL_PARAM params[2];
|
||||
+ size_t required_len = 0, out_len = 0;
|
||||
+
|
||||
+ params[0] = OSSL_PARAM_construct_utf8_string(
|
||||
+ OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
|
||||
+ "uncompressed", 0);
|
||||
+ params[1] = OSSL_PARAM_construct_end();
|
||||
+
|
||||
+ if (EVP_PKEY_set_params(pkey, params) <= 0
|
||||
+ || EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
|
||||
+ NULL, 0, &required_len) <= 0) {
|
||||
+ return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ if (required_len != buf_len)
|
||||
+ return SSH_ERR_INTERNAL_ERROR;
|
||||
+
|
||||
+ if (EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
|
||||
+ buf, required_len, &out_len) <= 0) {
|
||||
+ return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+/* nist_bytes_len should always be uncompressed */
|
||||
+static int
|
||||
+kex_kem_mlkem_nist_keypair(struct kex *kex, size_t mlkem_bytes_len, size_t nist_bytes_len)
|
||||
+{
|
||||
+ struct sshbuf *buf = NULL;
|
||||
+ u_char *cp = NULL;
|
||||
+ size_t need;
|
||||
+ int r = SSH_ERR_INTERNAL_ERROR;
|
||||
+ u_char *client_key = NULL;
|
||||
+
|
||||
+ if ((buf = sshbuf_new()) == NULL)
|
||||
+ return SSH_ERR_ALLOC_FAIL;
|
||||
+ need = mlkem_bytes_len + nist_bytes_len;
|
||||
+ if ((r = sshbuf_reserve(buf, need, &cp)) != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (mlkem_bytes_len == crypto_kem_mlkem768_PUBLICKEYBYTES) {
|
||||
+ client_key = kex->mlkem768_client_key;
|
||||
+ r = mlkem768_keypair_gen(cp, client_key);
|
||||
+ }
|
||||
+
|
||||
+ if (mlkem_bytes_len == crypto_kem_mlkem1024_PUBLICKEYBYTES) {
|
||||
+ client_key = kex->mlkem1024_client_key;
|
||||
+ r = mlkem1024_keypair_gen(cp, client_key);
|
||||
+ }
|
||||
+
|
||||
+ if (client_key == NULL)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (r != 0)
|
||||
+ goto out;
|
||||
+#ifdef DEBUG_KEXECDH
|
||||
+ dump_digest("client public key mlkemXXX:", cp, mlkem_bytes_len);
|
||||
+#endif
|
||||
+ cp += mlkem_bytes_len;
|
||||
+ if ((kex->ec_hybrid_client_key = nist_pkey_keygen(nist_bytes_len)) == NULL)
|
||||
+ goto out;
|
||||
+
|
||||
+ if ((r = get_uncompressed_ec_pubkey(kex->ec_hybrid_client_key, cp, nist_bytes_len)) != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+#ifdef DEBUG_KEXECDH
|
||||
+ dump_digest("client public key NIST:", cp, nist_bytes_len);
|
||||
+#endif
|
||||
+ /* success */
|
||||
+ r = 0;
|
||||
+ kex->client_pub = buf;
|
||||
+ buf = NULL;
|
||||
+ out:
|
||||
+ sshbuf_free(buf);
|
||||
+ if (r == SSH_ERR_LIBCRYPTO_ERROR)
|
||||
+ ERR_print_errors_fp(stderr);
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+kex_kem_mlkem_nist_enc(struct kex *kex, const char *nist_curve,
|
||||
+ const struct sshbuf *client_blob, struct sshbuf **server_blobp,
|
||||
+ struct sshbuf **shared_secretp)
|
||||
+{
|
||||
+ struct sshbuf *server_blob = NULL;
|
||||
+ struct sshbuf *buf = NULL;
|
||||
+ const u_char *client_pub;
|
||||
+ u_char server_pub[NIST_BUF_MAX_SIZE];
|
||||
+ u_char enc_out[crypto_kem_mlkem1024_CIPHERTEXTBYTES];
|
||||
+ u_char secret[crypto_kem_mlkem768_BYTES];
|
||||
+ EVP_PKEY *server_key = NULL;
|
||||
+ u_char hash[SSH_DIGEST_MAX_LENGTH];
|
||||
+ size_t client_buf_len, mlkem_buf_len, ecdh_buf_len, server_key_len, enc_out_len;
|
||||
+ int r = SSH_ERR_INTERNAL_ERROR;
|
||||
+
|
||||
+ *server_blobp = NULL;
|
||||
+ *shared_secretp = NULL;
|
||||
+
|
||||
+ client_buf_len = sshbuf_len(client_blob);
|
||||
+ /* client_blob contains both KEM and ECDH client pubkeys */
|
||||
+ if (strcmp(nist_curve, "P-256") == 0) {
|
||||
+ if (crypto_kem_mlkem768_PUBLICKEYBYTES > client_buf_len)
|
||||
+ return r;
|
||||
+
|
||||
+ ecdh_buf_len = client_buf_len - crypto_kem_mlkem768_PUBLICKEYBYTES;
|
||||
+ if (ecdh_buf_len != NIST_P256_COMPRESSED_LEN &&
|
||||
+ ecdh_buf_len != NIST_P256_UNCOMPRESSED_LEN)
|
||||
+ return r;
|
||||
+ mlkem_buf_len = crypto_kem_mlkem768_PUBLICKEYBYTES;
|
||||
+ enc_out_len = crypto_kem_mlkem768_CIPHERTEXTBYTES;
|
||||
+ server_key_len = NIST_P256_UNCOMPRESSED_LEN;
|
||||
+ } else if (strcmp(nist_curve, "P-384") == 0) {
|
||||
+ if (crypto_kem_mlkem1024_PUBLICKEYBYTES > client_buf_len)
|
||||
+ return r;
|
||||
+
|
||||
+ ecdh_buf_len = client_buf_len - crypto_kem_mlkem1024_PUBLICKEYBYTES;
|
||||
+ if (ecdh_buf_len != NIST_P384_COMPRESSED_LEN &&
|
||||
+ ecdh_buf_len != NIST_P384_UNCOMPRESSED_LEN)
|
||||
+ return r;
|
||||
+ mlkem_buf_len = crypto_kem_mlkem1024_PUBLICKEYBYTES;
|
||||
+ enc_out_len = crypto_kem_mlkem1024_CIPHERTEXTBYTES;
|
||||
+ server_key_len = NIST_P384_UNCOMPRESSED_LEN;
|
||||
+ } else
|
||||
+ return r;
|
||||
+
|
||||
+ client_pub = sshbuf_ptr(client_blob);
|
||||
+#ifdef DEBUG_KEXECDH
|
||||
+ dump_digest("client public key mlkem:", client_pub, mlkem_buf_len);
|
||||
+ dump_digest("client public key NIST:", client_pub + mlkem_buf_len, ecdh_buf_len);
|
||||
+#endif
|
||||
+
|
||||
+ /* allocate buffer for concatenation of KEM key and ECDH shared key */
|
||||
+ /* the buffer will be hashed and the result is the shared secret */
|
||||
+ if ((buf = sshbuf_new()) == NULL) {
|
||||
+ r = SSH_ERR_ALLOC_FAIL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ /* allocate space for encrypted KEM key and ECDH pub key */
|
||||
+ if ((server_blob = sshbuf_new()) == NULL) {
|
||||
+ r = SSH_ERR_ALLOC_FAIL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ r = (mlkem_buf_len == crypto_kem_mlkem768_PUBLICKEYBYTES) ?
|
||||
+ mlkem768_encap_secret(client_pub, secret, enc_out) :
|
||||
+ mlkem1024_encap_secret(client_pub, secret, enc_out);
|
||||
+
|
||||
+ if (r != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ /* generate ECDH key pair, store server pubkey after ciphertext */
|
||||
+ server_key = nist_pkey_keygen(server_key_len);
|
||||
+
|
||||
+ if ((r = get_uncompressed_ec_pubkey(server_key, server_pub, server_key_len) != 0) ||
|
||||
+ (r = sshbuf_put(buf, secret, sizeof(secret))) != 0 ||
|
||||
+ (r = sshbuf_put(server_blob, enc_out, enc_out_len) != 0)||
|
||||
+ (r = sshbuf_put(server_blob, server_pub, server_key_len)) != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ /* append ECDH shared key */
|
||||
+ client_pub += mlkem_buf_len;
|
||||
+ if ((r = kex_nist_shared_key_ext(server_key, client_pub, ecdh_buf_len, buf)) < 0)
|
||||
+ goto out;
|
||||
+ if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
|
||||
+ goto out;
|
||||
+#ifdef DEBUG_KEXECDH
|
||||
+ dump_digest("server public NIST:", server_pub, server_key_len);
|
||||
+ dump_digest("server cipher text:", enc_out, enc_out_len);
|
||||
+ dump_digest("server kem key:", secret, sizeof(secret));
|
||||
+ dump_digest("concatenation of KEM key and ECDH shared key:",
|
||||
+ sshbuf_ptr(buf), sshbuf_len(buf));
|
||||
+#endif
|
||||
+ /* string-encoded hash is resulting shared secret */
|
||||
+ sshbuf_reset(buf);
|
||||
+ if ((r = sshbuf_put_string(buf, hash,
|
||||
+ ssh_digest_bytes(kex->hash_alg))) != 0)
|
||||
+ goto out;
|
||||
+#ifdef DEBUG_KEXECDH
|
||||
+ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
|
||||
+#endif
|
||||
+ /* success */
|
||||
+ r = 0;
|
||||
+ *server_blobp = server_blob;
|
||||
+ *shared_secretp = buf;
|
||||
+ server_blob = NULL;
|
||||
+ buf = NULL;
|
||||
+ out:
|
||||
+ explicit_bzero(hash, sizeof(hash));
|
||||
+ EVP_PKEY_free(server_key);
|
||||
+ explicit_bzero(enc_out, sizeof(enc_out));
|
||||
+ explicit_bzero(secret, sizeof(secret));
|
||||
+ sshbuf_free(server_blob);
|
||||
+ sshbuf_free(buf);
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+kex_kem_mlkem_nist_dec(struct kex *kex,
|
||||
+ const struct sshbuf *server_blob, struct sshbuf **shared_secretp,
|
||||
+ size_t mlkem_len)
|
||||
+{
|
||||
+ struct sshbuf *buf = NULL;
|
||||
+ const u_char *ciphertext, *server_pub;
|
||||
+ u_char hash[SSH_DIGEST_MAX_LENGTH];
|
||||
+ u_char decap[crypto_kem_mlkem768_BYTES];
|
||||
+ int r;
|
||||
+ size_t nist_len;
|
||||
+
|
||||
+ *shared_secretp = NULL;
|
||||
+
|
||||
+ if (sshbuf_len(server_blob) < mlkem_len) {
|
||||
+ r = SSH_ERR_SIGNATURE_INVALID;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ nist_len = sshbuf_len(server_blob) - mlkem_len;
|
||||
+
|
||||
+ switch (mlkem_len) {
|
||||
+ case crypto_kem_mlkem768_CIPHERTEXTBYTES:
|
||||
+ if (nist_len != NIST_P256_COMPRESSED_LEN
|
||||
+ && nist_len != NIST_P256_UNCOMPRESSED_LEN) {
|
||||
+ r = SSH_ERR_SIGNATURE_INVALID;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ break;
|
||||
+ case crypto_kem_mlkem1024_CIPHERTEXTBYTES:
|
||||
+ if (nist_len != NIST_P384_COMPRESSED_LEN
|
||||
+ && nist_len != NIST_P384_UNCOMPRESSED_LEN) {
|
||||
+ r = SSH_ERR_SIGNATURE_INVALID;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ ciphertext = sshbuf_ptr(server_blob);
|
||||
+ server_pub = ciphertext + mlkem_len;
|
||||
+ /* hash concatenation of KEM key and ECDH shared key */
|
||||
+ if ((buf = sshbuf_new()) == NULL) {
|
||||
+ r = SSH_ERR_ALLOC_FAIL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+#ifdef DEBUG_KEXECDH
|
||||
+ dump_digest("server cipher text:", ciphertext, mlkem_len);
|
||||
+ dump_digest("server public key NIST:", server_pub, nist_len);
|
||||
+#endif
|
||||
+ r = (mlkem_len == crypto_kem_mlkem768_CIPHERTEXTBYTES) ?
|
||||
+ mlkem768_decap_secret(kex->mlkem768_client_key, ciphertext, decap) :
|
||||
+ mlkem1024_decap_secret(kex->mlkem1024_client_key, ciphertext, decap);
|
||||
+
|
||||
+ if (r != 0)
|
||||
+ goto out;
|
||||
+ if ((r = sshbuf_put(buf, decap, sizeof(decap))) != 0)
|
||||
+ goto out;
|
||||
+ if ((r = kex_nist_shared_key_ext(kex->ec_hybrid_client_key, server_pub,
|
||||
+ nist_len, buf)) < 0)
|
||||
+ goto out;
|
||||
+ if ((r = ssh_digest_buffer(kex->hash_alg, buf,
|
||||
+ hash, sizeof(hash))) != 0)
|
||||
+ goto out;
|
||||
+#ifdef DEBUG_KEXECDH
|
||||
+ dump_digest("client kem key:", decap, sizeof(decap));
|
||||
+ dump_digest("concatenation of KEM key and ECDH shared key:",
|
||||
+ sshbuf_ptr(buf), sshbuf_len(buf));
|
||||
+#endif
|
||||
+ sshbuf_reset(buf);
|
||||
+ if ((r = sshbuf_put_string(buf, hash,
|
||||
+ ssh_digest_bytes(kex->hash_alg))) != 0)
|
||||
+ goto out;
|
||||
+#ifdef DEBUG_KEXECDH
|
||||
+ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
|
||||
+#endif
|
||||
+ /* success */
|
||||
+ r = 0;
|
||||
+ *shared_secretp = buf;
|
||||
+ buf = NULL;
|
||||
+ out:
|
||||
+ explicit_bzero(hash, sizeof(hash));
|
||||
+ explicit_bzero(decap, sizeof(decap));
|
||||
+ sshbuf_free(buf);
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+kex_kem_mlkem768nistp256_keypair(struct kex *kex)
|
||||
+{
|
||||
+ return kex_kem_mlkem_nist_keypair(kex, crypto_kem_mlkem768_PUBLICKEYBYTES, NIST_P256_UNCOMPRESSED_LEN);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+kex_kem_mlkem768nistp256_enc(struct kex *kex, const struct sshbuf *client_blob,
|
||||
+ struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
|
||||
+{
|
||||
+ return kex_kem_mlkem_nist_enc(kex, "P-256", client_blob, server_blobp, shared_secretp);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+kex_kem_mlkem768nistp256_dec(struct kex *kex, const struct sshbuf *server_blob,
|
||||
+ struct sshbuf **shared_secretp)
|
||||
+{
|
||||
+ return kex_kem_mlkem_nist_dec(kex, server_blob, shared_secretp,
|
||||
+ crypto_kem_mlkem768_CIPHERTEXTBYTES);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+kex_kem_mlkem1024nistp384_keypair(struct kex *kex)
|
||||
+{
|
||||
+ return kex_kem_mlkem_nist_keypair(kex, crypto_kem_mlkem1024_PUBLICKEYBYTES, NIST_P384_UNCOMPRESSED_LEN);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+kex_kem_mlkem1024nistp384_enc(struct kex *kex, const struct sshbuf *client_blob,
|
||||
+ struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
|
||||
+{
|
||||
+ return kex_kem_mlkem_nist_enc(kex, "P-384", client_blob, server_blobp, shared_secretp);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+kex_kem_mlkem1024nistp384_dec(struct kex *kex, const struct sshbuf *server_blob,
|
||||
+ struct sshbuf **shared_secretp)
|
||||
+{
|
||||
+ return kex_kem_mlkem_nist_dec(kex, server_blob, shared_secretp,
|
||||
+ crypto_kem_mlkem1024_CIPHERTEXTBYTES);
|
||||
+}
|
||||
+
|
||||
#else /* USE_MLKEM768X25519 */
|
||||
int
|
||||
kex_kem_mlkem768x25519_keypair(struct kex *kex)
|
||||
@@ -571,4 +1092,39 @@ kex_kem_mlkem768x25519_dec(struct kex *kex,
|
||||
{
|
||||
return SSH_ERR_SIGN_ALG_UNSUPPORTED;
|
||||
}
|
||||
+
|
||||
+int kex_kem_mlkem768nistp256_keypair(struct kex *)
|
||||
+{
|
||||
+ return SSH_ERR_SIGN_ALG_UNSUPPORTED;
|
||||
+}
|
||||
+
|
||||
+int kex_kem_mlkem768nistp256_enc(struct kex *, const struct sshbuf *,
|
||||
+ struct sshbuf **, struct sshbuf **)
|
||||
+{
|
||||
+ return SSH_ERR_SIGN_ALG_UNSUPPORTED;
|
||||
+}
|
||||
+
|
||||
+int kex_kem_mlkem768nistp256_dec(struct kex *, const struct sshbuf *,
|
||||
+ struct sshbuf **)
|
||||
+{
|
||||
+ return SSH_ERR_SIGN_ALG_UNSUPPORTED;
|
||||
+}
|
||||
+
|
||||
+int kex_kem_mlkem1024nistp384_keypair(struct kex *)
|
||||
+{
|
||||
+ return SSH_ERR_SIGN_ALG_UNSUPPORTED;
|
||||
+}
|
||||
+
|
||||
+int kex_kem_mlkem1024nistp384_enc(struct kex *, const struct sshbuf *,
|
||||
+ struct sshbuf **, struct sshbuf **)
|
||||
+{
|
||||
+ return SSH_ERR_SIGN_ALG_UNSUPPORTED;
|
||||
+}
|
||||
+
|
||||
+int kex_kem_mlkem1024nistp384_dec(struct kex *, const struct sshbuf *,
|
||||
+ struct sshbuf **)
|
||||
+{
|
||||
+ return SSH_ERR_SIGN_ALG_UNSUPPORTED;
|
||||
+}
|
||||
+
|
||||
#endif /* USE_MLKEM768X25519 */
|
||||
diff --git a/monitor.c b/monitor.c
|
||||
index 58fbac9df..75413ce71 100644
|
||||
--- a/monitor.c
|
||||
+++ b/monitor.c
|
||||
@@ -2009,6 +2009,8 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor)
|
||||
kex->kex[KEX_C25519_SHA256] = kex_gen_server;
|
||||
kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
|
||||
kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server;
|
||||
+ kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server;
|
||||
+ kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server;
|
||||
kex->load_host_public_key=&get_hostkey_public_by_type;
|
||||
kex->load_host_private_key=&get_hostkey_private_by_type;
|
||||
kex->host_key_index=&get_hostkey_index;
|
||||
diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c
|
||||
index 09016aead..2baf9a7a0 100644
|
||||
--- a/regress/unittests/kex/test_kex.c
|
||||
+++ b/regress/unittests/kex/test_kex.c
|
||||
@@ -155,6 +155,8 @@ do_kex_with_key(char *kex, int keytype, int bits)
|
||||
server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
|
||||
server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
|
||||
server2->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server;
|
||||
+ server2->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server;
|
||||
+ server2->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server;
|
||||
server2->kex->load_host_public_key = server->kex->load_host_public_key;
|
||||
server2->kex->load_host_private_key = server->kex->load_host_private_key;
|
||||
server2->kex->sign = server->kex->sign;
|
||||
@@ -211,6 +213,8 @@ kex_tests(void)
|
||||
do_kex("diffie-hellman-group1-sha1");
|
||||
# ifdef USE_MLKEM768X25519
|
||||
do_kex("mlkem768x25519-sha256");
|
||||
+ do_kex("mlkem768nistp256-sha256");
|
||||
+ do_kex("mlkem1024nistp384-sha384");
|
||||
# endif /* USE_MLKEM768X25519 */
|
||||
# ifdef USE_SNTRUP761X25519
|
||||
do_kex("sntrup761x25519-sha512@openssh.com");
|
||||
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
|
||||
index 9f76ad225..8660088b7 100644
|
||||
--- a/ssh-keyscan.c
|
||||
+++ b/ssh-keyscan.c
|
||||
@@ -304,6 +304,8 @@ keygrab_ssh2(con *c)
|
||||
c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
|
||||
c->c_ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
|
||||
c->c_ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client;
|
||||
+ c->c_ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client;
|
||||
+ c->c_ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client;
|
||||
ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper);
|
||||
/*
|
||||
* do the key-exchange until an error occurs or until
|
||||
diff --git a/ssh_api.c b/ssh_api.c
|
||||
index 7bdcee148..d20b03a00 100644
|
||||
--- a/ssh_api.c
|
||||
+++ b/ssh_api.c
|
||||
@@ -135,6 +135,8 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params)
|
||||
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
|
||||
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
|
||||
ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server;
|
||||
+ ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server;
|
||||
+ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server;
|
||||
ssh->kex->load_host_public_key=&_ssh_host_public_key;
|
||||
ssh->kex->load_host_private_key=&_ssh_host_private_key;
|
||||
ssh->kex->sign=&_ssh_host_key_sign;
|
||||
@@ -154,6 +156,8 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params)
|
||||
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
|
||||
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
|
||||
ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client;
|
||||
+ ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client;
|
||||
+ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client;
|
||||
ssh->kex->verify_host_key =&_ssh_verify_host_key;
|
||||
}
|
||||
*sshp = ssh;
|
||||
diff --git a/sshconnect2.c b/sshconnect2.c
|
||||
index 5beae1c10..6d9f1238b 100644
|
||||
--- a/sshconnect2.c
|
||||
+++ b/sshconnect2.c
|
||||
@@ -347,6 +347,8 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
|
||||
ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
|
||||
ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
|
||||
ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client;
|
||||
+ ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client;
|
||||
+ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client;
|
||||
ssh->kex->verify_host_key=&verify_host_key_callback;
|
||||
|
||||
#if defined(GSSAPI) && defined(WITH_OPENSSL)
|
||||
diff -up openssh-9.9p1-build/openssh-9.9p1/sshd-session.c.xxx openssh-9.9p1-build/openssh-9.9p1/sshd-session.c
|
||||
--- a/sshd-session.c.xxx 2025-11-03 12:07:44.196167561 +0100
|
||||
+++ b/sshd-session.c 2025-11-03 12:08:26.809214111 +0100
|
||||
@@ -1659,6 +1659,8 @@ do_ssh2_kex(struct ssh *ssh)
|
||||
kex->kex[KEX_C25519_SHA256] = kex_gen_server;
|
||||
kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
|
||||
kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server;
|
||||
+ kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server;
|
||||
+ kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server;
|
||||
kex->load_host_public_key=&get_hostkey_public_by_type;
|
||||
kex->load_host_private_key=&get_hostkey_private_by_type;
|
||||
kex->host_key_index=&get_hostkey_index;
|
||||
10
openssh.spec
10
openssh.spec
@ -43,7 +43,7 @@
|
||||
Summary: An open source implementation of SSH protocol version 2
|
||||
Name: openssh
|
||||
Version: %{openssh_ver}
|
||||
Release: 15%{?dist}.alma.1
|
||||
Release: 16%{?dist}.alma.1
|
||||
URL: http://www.openssh.com/portable.html
|
||||
Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
|
||||
Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc
|
||||
@ -220,6 +220,7 @@ Patch1028: openssh-9.9p1-fips-gss.patch
|
||||
#upstream 4f14ca8633a2c8c0a1a19165663421f0ab32f6ab
|
||||
Patch1029: openssh-9.9p1-scp-traversing.patch
|
||||
Patch1030: openssh-9.9p1-canonical-match-user.patch
|
||||
Patch1031: openssh-10.0-mlkem-nist.patch
|
||||
|
||||
License: BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND sprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant
|
||||
Requires: /sbin/nologin
|
||||
@ -415,6 +416,7 @@ gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0}
|
||||
%patch -P 1028 -p1 -b .gss-fips
|
||||
%patch -P 1029 -p1 -b .scp-traversing
|
||||
%patch -P 1030 -p1 -b .canonical-match-user
|
||||
%patch -P 1031 -p1 -b .mlkem-nist
|
||||
|
||||
%patch -P 100 -p1 -b .coverity
|
||||
|
||||
@ -695,9 +697,13 @@ test -f %{sysconfig_anaconda} && \
|
||||
%attr(0755,root,root) %{_libdir}/sshtest/sk-dummy.so
|
||||
|
||||
%changelog
|
||||
* Fri Oct 31 2025 Koichiro Iwao <meta@almalinux.org> - 9.9p1-15.alma.1
|
||||
* Tue Nov 04 2025 Koichiro Iwao <meta@almalinux.org> - 9.9p1-16.alma.1
|
||||
- Unpatch Red Hat help message
|
||||
|
||||
* Mon Nov 03 2025 Dmitry Belyavskiy <dbelyavs@redhat.com> - 9.9p1-16
|
||||
- Implement mlkem768nistp256-sha256 and mlkem1024nistp384-sha384 KEX methods
|
||||
Resolves: RHEL-70824
|
||||
|
||||
* Mon Oct 27 2025 Zoltan Fridrich <zfridric@redhat.com> - 9.9p1-15
|
||||
- Fix implicit destination path selection when source path ends with ".."
|
||||
Resolves: RHEL-118406
|
||||
|
||||
Loading…
Reference in New Issue
Block a user