support GOST (from ALT Linux)

This commit is contained in:
Mikhail Novosyolov 2020-02-20 11:07:57 +03:00
parent 3faae1666e
commit acc6d5b84f
2 changed files with 646 additions and 1 deletions

View file

@ -0,0 +1,636 @@
From ac75e02d00b0779ad3d48fc1b2bf8af978ae6890 Mon Sep 17 00:00:00 2001
From: Gleb Fotengauer-Malinovskiy <glebfm@altlinux.org>
Date: Fri, 10 Aug 2018 15:39:21 +0300
Subject: [PATCH] Add support of gost cipher and digests
[ mikhailnov@ROSA:
copied algo names xxx@altlinux.org to xxx,
e.g. "magma-ctr@altlinux.org" and "magma-ctr" are the same
]
---
Makefile.in | 2 +
cipher.c | 24 ++++++++++++-
digest-openssl.c | 35 ++++++++++++++++++
digest.h | 7 +++-
ext-mac.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
ext-mac.h | 38 ++++++++++++++++++++
gost-engine.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++
gost-engine.h | 24 ++++++++++++
mac.c | 49 +++++++++++++++++++++++++-
mac.h | 1 +
sshd.c | 1 +
11 files changed, 378 insertions(+), 3 deletions(-)
create mode 100644 ext-mac.c
create mode 100644 ext-mac.h
create mode 100644 gost-engine.c
create mode 100644 gost-engine.h
diff --git a/Makefile.in b/Makefile.in
index 126b2c7..8b6193b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -102,6 +102,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
platform-pledge.o platform-tracing.o platform-misc.o
+LIBSSH_OBJS += ext-mac.o gost-engine.o
+
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
sshconnect.o sshconnect2.o mux.o
diff --git a/cipher.c b/cipher.c
index 12c5988..6eabcc4 100644
--- a/cipher.c
+++ b/cipher.c
@@ -51,6 +51,8 @@
#include "openbsd-compat/openssl-compat.h"
+#include "gost-engine.h"
+
struct sshcipher_ctx {
int plaintext;
@@ -106,6 +108,22 @@ static const struct sshcipher ciphers[] = {
#endif
{ "chacha20-poly1305@openssh.com",
8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL },
+ { "grasshopper-cbc@altlinux.org",
+ 16, 32, 0, 0, CFLAG_CBC, EVP_grasshopper_cbc },
+ { "grasshopper-cbc",
+ 16, 32, 0, 0, CFLAG_CBC, EVP_grasshopper_cbc },
+ { "grasshopper-ctr@altlinux.org",
+ 16, 32, 0, 0, 0, EVP_grasshopper_ctr },
+ { "grasshopper-ctr",
+ 16, 32, 0, 0, 0, EVP_grasshopper_ctr },
+ { "magma-cbc@altlinux.org",
+ 8, 32, 0, 0, CFLAG_CBC, EVP_magma_cbc },
+ { "magma-cbc",
+ 8, 32, 0, 0, CFLAG_CBC, EVP_magma_cbc },
+ { "magma-ctr@altlinux.org",
+ 8, 32, 0, 0, 0, EVP_magma_ctr },
+ { "magma-ctr",
+ 8, 32, 0, 0, 0, EVP_magma_ctr },
{ "none", 8, 0, 0, 0, CFLAG_NONE, NULL },
{ NULL, 0, 0, 0, 0, 0, NULL }
@@ -113,6 +123,15 @@ static const struct sshcipher ciphers[] = {
/*--*/
+static int
+cipher_avaliable(const struct sshcipher * c)
+{
+ if (c->evptype && c->evptype() == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+ return 0;
+}
+
+
/* Returns a comma-separated list of supported ciphers. */
char *
cipher_alg_list(char sep, int auth_only)
@@ -122,6 +141,8 @@ cipher_alg_list(char sep, int auth_only)
const struct sshcipher *c;
for (c = ciphers; c->name != NULL; c++) {
+ if (cipher_avaliable(c) < 0)
+ continue;
if ((c->flags & CFLAG_INTERNAL) != 0)
continue;
if (auth_only && c->auth_len == 0)
@@ -214,7 +235,8 @@ ciphers_valid(const char *names)
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
(p = strsep(&cp, CIPHER_SEP))) {
c = cipher_by_name(p);
- if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0) {
+ if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0 ||
+ cipher_avaliable(c) < 0) {
free(cipher_list);
return 0;
}
diff --git a/digest-openssl.c b/digest-openssl.c
index da7ed72..536c34f 100644
--- a/digest-openssl.c
+++ b/digest-openssl.c
@@ -31,6 +31,7 @@
#include "sshbuf.h"
#include "digest.h"
#include "ssherr.h"
+#include "gost-engine.h"
#ifndef HAVE_EVP_RIPEMD160
# define EVP_ripemd160 NULL
@@ -60,6 +61,9 @@ const struct ssh_digest digests[] = {
{ SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 },
{ SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 },
{ SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 },
+ { SSH_DIGEST_STREEBOG_256, "STREEBOG_256", 32, EVP_streebog_256 },
+ { SSH_DIGEST_STREEBOG_512, "STREEBOG_512", 64, EVP_streebog_512 },
+ { SSH_DIGEST_GRASSHOPPER, "GRASSHOPPER-MAC", 16, EVP_grasshopper_omac },
{ -1, NULL, 0, NULL },
};
@@ -109,6 +113,16 @@ ssh_digest_blocksize(struct ssh_digest_ctx *ctx)
return EVP_MD_CTX_block_size(ctx->mdctx);
}
+int
+ssh_digest_avaliable(int alg) {
+ const struct ssh_digest *digest = ssh_digest_by_alg(alg);
+ if (digest == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if (digest->mdfunc() == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+ return 0;
+}
+
struct ssh_digest_ctx *
ssh_digest_start(int alg)
{
@@ -130,6 +144,27 @@ ssh_digest_start(int alg)
}
int
+ssh_digest_set_key(struct ssh_digest_ctx *ctx, const void *key, size_t klen)
+{
+ const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
+ const EVP_MD *md = digest->mdfunc();
+
+#ifndef EVP_MD_CTRL_SET_KEY
+#define EVP_MD_CTRL_SET_KEY (EVP_MD_CTRL_ALG_CTRL+4)
+#endif
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ if (md->md_ctrl &&
+ md->md_ctrl(&ctx->mdctx, EVP_MD_CTRL_SET_KEY, klen, (void *)key) != 1)
+#else
+ int (*md_ctrl)(EVP_MD_CTX *, int, int, void *) = EVP_MD_meth_get_ctrl(md);
+ if (md_ctrl &&
+ md_ctrl(ctx->mdctx, EVP_MD_CTRL_SET_KEY, klen, (void *)key) != 1)
+#endif
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ return 0;
+}
+
+int
ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
{
if (from->alg != to->alg)
diff --git a/digest.h b/digest.h
index 274574d..2fc3df2 100644
--- a/digest.h
+++ b/digest.h
@@ -27,7 +27,10 @@
#define SSH_DIGEST_SHA256 2
#define SSH_DIGEST_SHA384 3
#define SSH_DIGEST_SHA512 4
-#define SSH_DIGEST_MAX 5
+#define SSH_DIGEST_STREEBOG_256 5
+#define SSH_DIGEST_STREEBOG_512 6
+#define SSH_DIGEST_GRASSHOPPER 7
+#define SSH_DIGEST_MAX 8
struct sshbuf;
struct ssh_digest_ctx;
@@ -55,9 +58,11 @@ int ssh_digest_memory(int alg, const void *m, size_t mlen,
__attribute__((__bounded__(__buffer__, 4, 5)));
int ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
__attribute__((__bounded__(__buffer__, 3, 4)));
+int ssh_digest_avaliable(int alg);
/* Update API */
struct ssh_digest_ctx *ssh_digest_start(int alg);
+int ssh_digest_set_key(struct ssh_digest_ctx *ctx, const void *key, size_t klen);
int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
__attribute__((__bounded__(__buffer__, 2, 3)));
int ssh_digest_update_buffer(struct ssh_digest_ctx *ctx,
diff --git a/ext-mac.c b/ext-mac.c
new file mode 100644
index 0000000..b505394
--- /dev/null
+++ b/ext-mac.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014 Markus Friedl. All rights reserved.
+ * Copyright (c) 2018 Gleb Fotengauer-Malinovskiy. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "sshbuf.h"
+#include "digest.h"
+#include "ext-mac.h"
+
+struct ssh_ext_mac_ctx {
+ int alg;
+ struct ssh_digest_ctx *digest;
+ struct ssh_digest_ctx *octx;
+};
+
+size_t
+ssh_ext_mac_bytes(int alg)
+{
+ return ssh_digest_bytes(alg);
+}
+
+struct ssh_ext_mac_ctx *
+ssh_ext_mac_start(int alg)
+{
+ struct ssh_ext_mac_ctx *ret;
+
+ if ((ret = calloc(1, sizeof(*ret))) == NULL)
+ return NULL;
+ ret->alg = alg;
+ if ((ret->digest = ssh_digest_start(alg)) == NULL ||
+ (ret->octx = ssh_digest_start(alg)) == NULL)
+ goto fail;
+ return ret;
+fail:
+ ssh_ext_mac_free(ret);
+ return NULL;
+}
+
+int
+ssh_ext_mac_init(struct ssh_ext_mac_ctx *ctx, const void *key, size_t klen)
+{
+ if (key != NULL && ssh_digest_set_key(ctx->octx, key, klen) < 0)
+ return -1;
+
+ /* (re)start with octx */
+ if (ssh_digest_copy_state(ctx->octx, ctx->digest) < 0)
+ return -1;
+
+ return 0;
+}
+
+int
+ssh_ext_mac_update(struct ssh_ext_mac_ctx *ctx, const void *m, size_t mlen)
+{
+ return ssh_digest_update(ctx->digest, m, mlen);
+}
+
+int
+ssh_ext_mac_update_buffer(struct ssh_ext_mac_ctx *ctx, const struct sshbuf *b)
+{
+ return ssh_digest_update_buffer(ctx->digest, b);
+}
+
+int
+ssh_ext_mac_final(struct ssh_ext_mac_ctx *ctx, u_char *d, size_t dlen)
+{
+ size_t len;
+
+ len = ssh_digest_bytes(ctx->alg);
+ if (dlen < len ||
+ ssh_digest_final(ctx->digest, d, dlen))
+ return -1;
+
+ return 0;
+}
+
+void
+ssh_ext_mac_free(struct ssh_ext_mac_ctx *ctx)
+{
+ if (ctx != NULL) {
+ ssh_digest_free(ctx->digest);
+ ssh_digest_free(ctx->octx);
+ explicit_bzero(ctx, sizeof(*ctx));
+ free(ctx);
+ }
+}
diff --git a/ext-mac.h b/ext-mac.h
new file mode 100644
index 0000000..a55209c
--- /dev/null
+++ b/ext-mac.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Markus Friedl. All rights reserved.
+ * Copyright (c) 2018 Gleb Fotengauer-Malinovskiy. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _EXT_MAC_H
+#define _EXT_MAC_H
+
+/* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */
+size_t ssh_ext_mac_bytes(int alg);
+
+struct sshbuf;
+struct ssh_ext_mac_ctx;
+struct ssh_ext_mac_ctx *ssh_ext_mac_start(int alg);
+
+/* Sets the state of the EXT_MAC or resets the state if key == NULL */
+int ssh_ext_mac_init(struct ssh_ext_mac_ctx *ctx, const void *key, size_t klen)
+ __attribute__((__bounded__(__buffer__, 2, 3)));
+int ssh_ext_mac_update(struct ssh_ext_mac_ctx *ctx, const void *m, size_t mlen)
+ __attribute__((__bounded__(__buffer__, 2, 3)));
+int ssh_ext_mac_update_buffer(struct ssh_ext_mac_ctx *ctx, const struct sshbuf *b);
+int ssh_ext_mac_final(struct ssh_ext_mac_ctx *ctx, u_char *d, size_t dlen)
+ __attribute__((__bounded__(__buffer__, 2, 3)));
+void ssh_ext_mac_free(struct ssh_ext_mac_ctx *ctx);
+
+#endif /* _EXT_MAC_H */
diff --git a/gost-engine.c b/gost-engine.c
new file mode 100644
index 0000000..c0aac3f
--- /dev/null
+++ b/gost-engine.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018 Gleb Fotengauer-Malinovskiy. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <openssl/engine.h>
+#include <openssl/conf.h>
+
+#include "openbsd-compat/openssl-compat.h"
+
+static void
+init_algorithms() {
+ static int algorithms_init = -1;
+
+ if (algorithms_init < 0) {
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+ algorithms_init = 1;
+ }
+}
+
+static const EVP_MD*
+get_gost_md_by_nid(int nid)
+{
+ init_algorithms();
+
+ const EVP_MD* digest;
+ if (!(digest = EVP_get_digestbynid(nid)))
+ return NULL;
+
+ return digest;
+}
+
+static const EVP_CIPHER*
+get_gost_cipher_by_nid(int nid)
+{
+ init_algorithms();
+
+ const EVP_CIPHER *cipher;
+ if (!(cipher = EVP_get_cipherbynid(nid)))
+ return NULL;
+
+ return cipher;
+}
+
+const EVP_MD*
+EVP_streebog_256()
+{
+ return get_gost_md_by_nid(NID_id_GostR3411_2012_256);
+}
+
+const EVP_MD*
+EVP_streebog_512()
+{
+ return get_gost_md_by_nid(NID_id_GostR3411_2012_512);
+}
+
+const EVP_MD*
+EVP_grasshopper_omac()
+{
+ return get_gost_md_by_nid(NID_grasshopper_mac);
+}
+
+const EVP_CIPHER*
+EVP_magma_cbc()
+{
+ return get_gost_cipher_by_nid(NID_magma_cbc);
+}
+
+const EVP_CIPHER*
+EVP_magma_ctr()
+{
+ return get_gost_cipher_by_nid(NID_magma_ctr);
+}
+
+const EVP_CIPHER*
+EVP_grasshopper_cbc()
+{
+ return get_gost_cipher_by_nid(NID_grasshopper_cbc);
+}
+
+const EVP_CIPHER*
+EVP_grasshopper_ctr()
+{
+ return get_gost_cipher_by_nid(NID_grasshopper_ctr);
+}
diff --git a/gost-engine.h b/gost-engine.h
new file mode 100644
index 0000000..54e4b11
--- /dev/null
+++ b/gost-engine.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018 Gleb Fotengauer-Malinovskiy. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+const EVP_MD* EVP_streebog_256();
+const EVP_MD* EVP_streebog_512();
+const EVP_MD* EVP_grasshopper_omac();
+
+const EVP_CIPHER* EVP_magma_cbc();
+const EVP_CIPHER* EVP_magma_ctr();
+const EVP_CIPHER* EVP_grasshopper_cbc();
+const EVP_CIPHER* EVP_grasshopper_ctr();
diff --git a/mac.c b/mac.c
index 51dc11d..be27109 100644
--- a/mac.c
+++ b/mac.c
@@ -32,6 +32,7 @@
#include "digest.h"
#include "hmac.h"
+#include "ext-mac.h"
#include "umac.h"
#include "mac.h"
#include "misc.h"
@@ -43,6 +44,7 @@
#define SSH_DIGEST 1 /* SSH_DIGEST_XXX */
#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */
#define SSH_UMAC128 3
+#define SSH_EXTMAC 4
struct macalg {
char *name;
@@ -79,6 +81,17 @@ static const struct macalg macs[] = {
{ "umac-64-etm@openssh.com", SSH_UMAC, 0, 0, 128, 64, 1 },
{ "umac-128-etm@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 1 },
+ { "grasshopper-mac@altlinux.org", SSH_EXTMAC, SSH_DIGEST_GRASSHOPPER, 0, 256, 64, 0 },
+
+ { "hmac-gostr3411-2012-256@altlinux.org", SSH_DIGEST, SSH_DIGEST_STREEBOG_256, 0, 0, 0, 0 },
+ { "hmac-streebog-256@altlinux.org", SSH_DIGEST, SSH_DIGEST_STREEBOG_256, 0, 0, 0, 0 },
+ { "hmac-gostr3411-2012-512@altlinux.org", SSH_DIGEST, SSH_DIGEST_STREEBOG_512, 0, 0, 0, 0 },
+ { "hmac-streebog-512@altlinux.org", SSH_DIGEST, SSH_DIGEST_STREEBOG_512, 0, 0, 0, 0 },
+
+ { "hmac-gostr3411-2012-256-etm@altlinux.org", SSH_DIGEST, SSH_DIGEST_STREEBOG_256, 0, 0, 0, 1 },
+ { "hmac-streebog-256-etm@altlinux.org", SSH_DIGEST, SSH_DIGEST_STREEBOG_256, 0, 0, 0, 1 },
+ { "hmac-gostr3411-2012-512-etm@altlinux.org", SSH_DIGEST, SSH_DIGEST_STREEBOG_512, 0, 0, 0, 1 },
+ { "hmac-streebog-512-etm@altlinux.org", SSH_DIGEST, SSH_DIGEST_STREEBOG_512, 0, 0, 0, 1 },
{ NULL, 0, 0, 0, 0, 0, 0 }
};
@@ -91,6 +104,8 @@ mac_alg_list(char sep)
const struct macalg *m;
for (m = macs; m->name != NULL; m++) {
+ if (ssh_digest_avaliable(m->alg) < 0)
+ continue;
if (ret != NULL)
ret[rlen++] = sep;
nlen = strlen(m->name);
@@ -113,6 +128,11 @@ mac_setup_by_alg(struct sshmac *mac, const struct macalg *macalg)
if ((mac->hmac_ctx = ssh_hmac_start(macalg->alg)) == NULL)
return SSH_ERR_ALLOC_FAIL;
mac->key_len = mac->mac_len = ssh_hmac_bytes(macalg->alg);
+ } else if (mac->type == SSH_EXTMAC) {
+ if ((mac->ext_mac_ctx = ssh_ext_mac_start(macalg->alg)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ mac->mac_len = macalg->len / 8;
+ mac->key_len = macalg->key_len / 8;
} else {
mac->mac_len = macalg->len / 8;
mac->key_len = macalg->key_len / 8;
@@ -150,6 +170,11 @@ mac_init(struct sshmac *mac)
ssh_hmac_init(mac->hmac_ctx, mac->key, mac->key_len) < 0)
return SSH_ERR_INVALID_ARGUMENT;
return 0;
+ case SSH_EXTMAC:
+ if (mac->ext_mac_ctx == NULL ||
+ ssh_ext_mac_init(mac->ext_mac_ctx, mac->key, mac->key_len) < 0)
+ return SSH_ERR_INVALID_ARGUMENT;
+ return 0;
case SSH_UMAC:
if ((mac->umac_ctx = umac_new(mac->key)) == NULL)
return SSH_ERR_ALLOC_FAIL;
@@ -188,6 +213,15 @@ mac_compute(struct sshmac *mac, u_int32_t seqno,
ssh_hmac_final(mac->hmac_ctx, u.m, sizeof(u.m)) < 0)
return SSH_ERR_LIBCRYPTO_ERROR;
break;
+ case SSH_EXTMAC:
+ put_u32(b, seqno);
+ /* reset HMAC context */
+ if (ssh_ext_mac_init(mac->ext_mac_ctx, NULL, 0) < 0 ||
+ ssh_ext_mac_update(mac->ext_mac_ctx, b, sizeof(b)) < 0 ||
+ ssh_ext_mac_update(mac->ext_mac_ctx, data, datalen) < 0 ||
+ ssh_ext_mac_final(mac->ext_mac_ctx, u.m, sizeof(u.m)) < 0)
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ break;
case SSH_UMAC:
POKE_U64(nonce, seqno);
umac_update(mac->umac_ctx, data, datalen);
@@ -242,6 +276,19 @@ mac_clear(struct sshmac *mac)
mac->umac_ctx = NULL;
}
+static int
+mac_avaliable(char *name)
+{
+ const struct macalg *m;
+
+ for (m = macs; m->name != NULL; m++) {
+ if (strcmp(name, m->name) != 0)
+ continue;
+ return ssh_digest_avaliable(m->alg);
+ }
+ return SSH_ERR_INVALID_ARGUMENT;
+}
+
/* XXX copied from ciphers_valid */
#define MAC_SEP ","
int
@@ -255,7 +302,7 @@ mac_valid(const char *names)
return 0;
for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0';
(p = strsep(&cp, MAC_SEP))) {
- if (mac_setup(NULL, p) < 0) {
+ if (mac_avaliable(p) < 0 || mac_setup(NULL, p) < 0) {
free(maclist);
return 0;
}
diff --git a/mac.h b/mac.h
index 0b119d7..7612f93 100644
--- a/mac.h
+++ b/mac.h
@@ -37,6 +37,7 @@ struct sshmac {
int type;
int etm; /* Encrypt-then-MAC */
struct ssh_hmac_ctx *hmac_ctx;
+ struct ssh_ext_mac_ctx *ext_mac_ctx;
struct umac_ctx *umac_ctx;
};
diff --git a/sshd.c b/sshd.c
index 7a3384c..b7c092e 100644
--- a/sshd.c
+++ b/sshd.c
@@ -78,6 +78,7 @@
#include <openssl/bn.h>
#include <openssl/rand.h>
#include "openbsd-compat/openssl-compat.h"
+#include "gost-engine.h"
#endif
#ifdef HAVE_SECUREWARE
--
1.7.3.3

View file

@ -14,7 +14,7 @@
Summary: OpenSSH free Secure Shell (SSH) implementation
Name: openssh
Version: 8.2p1
Release: 1
Release: 2
License: BSD
Group: Networking/Remote access
Url: http://www.openssh.com/
@ -56,6 +56,15 @@ Patch31: openssh-6.6p1-keycat.patch
# Pass inetd flags for SELinux down to openbsd compat level
Patch32: openssh-7.6p1-cleanup-selinux.patch
# Support of GOST R 34.12-2015 and other GOSTs
# From http://git.altlinux.org/gears/o/openssh-gostcrypto.git
# Adjusted a bit for compatibility with both
# "xxx@altlinux.org" and "xxx" as algo names.
# TODO: get rid of dlopen()-ing gost-engine and use LibreSSL,
# delete checks of availability of algos (not needed in case of
# LibreSSL where they are known at compile time).
Patch40: ALT-openssh-openssl-gost-engine.patch
BuildRequires: groff-base
BuildRequires: systemd-units
%if %{with ldap}