From acc6d5b84fe4e1f8d5c325c4e5bdec89b8e9eb49 Mon Sep 17 00:00:00 2001 From: Mikhail Novosyolov Date: Thu, 20 Feb 2020 11:07:57 +0300 Subject: [PATCH] support GOST (from ALT Linux) --- ALT-openssh-openssl-gost-engine.patch | 636 ++++++++++++++++++++++++++ openssh.spec | 11 +- 2 files changed, 646 insertions(+), 1 deletion(-) create mode 100644 ALT-openssh-openssl-gost-engine.patch diff --git a/ALT-openssh-openssl-gost-engine.patch b/ALT-openssh-openssl-gost-engine.patch new file mode 100644 index 0000000..c5d15cf --- /dev/null +++ b/ALT-openssh-openssl-gost-engine.patch @@ -0,0 +1,636 @@ +From ac75e02d00b0779ad3d48fc1b2bf8af978ae6890 Mon Sep 17 00:00:00 2001 +From: Gleb Fotengauer-Malinovskiy +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 ++#include ++ ++#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 ++#include ++ ++#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 + #include + #include "openbsd-compat/openssl-compat.h" ++#include "gost-engine.h" + #endif + + #ifdef HAVE_SECUREWARE +-- +1.7.3.3 + diff --git a/openssh.spec b/openssh.spec index fddf4c6..9fd87a2 100644 --- a/openssh.spec +++ b/openssh.spec @@ -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}