]> wagner.pp.ru Git - openssl-gost/engine.git/commitdiff
Special branch reuires patching OpenSSL
authorDmitry Belyavskiy <beldmit@gmail.com>
Wed, 2 Sep 2020 14:59:21 +0000 (17:59 +0300)
committerDmitry Belyavskiy <beldmit@gmail.com>
Wed, 2 Sep 2020 14:59:21 +0000 (17:59 +0300)
This branch is created for experiments with the patched OpenSSL version.
The patch implements Russian GOST TLS 1.2 and TLS 1.3 support in
OpenSSL.

Some parts of the patch are already included in OpenSSL 3.0, some are
not and possibly, will never be.

This branch is recommended for ditribution builders and those who want
make experiments. It MUST NOT be used instead of system OpenSSL.

CMakeLists.txt
README.md
patches/openssl_111g.diff [new file with mode: 0644]

index 1d4d65b86de17edf15ba656cb0b8dab578af5487..28236b54b98d893d4a215764460b8f787604c487 100644 (file)
@@ -8,7 +8,7 @@ include(CheckCSourceRuns)
 
 enable_testing()
 
-find_package(OpenSSL 3.0 REQUIRED)
+find_package(OpenSSL 1.1.1 REQUIRED)
 include_directories(${OPENSSL_INCLUDE_DIR})
 
 if (CMAKE_C_COMPILER_ID MATCHES "Clang")
index aa636d71fed413f0483d459578bf0959955b2274..fde70cba68effb8b5f18ef1dd73fb7602ec33ff6 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
 # engine
 A reference implementation of the Russian GOST crypto algorithms for OpenSSL
 
-Compatibility: OpenSSL 1.0.2 (needs patches), OpenSSL 1.1.*
+Compatibility: OpenSSL 1.1.1 (needs patches)
+*This branch should not compile with vanilla OpenSSL 1.1.1!
+It requires patching OpenSSL using the patches/openssl_111g.diff*
 
 License: same as the corresponding version of OpenSSL.
 
diff --git a/patches/openssl_111g.diff b/patches/openssl_111g.diff
new file mode 100644 (file)
index 0000000..fa3dd56
--- /dev/null
@@ -0,0 +1,3372 @@
+Index: apps/cms.c
+===================================================================
+--- apps/cms.c (revision 14523)
++++ apps/cms.c (working copy)
+@@ -75,15 +75,16 @@
+     OPT_NOSIGS, OPT_NO_CONTENT_VERIFY, OPT_NO_ATTR_VERIFY, OPT_INDEF,
+     OPT_NOINDEF, OPT_CRLFEOL, OPT_NOOUT, OPT_RR_PRINT,
+     OPT_RR_ALL, OPT_RR_FIRST, OPT_RCTFORM, OPT_CERTFILE, OPT_CAFILE,
+-    OPT_CAPATH, OPT_NOCAPATH, OPT_NOCAFILE,OPT_CONTENT, OPT_PRINT,
++    OPT_CAPATH, OPT_NOCAPATH, OPT_NOCAFILE,OPT_CONTENT, OPT_PRINT, OPT_NAMEOPT,
+     OPT_SECRETKEY, OPT_SECRETKEYID, OPT_PWRI_PASSWORD, OPT_ECONTENT_TYPE,
+     OPT_PASSIN, OPT_TO, OPT_FROM, OPT_SUBJECT, OPT_SIGNER, OPT_RECIP,
+     OPT_CERTSOUT, OPT_MD, OPT_INKEY, OPT_KEYFORM, OPT_KEYOPT, OPT_RR_FROM,
+     OPT_RR_TO, OPT_AES128_WRAP, OPT_AES192_WRAP, OPT_AES256_WRAP,
+-    OPT_3DES_WRAP, OPT_ENGINE,
++    OPT_3DES_WRAP, OPT_WRAP, OPT_ENGINE,
+     OPT_R_ENUM,
+     OPT_V_ENUM,
+-    OPT_CIPHER
++    OPT_CIPHER,
++    OPT_ORIGINATOR
+ } OPTION_CHOICE;
+ const OPTIONS cms_options[] = {
+@@ -150,6 +151,8 @@
+      "Supply or override content for detached signature"},
+     {"print", OPT_PRINT, '-',
+      "For the -cmsout operation print out all fields of the CMS structure"},
++    {"nameopt", OPT_NAMEOPT, 's',
++     "For the -print option specifies various strings printing options"},
+     {"secretkey", OPT_SECRETKEY, 's'},
+     {"secretkeyid", OPT_SECRETKEYID, 's'},
+     {"pwri_password", OPT_PWRI_PASSWORD, 's'},
+@@ -159,6 +162,7 @@
+     {"from", OPT_FROM, 's', "From address"},
+     {"subject", OPT_SUBJECT, 's', "Subject"},
+     {"signer", OPT_SIGNER, 's', "Signer certificate file"},
++    {"originator", OPT_ORIGINATOR, 's', "Originator certificate file"},
+     {"recip", OPT_RECIP, '<', "Recipient cert file for decryption"},
+     {"certsout", OPT_CERTSOUT, '>', "Certificate output file"},
+     {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"},
+@@ -177,6 +181,7 @@
+ # ifndef OPENSSL_NO_DES
+     {"des3-wrap", OPT_3DES_WRAP, '-', "Use 3DES-EDE to wrap key"},
+ # endif
++    {"wrap", OPT_WRAP, 's', "Any wrap cipher to wrap key"},
+ # ifndef OPENSSL_NO_ENGINE
+     {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"},
+ # endif
+@@ -196,7 +201,7 @@
+     STACK_OF(OPENSSL_STRING) *rr_to = NULL, *rr_from = NULL;
+     STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
+     STACK_OF(X509) *encerts = NULL, *other = NULL;
+-    X509 *cert = NULL, *recip = NULL, *signer = NULL;
++    X509 *cert = NULL, *recip = NULL, *signer = NULL, *originator = 0;
+     X509_STORE *store = NULL;
+     X509_VERIFY_PARAM *vpm = NULL;
+     char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
+@@ -204,7 +209,7 @@
+     char *certsoutfile = NULL;
+     int noCAfile = 0, noCApath = 0;
+     char *infile = NULL, *outfile = NULL, *rctfile = NULL;
+-    char *passinarg = NULL, *passin = NULL, *signerfile = NULL, *recipfile = NULL;
++    char *passinarg = NULL, *passin = NULL, *signerfile = NULL, *originatorfile = NULL, *recipfile = NULL;
+     char *to = NULL, *from = NULL, *subject = NULL, *prog;
+     cms_key_param *key_first = NULL, *key_param = NULL;
+     int flags = CMS_DETACHED, noout = 0, print = 0, keyidx = -1, vpmtouched = 0;
+@@ -406,6 +411,10 @@
+         case OPT_PRINT:
+             noout = print = 1;
+             break;
++        case OPT_NAMEOPT:
++            if (!set_nameopt(opt_arg()))
++                goto opthelp;
++            break;
+         case OPT_SECRETKEY:
+             if (secret_key != NULL) {
+                 BIO_printf(bio_err, "Invalid key (supplied twice) %s\n",
+@@ -486,6 +495,9 @@
+             }
+             signerfile = opt_arg();
+             break;
++        case OPT_ORIGINATOR:
++             originatorfile = opt_arg();
++             break;
+         case OPT_INKEY:
+             /* If previous -inkey argument add signer to list */
+             if (keyfile != NULL) {
+@@ -580,6 +592,10 @@
+         case OPT_AES256_WRAP:
+             wrap_cipher = EVP_aes_256_wrap();
+             break;
++        case OPT_WRAP:
++            if (!opt_cipher(opt_unknown(), &wrap_cipher))
++                goto end;
++            break;
+         }
+     }
+     argc = opt_num_rest();
+@@ -687,11 +703,11 @@
+     }
+     if (certfile != NULL) {
+-        if (!load_certs(certfile, &other, FORMAT_PEM, NULL,
+-                        "certificate file")) {
+-            ERR_print_errors(bio_err);
+-            goto end;
+-        }
++         if (!load_certs(certfile, &other, FORMAT_PEM, NULL,
++              "certificate file")) {
++              ERR_print_errors(bio_err);
++              goto end;
++         }
+     }
+     if (recipfile != NULL && (operation == SMIME_DECRYPT)) {
+@@ -702,6 +718,15 @@
+         }
+     }
++    if (originatorfile != NULL)
++    {
++         if ((originator = load_cert(originatorfile, FORMAT_PEM,
++              "originator certificate file")) == NULL) {
++              ERR_print_errors(bio_err);
++              goto end;
++         }
++    }
++
+     if (operation == SMIME_SIGN_RECEIPT) {
+         if ((signer = load_cert(signerfile, FORMAT_PEM,
+                                 "receipt signer certificate file")) == NULL) {
+@@ -710,7 +735,8 @@
+         }
+     }
+-    if (operation == SMIME_DECRYPT) {
++    if (operation == SMIME_DECRYPT ||
++         operation == SMIME_ENCRYPT) {
+         if (keyfile == NULL)
+             keyfile = recipfile;
+     } else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) {
+@@ -819,23 +845,31 @@
+         for (i = 0; i < sk_X509_num(encerts); i++) {
+             CMS_RecipientInfo *ri;
+             cms_key_param *kparam;
+-            int tflags = flags;
++            int tflags = flags | CMS_KEY_PARAM; /* This flag enforces allocating the EVP_PKEY_CTX for the recipient here */
++            EVP_PKEY_CTX *pctx;
+             X509 *x = sk_X509_value(encerts, i);
++            int res;
++
+             for (kparam = key_first; kparam; kparam = kparam->next) {
+                 if (kparam->idx == i) {
+-                    tflags |= CMS_KEY_PARAM;
+                     break;
+                 }
+             }
+-            ri = CMS_add1_recipient_cert(cms, x, tflags);
++            ri = CMS_add1_recipient(cms, x, key, originator, tflags);
+             if (ri == NULL)
+                 goto end;
++
++            pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
+             if (kparam != NULL) {
+-                EVP_PKEY_CTX *pctx;
+-                pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
+                 if (!cms_set_pkey_param(pctx, kparam->param))
+                     goto end;
+             }
++
++            res = EVP_PKEY_CTX_ctrl(pctx, -1, -1,
++                        EVP_PKEY_CTRL_CIPHER, EVP_CIPHER_nid(cipher), NULL);
++            if (res <= 0 && res != -2)
++                goto end;
++
+             if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_AGREE
+                 && wrap_cipher) {
+                 EVP_CIPHER_CTX *wctx;
+@@ -981,7 +1015,7 @@
+         }
+         if (key != NULL) {
+-            if (!CMS_decrypt_set1_pkey(cms, key, recip)) {
++            if (!CMS_decrypt_set1_pkey_and_peer(cms, key, recip, originator)) {
+                 BIO_puts(bio_err, "Error decrypting CMS using private key\n");
+                 goto end;
+             }
+@@ -1047,8 +1081,19 @@
+         }
+     } else {
+         if (noout) {
+-            if (print)
+-                CMS_ContentInfo_print_ctx(out, cms, 0, NULL);
++            if (print) {
++                ASN1_PCTX *pctx = NULL;
++                if (get_nameopt() != XN_FLAG_ONELINE) {
++                    pctx = ASN1_PCTX_new();
++                    if (pctx) { /* Print anyway if malloc failed */
++                        ASN1_PCTX_set_flags(pctx, ASN1_PCTX_FLAGS_SHOW_ABSENT);
++                        ASN1_PCTX_set_str_flags(pctx, get_nameopt());
++                        ASN1_PCTX_set_nm_flags(pctx, get_nameopt());
++                    }
++                }
++                 CMS_ContentInfo_print_ctx(out, cms, 0, pctx);
++                ASN1_PCTX_free(pctx);
++            }
+         } else if (outformat == FORMAT_SMIME) {
+             if (to)
+                 BIO_printf(out, "To: %s%s", to, mime_eol);
+Index: apps/s_cb.c
+===================================================================
+--- apps/s_cb.c        (revision 14523)
++++ apps/s_cb.c        (working copy)
+@@ -684,7 +684,7 @@
+     {NULL}
+ };
+-/* from rfc8446 4.2.3. + gost (https://tools.ietf.org/id/draft-smyshlyaev-tls12-gost-suites-04.html) */
++/* from rfc8446 4.2.3. + GOST (https://tools.ietf.org/html/draft-smyshlyaev-tls13-gost-suites-01) */
+ static STRINT_PAIR signature_tls13_scheme_list[] = {
+     {"rsa_pkcs1_sha1",         0x0201 /* TLSEXT_SIGALG_rsa_pkcs1_sha1 */},
+     {"ecdsa_sha1",             0x0203 /* TLSEXT_SIGALG_ecdsa_sha1 */},
+@@ -696,6 +696,13 @@
+     {"ecdsa_secp384r1_sha384", 0x0503 /* TLSEXT_SIGALG_ecdsa_secp384r1_sha384 */},
+     {"rsa_pkcs1_sha512",       0x0601 /* TLSEXT_SIGALG_rsa_pkcs1_sha512 */},
+     {"ecdsa_secp521r1_sha512", 0x0603 /* TLSEXT_SIGALG_ecdsa_secp521r1_sha512 */},
++    {"gostr34102012_256a",     0x0709 /* TLSEXT_SIGALG_gostr34102012_256a */},
++    {"gostr34102012_256b",     0x070A /* TLSEXT_SIGALG_gostr34102012_256b */},
++    {"gostr34102012_256c",     0x070B /* TLSEXT_SIGALG_gostr34102012_256c */},
++    {"gostr34102012_256d",     0x070C /* TLSEXT_SIGALG_gostr34102012_256d */},
++    {"gostr34102012_512a",     0x070D /* TLSEXT_SIGALG_gostr34102012_512a */},
++    {"gostr34102012_512b",     0x070E /* TLSEXT_SIGALG_gostr34102012_512b */},
++    {"gostr34102012_512c",     0x070F /* TLSEXT_SIGALG_gostr34102012_512c */},
+     {"rsa_pss_rsae_sha256",    0x0804 /* TLSEXT_SIGALG_rsa_pss_rsae_sha256 */},
+     {"rsa_pss_rsae_sha384",    0x0805 /* TLSEXT_SIGALG_rsa_pss_rsae_sha384 */},
+     {"rsa_pss_rsae_sha512",    0x0806 /* TLSEXT_SIGALG_rsa_pss_rsae_sha512 */},
+@@ -704,9 +711,6 @@
+     {"rsa_pss_pss_sha256",     0x0809 /* TLSEXT_SIGALG_rsa_pss_pss_sha256 */},
+     {"rsa_pss_pss_sha384",     0x080a /* TLSEXT_SIGALG_rsa_pss_pss_sha384 */},
+     {"rsa_pss_pss_sha512",     0x080b /* TLSEXT_SIGALG_rsa_pss_pss_sha512 */},
+-    {"gostr34102001",          0xeded /* TLSEXT_SIGALG_gostr34102001_gostr3411 */},
+-    {"gostr34102012_256",      0xeeee /* TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256 */},
+-    {"gostr34102012_512",      0xefef /* TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512 */},
+     {NULL}
+ };
+Index: crypto/objects/objects.txt
+===================================================================
+--- crypto/objects/objects.txt (revision 14523)
++++ crypto/objects/objects.txt (working copy)
+@@ -1321,6 +1321,14 @@
+ # TC26 GOST OIDs
++id-tc26 0             : id-tc26-modules: GOST TC26 ASN.1 modules
++
++id-tc26-modules 6 : id-tc26-cms: GOST TC26 SMS
++
++id-tc26-cms 1 : id-tc26-cms-attrs: GOST TC26 SMS attributes
++
++id-tc26-cms-attrs 1 : id-tc26-mac-attr: GOST TC26 SMS content-mac attribute
++
+ id-tc26 1             : id-tc26-algorithms
+ id-tc26-algorithms 1  : id-tc26-sign
+ !Cname id-GostR3410-2012-256
+@@ -1344,11 +1352,11 @@
+ id-tc26-algorithms 5  : id-tc26-cipher
+ id-tc26-cipher 1      :  id-tc26-cipher-gostr3412-2015-magma
+-id-tc26-cipher-gostr3412-2015-magma 1 : id-tc26-cipher-gostr3412-2015-magma-ctracpkm
+-id-tc26-cipher-gostr3412-2015-magma 2 : id-tc26-cipher-gostr3412-2015-magma-ctracpkm-omac
++id-tc26-cipher-gostr3412-2015-magma 1 : magma-ctr-acpkm
++id-tc26-cipher-gostr3412-2015-magma 2 : magma-ctr-acpkm-omac
+ id-tc26-cipher 2      :  id-tc26-cipher-gostr3412-2015-kuznyechik
+-id-tc26-cipher-gostr3412-2015-kuznyechik 1    : id-tc26-cipher-gostr3412-2015-kuznyechik-ctracpkm
+-id-tc26-cipher-gostr3412-2015-kuznyechik 2    : id-tc26-cipher-gostr3412-2015-kuznyechik-ctracpkm-omac
++id-tc26-cipher-gostr3412-2015-kuznyechik 1    : kuznyechik-ctr-acpkm
++id-tc26-cipher-gostr3412-2015-kuznyechik 2    : kuznyechik-ctr-acpkm-omac
+ id-tc26-algorithms 6  : id-tc26-agreement
+ id-tc26-agreement 1   : id-tc26-agreement-gost-3410-2012-256
+@@ -1356,9 +1364,9 @@
+ id-tc26-algorithms 7  :       id-tc26-wrap
+ id-tc26-wrap 1        : id-tc26-wrap-gostr3412-2015-magma
+-id-tc26-wrap-gostr3412-2015-magma 1   : id-tc26-wrap-gostr3412-2015-magma-kexp15
++id-tc26-wrap-gostr3412-2015-magma 1   : magma-kexp15
+ id-tc26-wrap 2        : id-tc26-wrap-gostr3412-2015-kuznyechik
+-id-tc26-wrap-gostr3412-2015-kuznyechik 1      : id-tc26-wrap-gostr3412-2015-kuznyechik-kexp15
++id-tc26-wrap-gostr3412-2015-kuznyechik 1      : kuznyechik-kexp15
+ id-tc26 2             : id-tc26-constants
+@@ -1382,16 +1390,25 @@
+ member-body 643 3 131 1 1     : INN   : INN
+ member-body 643 100 1         : OGRN  : OGRN
+ member-body 643 100 3         : SNILS : SNILS
++member-body 643 100 5         : OGRNIP        : OGRNIP
+ member-body 643 100 111       : subjectSignTool       : Signing Tool of Subject
+ member-body 643 100 112       : issuerSignTool        : Signing Tool of Issuer
++member-body 643 100 113  : classSignTool   : Class of Signing Tool
++member-body 643 100 113 1 : classSignToolKC1 : Class of Signing Tool KC1
++member-body 643 100 113 2 : classSignToolKC2 : Class of Signing Tool KC2
++member-body 643 100 113 3 : classSignToolKC3 : Class of Signing Tool KC3
++member-body 643 100 113 4 : classSignToolKB1 : Class of Signing Tool KB1
++member-body 643 100 113 5 : classSignToolKB2 : Class of Signing Tool KB2
++member-body 643 100 113 6 : classSignToolKA1 : Class of Signing Tool KA1
+ #GOST R34.13-2015 Grasshopper "Kuznechik"
+-                      : grasshopper-ecb
+-                      : grasshopper-ctr
+-                      : grasshopper-ofb
+-                      : grasshopper-cbc
+-                      : grasshopper-cfb
+-                      : grasshopper-mac
++                      : kuznyechik-ecb
++                      : kuznyechik-ctr
++                      : kuznyechik-ofb
++                      : kuznyechik-cbc
++                      : kuznyechik-cfb
++                      : kuznyechik-mac
++                      : kuznyechik-mgm
+ #GOST R34.13-2015 Magma
+                       : magma-ecb
+@@ -1400,6 +1417,7 @@
+                       : magma-cbc
+                       : magma-cfb
+                       : magma-mac
++                      : magma-mgm
+ # Definitions for Camellia cipher - CBC MODE
+Index: crypto/cms/cms_local.h
+===================================================================
+--- crypto/cms/cms_local.h     (revision 14523)
++++ crypto/cms/cms_local.h     (working copy)
+@@ -403,12 +403,13 @@
+ ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si);
+ BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
++int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain);
+ CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms);
+ int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd);
+ int cms_pkey_get_ri_type(EVP_PKEY *pk);
++int cms_pkey_is_ri_type_supported(EVP_PKEY *pk, int ri_type);
+ /* KARI routines */
+-int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip,
+-                                EVP_PKEY *pk, unsigned int flags);
++int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri,  X509 *recip, EVP_PKEY *recipPubKey, X509 * originator, EVP_PKEY *originatorPrivKey, unsigned int flags);
+ int cms_RecipientInfo_kari_encrypt(CMS_ContentInfo *cms,
+                                    CMS_RecipientInfo *ri);
+Index: crypto/cms/cms_lib.c
+===================================================================
+--- crypto/cms/cms_lib.c       (revision 14523)
++++ crypto/cms/cms_lib.c       (working copy)
+@@ -130,12 +130,14 @@
+     switch (OBJ_obj2nid(cms->contentType)) {
+     case NID_pkcs7_data:
+-    case NID_pkcs7_enveloped:
+     case NID_pkcs7_encrypted:
+     case NID_id_smime_ct_compressedData:
+         /* Nothing to do */
+         return 1;
++    case NID_pkcs7_enveloped:
++        return cms_EnvelopedData_final(cms, cmsbio);
++
+     case NID_pkcs7_signed:
+         return cms_SignedData_final(cms, cmsbio);
+Index: crypto/cms/cms_smime.c
+===================================================================
+--- crypto/cms/cms_smime.c     (revision 14523)
++++ crypto/cms/cms_smime.c     (working copy)
+@@ -576,8 +576,8 @@
+     return NULL;
+ }
+-static int cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
+-                              EVP_PKEY *pk, X509 *cert)
++static int cms_kari_set1_pkey_and_peer(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
++                              EVP_PKEY *pk, X509 *cert, X509 *peer)
+ {
+     int i;
+     STACK_OF(CMS_RecipientEncryptedKey) *reks;
+@@ -588,7 +588,7 @@
+         rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
+         if (cert != NULL && CMS_RecipientEncryptedKey_cert_cmp(rek, cert))
+             continue;
+-        CMS_RecipientInfo_kari_set0_pkey(ri, pk);
++        CMS_RecipientInfo_kari_set0_pkey_and_peer(ri, pk, peer);
+         rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek);
+         CMS_RecipientInfo_kari_set0_pkey(ri, NULL);
+         if (rv > 0)
+@@ -600,27 +600,35 @@
+ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
+ {
++     return CMS_decrypt_set1_pkey_and_peer(cms, pk, cert, NULL);
++}
++
++int CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, X509 *peer)
++{
+     STACK_OF(CMS_RecipientInfo) *ris;
+     CMS_RecipientInfo *ri;
+-    int i, r, ri_type;
++    int i, r, cms_pkey_ri_type;
+     int debug = 0, match_ri = 0;
+     ris = CMS_get0_RecipientInfos(cms);
+     if (ris)
+         debug = cms->d.envelopedData->encryptedContentInfo->debug;
+-    ri_type = cms_pkey_get_ri_type(pk);
+-    if (ri_type == CMS_RECIPINFO_NONE) {
+-        CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY,
+-               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+-        return 0;
++
++    cms_pkey_ri_type = cms_pkey_get_ri_type(pk);
++    if (cms_pkey_ri_type == CMS_RECIPINFO_NONE) {
++         CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER,
++              CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
++         return 0;
+     }
+     for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
++        int ri_type;
+         ri = sk_CMS_RecipientInfo_value(ris, i);
+-        if (CMS_RecipientInfo_type(ri) != ri_type)
+-            continue;
++        ri_type = CMS_RecipientInfo_type(ri);
++/*        if (!cms_pkey_is_ri_type_supported(pk, ri_type))
++            continue; */
+         match_ri = 1;
+         if (ri_type == CMS_RECIPINFO_AGREE) {
+-            r = cms_kari_set1_pkey(cms, ri, pk, cert);
++            r = cms_kari_set1_pkey_and_peer(cms, ri, pk, cert, peer);
+             if (r > 0)
+                 return 1;
+             if (r < 0)
+@@ -640,13 +648,13 @@
+                  * If not debugging clear any error and return success to
+                  * avoid leaking of information useful to MMA
+                  */
+-                if (!debug) {
++                if (!debug && cms_pkey_ri_type == CMS_RECIPINFO_TRANS) {
+                     ERR_clear_error();
+                     return 1;
+                 }
+                 if (r > 0)
+                     return 1;
+-                CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR);
++                CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER, CMS_R_DECRYPT_ERROR);
+                 return 0;
+             }
+             /*
+@@ -654,17 +662,17 @@
+              * successful decrypt. Always attempt to decrypt all recipients
+              * to avoid leaking timing of a successful decrypt.
+              */
+-            else if (r > 0 && debug)
++            else if (r > 0 && (debug || cms_pkey_ri_type != CMS_RECIPINFO_TRANS))
+                 return 1;
+         }
+     }
+     /* If no cert, key transport and not debugging always return success */
+-    if (cert == NULL && ri_type == CMS_RECIPINFO_TRANS && match_ri && !debug) {
++    if (cert == NULL && cms_pkey_ri_type == CMS_RECIPINFO_TRANS && match_ri && !debug) {
+         ERR_clear_error();
+         return 1;
+     }
+-    CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
++    CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER, CMS_R_NO_MATCHING_RECIPIENT);
+     return 0;
+ }
+Index: crypto/cms/cms_kari.c
+===================================================================
+--- crypto/cms/cms_kari.c      (revision 14523)
++++ crypto/cms/cms_kari.c      (working copy)
+@@ -152,7 +152,7 @@
+         return -1;
+ }
+-int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
++int CMS_RecipientInfo_kari_set0_pkey_and_peer(CMS_RecipientInfo *ri, EVP_PKEY *pk, X509 *peer)
+ {
+     EVP_PKEY_CTX *pctx;
+     CMS_KeyAgreeRecipientInfo *kari = ri->d.kari;
+@@ -164,6 +164,16 @@
+     pctx = EVP_PKEY_CTX_new(pk, NULL);
+     if (!pctx || EVP_PKEY_derive_init(pctx) <= 0)
+         goto err;
++
++    if (peer)
++    {
++         EVP_PKEY *pub_pkey = X509_get0_pubkey(peer);
++         if (0 >= EVP_PKEY_derive_set_peer(pctx, pub_pkey))
++         {
++              goto err;
++         }
++    }
++
+     kari->pctx = pctx;
+     return 1;
+  err:
+@@ -171,6 +181,11 @@
+     return 0;
+ }
++int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
++{
++     return CMS_RecipientInfo_kari_set0_pkey_and_peer(ri, pk, NULL);
++}
++
+ EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri)
+ {
+     if (ri->type == CMS_RECIPINFO_AGREE)
+@@ -282,10 +297,27 @@
+     return rv;
+ }
++/* Set originator private key and initialise context based on it */
++static int cms_kari_set_originator_private_key(CMS_KeyAgreeRecipientInfo *kari, EVP_PKEY *originatorPrivKey )
++{
++     EVP_PKEY_CTX *pctx = NULL;
++     int rv = 0;
++     pctx = EVP_PKEY_CTX_new(originatorPrivKey, NULL);
++     if (!pctx)
++          goto err;
++     if (EVP_PKEY_derive_init(pctx) <= 0)
++          goto err;
++     kari->pctx = pctx;
++     rv = 1;
++err:
++     if (!rv)
++          EVP_PKEY_CTX_free(pctx);
++     return rv;
++}
++
+ /* Initialise a kari based on passed certificate and key */
+-int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip,
+-                                EVP_PKEY *pk, unsigned int flags)
++int cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri,  X509 *recip, EVP_PKEY *recipPubKey, X509 * originator, EVP_PKEY *originatorPrivKey, unsigned int flags)
+ {
+     CMS_KeyAgreeRecipientInfo *kari;
+     CMS_RecipientEncryptedKey *rek = NULL;
+@@ -320,12 +352,45 @@
+             return 0;
+     }
+-    /* Create ephemeral key */
+-    if (!cms_kari_create_ephemeral_key(kari, pk))
+-        return 0;
++    if (!originatorPrivKey && !originator)
++    {
++         /* Create ephemeral key */
++         if (!cms_kari_create_ephemeral_key(kari, recipPubKey))
++              return 0;
++    }
++    else
++    {
++         /* Use originator key */
++         CMS_OriginatorIdentifierOrKey *oik = ri->d.kari->originator;
+-    EVP_PKEY_up_ref(pk);
+-    rek->pkey = pk;
++         if (!originatorPrivKey && !originator)
++         {
++              return 0;
++         }
++
++         if (flags & CMS_USE_ORIGINATOR_KEYID) {
++              //kari->originator->issuerAndSerialNumber
++              oik->type = CMS_OIK_KEYIDENTIFIER;
++              oik->d.subjectKeyIdentifier = ASN1_OCTET_STRING_new();
++              if (oik->d.subjectKeyIdentifier == NULL)
++                   return 0;
++              if (!cms_set1_keyid(&oik->d.subjectKeyIdentifier, originator))
++                   return 0;
++         }
++         else {
++              oik->type = CMS_REK_ISSUER_SERIAL;
++              if (!cms_set1_ias(&oik->d.issuerAndSerialNumber, originator))
++                   return 0;
++         }
++
++         if (!cms_kari_set_originator_private_key(kari, originatorPrivKey))
++         {
++              return 0;
++         }
++    }
++
++    EVP_PKEY_up_ref(recipPubKey);
++    rek->pkey = recipPubKey;
+     return 1;
+ }
+@@ -335,14 +400,35 @@
+     EVP_CIPHER_CTX *ctx = kari->ctx;
+     const EVP_CIPHER *kekcipher;
+     int keylen = EVP_CIPHER_key_length(cipher);
++    int ret;
+     /* If a suitable wrap algorithm is already set nothing to do */
+     kekcipher = EVP_CIPHER_CTX_cipher(ctx);
+-    if (kekcipher) {
+-        if (EVP_CIPHER_CTX_mode(ctx) != EVP_CIPH_WRAP_MODE)
+-            return 0;
+-        return 1;
++    if (kekcipher)
++    {
++         if (EVP_CIPHER_CTX_mode(ctx) != EVP_CIPH_WRAP_MODE)
++              return 0;
++         return 1;
+     }
++              /* Here the Infotecs patch begins */
++    else if (cipher && (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_GET_WRAP_CIPHER))
++    {
++         ret = EVP_CIPHER_meth_get_ctrl(cipher)(NULL, EVP_CTRL_GET_WRAP_CIPHER, 0, &kekcipher);
++         if (0 >= ret)
++         {
++              return 0;
++         }
++
++         if (kekcipher)
++         {
++              if (EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE)
++                   return 0;
++
++              return EVP_EncryptInit_ex(ctx, kekcipher, NULL, NULL, NULL);
++         }
++    }
++              /* Here the Infotecs patch ends */
++
+     /*
+      * Pick a cipher based on content encryption cipher. If it is DES3 use
+      * DES3 wrap otherwise use AES wrap similar to key size.
+Index: crypto/cms/cms_env.c
+===================================================================
+--- crypto/cms/cms_env.c       (revision 14523)
++++ crypto/cms/cms_env.c       (working copy)
+@@ -20,6 +20,8 @@
+ /* CMS EnvelopedData Utilities */
++static void cms_env_set_version(CMS_EnvelopedData *env);
++
+ CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
+ {
+     if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) {
+@@ -121,6 +123,39 @@
+     return NULL;
+ }
++int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain)
++{
++    CMS_EnvelopedData *env = NULL;
++    EVP_CIPHER_CTX *ctx = NULL;
++    BIO *mbio = BIO_find_type(chain, BIO_TYPE_CIPHER);
++
++    env = cms_get0_enveloped(cms);
++    if (!env)
++        return 0;
++
++    if (!mbio) {
++        CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CONTENT_NOT_FOUND);
++        return 0;
++    }
++
++    BIO_get_cipher_ctx(mbio, &ctx);
++
++    /*
++     * If the selected cipher supports unprotected attributes,
++     * deal with it using special ctrl function
++     */
++    if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) {
++      cms->d.envelopedData->unprotectedAttrs = sk_X509_ATTRIBUTE_new_null();
++      if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED, 1, env->unprotectedAttrs) <= 0) {
++        CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CTRL_FAILURE);
++        return 0;
++      }
++    }
++    cms_env_set_version(cms->d.envelopedData);
++
++    return 1;
++}
++
+ /* Key Transport Recipient Info (KTRI) routines */
+ /* Initialise a ktri based on passed certificate and key */
+@@ -175,8 +210,8 @@
+  * Add a recipient certificate using appropriate type of RecipientInfo
+  */
+-CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
+-                                           X509 *recip, unsigned int flags)
++CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip,
++          EVP_PKEY *originatorPrivKey, X509 * originator, unsigned int flags)
+ {
+     CMS_RecipientInfo *ri = NULL;
+     CMS_EnvelopedData *env;
+@@ -192,7 +227,7 @@
+     pk = X509_get0_pubkey(recip);
+     if (!pk) {
+-        CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_ERROR_GETTING_PUBLIC_KEY);
++        CMSerr(CMS_F_CMS_ADD1_RECIPIENT, CMS_R_ERROR_GETTING_PUBLIC_KEY);
+         goto err;
+     }
+@@ -204,12 +239,12 @@
+         break;
+     case CMS_RECIPINFO_AGREE:
+-        if (!cms_RecipientInfo_kari_init(ri, recip, pk, flags))
++        if (!cms_RecipientInfo_kari_init(ri, recip, pk, originator, originatorPrivKey, flags))
+             goto err;
+         break;
+     default:
+-        CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
++        CMSerr(CMS_F_CMS_ADD1_RECIPIENT,
+                CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+         goto err;
+@@ -221,7 +256,7 @@
+     return ri;
+  merr:
+-    CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE);
++    CMSerr(CMS_F_CMS_ADD1_RECIPIENT, ERR_R_MALLOC_FAILURE);
+  err:
+     M_ASN1_free_of(ri, CMS_RecipientInfo);
+     return NULL;
+@@ -228,6 +263,12 @@
+ }
++CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
++     X509 *recip, unsigned int flags)
++{
++     return CMS_add1_recipient(cms, recip, NULL, NULL, flags);
++}
++
+ int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
+                                      EVP_PKEY **pk, X509 **recip,
+                                      X509_ALGOR **palg)
+@@ -856,52 +897,90 @@
+     env->version = 0;
+ }
+-BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
++static BIO *cms_EnvelopedData_Decryption_init_bio(CMS_ContentInfo *cms)
+ {
+-    CMS_EncryptedContentInfo *ec;
+-    STACK_OF(CMS_RecipientInfo) *rinfos;
+-    CMS_RecipientInfo *ri;
+-    int i, ok = 0;
+-    BIO *ret;
++    CMS_EncryptedContentInfo *ec = cms->d.envelopedData->encryptedContentInfo;
++    BIO *contentBio = cms_EncryptedContent_init_bio(ec);
++    EVP_CIPHER_CTX *ctx = NULL;
+-    /* Get BIO first to set up key */
++    if (!contentBio)
++        return NULL;
+-    ec = cms->d.envelopedData->encryptedContentInfo;
+-    ret = cms_EncryptedContent_init_bio(ec);
++    BIO_get_cipher_ctx(contentBio, &ctx);
++    if (ctx == NULL) {
++        BIO_free(contentBio);
++        return NULL;
++              }
++/* 
++ * If the selected cipher supports unprotected attributes,
++ * deal with it using special ctrl function
++ */
++              if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC &&
++        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED, 0, cms->d.envelopedData->unprotectedAttrs) <= 0) {
++        BIO_free(contentBio);
++        return NULL;
++              }
++    return contentBio;
++}
+-    /* If error or no cipher end of processing */
++static BIO *cms_EnvelopedData_Encryption_init_bio(CMS_ContentInfo *cms)
++{
++     CMS_EncryptedContentInfo *ec;
++     STACK_OF(CMS_RecipientInfo) *rinfos;
++     CMS_RecipientInfo *ri;
++     int i, ok = 0;
++     BIO *ret;
+-    if (!ret || !ec->cipher)
+-        return ret;
++     /* Get BIO first to set up key */
+-    /* Now encrypt content key according to each RecipientInfo type */
++     ec = cms->d.envelopedData->encryptedContentInfo;
++     ret = cms_EncryptedContent_init_bio(ec);
+-    rinfos = cms->d.envelopedData->recipientInfos;
++     /* If error or no cipher end of processing */
+-    for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) {
+-        ri = sk_CMS_RecipientInfo_value(rinfos, i);
+-        if (CMS_RecipientInfo_encrypt(cms, ri) <= 0) {
+-            CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
+-                   CMS_R_ERROR_SETTING_RECIPIENTINFO);
+-            goto err;
+-        }
+-    }
+-    cms_env_set_version(cms->d.envelopedData);
++     if (!ret)
++          return ret;
+-    ok = 1;
++     /* Now encrypt content key according to each RecipientInfo type */
+- err:
+-    ec->cipher = NULL;
+-    OPENSSL_clear_free(ec->key, ec->keylen);
+-    ec->key = NULL;
+-    ec->keylen = 0;
+-    if (ok)
+-        return ret;
+-    BIO_free(ret);
+-    return NULL;
++     rinfos = cms->d.envelopedData->recipientInfos;
++     for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) {
++          ri = sk_CMS_RecipientInfo_value(rinfos, i);
++          if (CMS_RecipientInfo_encrypt(cms, ri) <= 0) {
++               CMSerr(CMS_F_CMS_ENVELOPEDDATA_ENCRYPTION_INIT_BIO,
++                    CMS_R_ERROR_SETTING_RECIPIENTINFO);
++               goto err;
++          }
++     }
++     cms_env_set_version(cms->d.envelopedData); /* FIXME move lower? */
++
++     ok = 1;
++
++err:
++     ec->cipher = NULL;
++     OPENSSL_clear_free(ec->key, ec->keylen);
++     ec->key = NULL;
++     ec->keylen = 0;
++     if (ok)
++          return ret;
++     BIO_free(ret);
++     return NULL;
++
+ }
++BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
++{
++     if (cms->d.envelopedData->encryptedContentInfo->cipher)
++     {
++          //If cipher is set it's encrypting
++          return cms_EnvelopedData_Encryption_init_bio(cms);
++     }
++
++     //If cipher is not set it's decrypting
++     return cms_EnvelopedData_Decryption_init_bio(cms);
++}
++
+ /*
+  * Get RecipientInfo type (if any) supported by a key (public or private). To
+  * retain compatibility with previous behaviour if the ctrl value isn't
+@@ -917,3 +996,25 @@
+     }
+     return CMS_RECIPINFO_TRANS;
+ }
++
++int cms_pkey_is_ri_type_supported(EVP_PKEY *pk, int ri_type)
++{
++     if (pk->ameth && pk->ameth->pkey_ctrl)
++     {
++          int i, r;
++          i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_IS_RI_TYPE_SUPPORTED, ri_type, &r);
++          if (i > 0)
++               return r;
++     }
++
++     //if ASN1_PKEY_CTRL_CMS_IS_RI_TYPE_SUPPORTED not supported
++
++     int supportedRiType = cms_pkey_get_ri_type(pk);
++
++     if (supportedRiType < 0)
++     {
++          return 0;
++     }
++
++     return (supportedRiType == ri_type);
++}
+Index: crypto/cms/cms_err.c
+===================================================================
+--- crypto/cms/cms_err.c       (revision 14523)
++++ crypto/cms/cms_err.c       (working copy)
+@@ -22,6 +22,7 @@
+      "CMS_add0_recipient_password"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ADD1_RECEIPTREQUEST, 0),
+      "CMS_add1_ReceiptRequest"},
++    {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ADD1_RECIPIENT, 0), "CMS_add1_recipient"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ADD1_RECIPIENT_CERT, 0),
+      "CMS_add1_recipient_cert"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ADD1_SIGNER, 0), "CMS_add1_signer"},
+@@ -45,6 +46,8 @@
+      "CMS_decrypt_set1_password"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_DECRYPT_SET1_PKEY, 0),
+      "CMS_decrypt_set1_pkey"},
++    {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER, 0),
++     "CMS_decrypt_set1_pkey_and_peer"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_DIGESTALGORITHM_FIND_CTX, 0),
+      "cms_DigestAlgorithm_find_ctx"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_DIGESTALGORITHM_INIT_BIO, 0),
+@@ -66,6 +69,12 @@
+      "CMS_EncryptedData_set1_key"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ENVELOPEDDATA_CREATE, 0),
+      "CMS_EnvelopedData_create"},
++    {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ENVELOPEDDATA_DECRYPTION_INIT_BIO, 0),
++     "cms_EnvelopedData_Decryption_init_bio"},
++    {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ENVELOPEDDATA_ENCRYPTION_INIT_BIO, 0),
++     "cms_EnvelopedData_Encryption_init_bio"},
++    {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ENVELOPEDDATA_FINAL, 0),
++     "cms_EnvelopedData_final"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ENVELOPEDDATA_INIT_BIO, 0),
+      "cms_EnvelopedData_init_bio"},
+     {ERR_PACK(ERR_LIB_CMS, CMS_F_CMS_ENVELOPED_DATA_INIT, 0),
+Index: crypto/x509v3/standard_exts.h
+===================================================================
+--- crypto/x509v3/standard_exts.h      (revision 14523)
++++ crypto/x509v3/standard_exts.h      (working copy)
+@@ -68,6 +68,8 @@
+     &v3_ct_scts[1],
+     &v3_ct_scts[2],
+ #endif
++    &v3_subject_sign_tool,
++    &v3_issuer_sign_tool,
+     &v3_tls_feature,
+     &v3_ext_admission
+ };
+Index: crypto/x509v3/v3err.c
+===================================================================
+--- crypto/x509v3/v3err.c      (revision 14523)
++++ crypto/x509v3/v3err.c      (working copy)
+@@ -1,6 +1,6 @@
+ /*
+  * Generated by util/mkerr.pl DO NOT EDIT
+- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
++ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+  *
+  * Licensed under the OpenSSL license (the "License").  You may not use
+  * this file except in compliance with the License.  You can obtain a copy
+@@ -37,6 +37,8 @@
+      "i2s_ASN1_IA5STRING"},
+     {ERR_PACK(ERR_LIB_X509V3, X509V3_F_I2S_ASN1_INTEGER, 0),
+      "i2s_ASN1_INTEGER"},
++    {ERR_PACK(ERR_LIB_X509V3, X509V3_F_I2S_ASN1_UTF8STRING, 0),
++     "i2s_ASN1_UTF8STRING"},
+     {ERR_PACK(ERR_LIB_X509V3, X509V3_F_I2V_AUTHORITY_INFO_ACCESS, 0),
+      "i2v_AUTHORITY_INFO_ACCESS"},
+     {ERR_PACK(ERR_LIB_X509V3, X509V3_F_LEVEL_ADD_NODE, 0), "level_add_node"},
+@@ -58,6 +60,8 @@
+      "s2i_ASN1_INTEGER"},
+     {ERR_PACK(ERR_LIB_X509V3, X509V3_F_S2I_ASN1_OCTET_STRING, 0),
+      "s2i_ASN1_OCTET_STRING"},
++    {ERR_PACK(ERR_LIB_X509V3, X509V3_F_S2I_ASN1_UTF8STRING, 0),
++     "s2i_ASN1_UTF8STRING"},
+     {ERR_PACK(ERR_LIB_X509V3, X509V3_F_S2I_SKEY_ID, 0), "s2i_skey_id"},
+     {ERR_PACK(ERR_LIB_X509V3, X509V3_F_SET_DIST_POINT_NAME, 0),
+      "set_dist_point_name"},
+Index: crypto/x509v3/build.info
+===================================================================
+--- crypto/x509v3/build.info   (revision 14523)
++++ crypto/x509v3/build.info   (working copy)
+@@ -5,4 +5,4 @@
+   v3_int.c v3_enum.c v3_sxnet.c v3_cpols.c v3_crld.c v3_purp.c v3_info.c \
+   v3_akeya.c v3_pmaps.c v3_pcons.c v3_ncons.c v3_pcia.c v3_pci.c \
+   pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \
+-  v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c
++  v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c v3_rus.c
+Index: crypto/x509v3/v3_alt.c
+===================================================================
+--- crypto/x509v3/v3_alt.c     (revision 14523)
++++ crypto/x509v3/v3_alt.c     (working copy)
+@@ -24,13 +24,46 @@
+ static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx);
+ static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx);
++static int i2r_GENERAL_NAMES(X509V3_EXT_METHOD *method,
++                                        GENERAL_NAMES *gens, BIO *out,
++                                        int indent);
++
++static int GENERAL_NAME_oneline_ex(char *name, GENERAL_NAME *gen, int len)
++{
++      int i;
++      BIO *mem = NULL;
++      BUF_MEM *bptr;
++
++      mem = BIO_new(BIO_s_mem());
++      if (mem == 0)
++              return 0;
++
++      switch (gen->type) {
++              case GEN_DIRNAME:
++                      X509_NAME_print_ex(mem, gen->d.dirn, 0, XN_FLAG_SEP_COMMA_PLUS | ASN1_STRFLGS_UTF8_CONVERT);
++                      break;
++      }
++
++      BIO_get_mem_ptr(mem, &bptr);
++      i = BIO_set_close(mem, BIO_NOCLOSE);
++      BIO_free(mem); 
++      if (i<=0) 
++              return 0;
++
++      if(bptr->length < len)
++              strncpy(name, bptr->data, bptr->length);
++      else
++              strncpy(name, bptr->data, len);
++      return 1;
++}
++
+ const X509V3_EXT_METHOD v3_alt[3] = {
+     {NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+      0, 0, 0, 0,
+      0, 0,
+-     (X509V3_EXT_I2V) i2v_GENERAL_NAMES,
++     NULL, /* (X509V3_EXT_I2V) i2v_GENERAL_NAMES, */
+      (X509V3_EXT_V2I)v2i_subject_alt,
+-     NULL, NULL, NULL},
++     (X509V3_EXT_I2R)i2r_GENERAL_NAMES, NULL, NULL},
+     {NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+      0, 0, 0, 0,
+@@ -37,13 +70,13 @@
+      0, 0,
+      (X509V3_EXT_I2V) i2v_GENERAL_NAMES,
+      (X509V3_EXT_V2I)v2i_issuer_alt,
+-     NULL, NULL, NULL},
++     (X509V3_EXT_I2R)i2r_GENERAL_NAMES/*NULL*/, NULL, NULL},
+     {NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+      0, 0, 0, 0,
+      0, 0,
+      (X509V3_EXT_I2V) i2v_GENERAL_NAMES,
+-     NULL, NULL, NULL, NULL},
++     NULL, (X509V3_EXT_I2R)i2r_GENERAL_NAMES/*NULL*/, NULL, NULL},
+ };
+ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
+@@ -79,7 +112,7 @@
+                                        STACK_OF(CONF_VALUE) *ret)
+ {
+     unsigned char *p;
+-    char oline[256], htmp[5];
++    char oline[1024], htmp[5];
+     int i;
+     switch (gen->type) {
+@@ -114,7 +147,7 @@
+         break;
+     case GEN_DIRNAME:
+-        if (X509_NAME_oneline(gen->d.dirn, oline, sizeof(oline)) == NULL
++        if (GENERAL_NAME_oneline_ex(oline, gen, sizeof(oline)) <= 0
+                 || !X509V3_add_value("DirName", oline, &ret))
+             return NULL;
+         break;
+@@ -151,6 +184,96 @@
+     return ret;
+ }
++/* beldmit */
++int i2r_GENERAL_NAME(X509V3_EXT_METHOD *method,
++                                       GENERAL_NAME *gen, BIO *out,
++                                       int indent)
++{
++    unsigned char *p;
++    char oline[256], htmp[5];
++    int i;
++              BIO_printf(out, "%*s", indent, "");
++    switch (gen->type) {
++    case GEN_OTHERNAME:
++        BIO_write(out, "othername: <unsupported>", 24);
++        break;
++
++    case GEN_X400:
++        BIO_write(out, "X400Name: <unsupported>", 24);
++        break;
++
++    case GEN_EDIPARTY:
++        BIO_write(out, "EdiPartyName: <unsupported>", 28);
++        break;
++
++    case GEN_EMAIL:
++        BIO_write(out, "email: ", 7); 
++                              BIO_write(out, gen->d.ia5->data, gen->d.ia5->length);
++        break;
++
++    case GEN_DNS:
++        BIO_write(out, "DNS: ", 5);
++                              BIO_write(out, gen->d.ia5->data, gen->d.ia5->length);
++        break;
++
++    case GEN_URI:
++        BIO_write(out, "URI: ", 5);
++                              BIO_write(out, gen->d.ia5->data, gen->d.ia5->length);
++        break;
++
++    case GEN_DIRNAME:
++        BIO_write(out, "DirName: ", 9); 
++                              X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_SEP_COMMA_PLUS|ASN1_STRFLGS_UTF8_CONVERT);
++        break;
++
++    case GEN_IPADD:
++        p = gen->d.ip->data;
++        if (gen->d.ip->length == 4)
++            BIO_snprintf(oline, sizeof oline,
++                         "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
++        else if (gen->d.ip->length == 16) {
++            oline[0] = 0;
++            for (i = 0; i < 8; i++) {
++                BIO_snprintf(htmp, sizeof htmp, "%X", p[0] << 8 | p[1]);
++                p += 2;
++                strcat(oline, htmp);
++                if (i != 7)
++                    strcat(oline, ":");
++            }
++        } else {
++            BIO_write(out, "IP Address: <invalid>", 22);
++            break;
++        }
++        BIO_write(out, "IP Address: ", 12);
++                              BIO_write(out, oline, strlen(oline));
++        break;
++
++    case GEN_RID:
++        i2t_ASN1_OBJECT(oline, 256, gen->d.rid);
++        BIO_write(out, "Registered ID: ", 15);
++                              BIO_write(out, oline, strlen(oline));
++        break;
++    }
++              BIO_write(out, "\n", 1);
++    return 1;
++}
++
++int i2r_GENERAL_NAMES(X509V3_EXT_METHOD *method,
++                                        GENERAL_NAMES *gens, BIO *out,
++                                        int indent)
++{
++    int i;
++    GENERAL_NAME *gen;
++    for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
++        gen = sk_GENERAL_NAME_value(gens, i);
++        if (!i2r_GENERAL_NAME(method, gen, out, indent))
++                                      return 0;
++    }
++    return 1;
++}
++
++/* beldmit */
++
+ int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
+ {
+     unsigned char *p;
+Index: crypto/x509v3/ext_dat.h
+===================================================================
+--- crypto/x509v3/ext_dat.h    (revision 14523)
++++ crypto/x509v3/ext_dat.h    (working copy)
+@@ -21,5 +21,6 @@
+ extern const X509V3_EXT_METHOD v3_name_constraints, v3_inhibit_anyp, v3_idp;
+ extern const X509V3_EXT_METHOD v3_addr, v3_asid;
+ extern const X509V3_EXT_METHOD v3_ct_scts[3];
++extern const X509V3_EXT_METHOD v3_subject_sign_tool, v3_issuer_sign_tool;
+ extern const X509V3_EXT_METHOD v3_tls_feature;
+ extern const X509V3_EXT_METHOD v3_ext_admission;
+Index: crypto/x509v3/v3_rus.c
+===================================================================
+--- crypto/x509v3/v3_rus.c     (nonexistent)
++++ crypto/x509v3/v3_rus.c     (revision 14744)
+@@ -0,0 +1,168 @@
++/* v3_rus.c */
++/*
++ * Written by Dmitry Belyavskiy for the OpenSSL project
++ * 2015.
++ */
++/* ====================================================================
++ * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ *
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in
++ *    the documentation and/or other materials provided with the
++ *    distribution.
++ *
++ * 3. All advertising materials mentioning features or use of this
++ *    software must display the following acknowledgment:
++ *    "This product includes software developed by the OpenSSL Project
++ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
++ *
++ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
++ *    endorse or promote products derived from this software without
++ *    prior written permission. For written permission, please contact
++ *    licensing@OpenSSL.org.
++ *
++ * 5. Products derived from this software may not be called "OpenSSL"
++ *    nor may "OpenSSL" appear in their names without prior written
++ *    permission of the OpenSSL Project.
++ *
++ * 6. Redistributions of any form whatsoever must retain the following
++ *    acknowledgment:
++ *    "This product includes software developed by the OpenSSL Project
++ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
++ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
++ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ * ====================================================================
++ *
++ * This product includes cryptographic software written by Eric Young
++ * (eay@cryptsoft.com).  This product includes software written by Tim
++ * Hudson (tjh@cryptsoft.com).
++ *
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <openssl/asn1t.h>
++#include <openssl/err.h>
++#include <openssl/x509v3.h>
++
++static char *i2s_ASN1_UTF8STRING(const X509V3_EXT_METHOD *method,
++                                ASN1_UTF8STRING *utf8str)
++{
++    char *tmp;
++    if (!utf8str || !utf8str->length)
++        return NULL;
++    if (!(tmp = OPENSSL_malloc(utf8str->length + 1))) {
++        X509V3err(X509V3_F_I2S_ASN1_UTF8STRING, ERR_R_MALLOC_FAILURE);
++        return NULL;
++    }
++    memcpy(tmp, utf8str->data, utf8str->length);
++    tmp[utf8str->length] = 0;
++    return tmp;
++}
++
++static ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
++                                          X509V3_CTX *ctx, char *str)
++{
++    ASN1_UTF8STRING *utf8str;
++    if (!str) {
++        X509V3err(X509V3_F_S2I_ASN1_UTF8STRING,
++                  X509V3_R_INVALID_NULL_ARGUMENT);
++        return NULL;
++    }
++    if (!(utf8str = ASN1_STRING_type_new(V_ASN1_UTF8STRING)))
++        goto err;
++    if (!ASN1_STRING_set((ASN1_STRING *)utf8str, (unsigned char *)str,
++                         strlen(str))) {
++        ASN1_STRING_free(utf8str);
++        goto err;
++    }
++#ifdef CHARSET_EBCDIC
++    ebcdic2ascii(utf8str->data, utf8str->data, utf8str->length);
++#endif                          /* CHARSET_EBCDIC */
++    return utf8str;
++ err:
++    X509V3err(X509V3_F_S2I_ASN1_UTF8STRING, ERR_R_MALLOC_FAILURE);
++    return NULL;
++}
++
++const X509V3_EXT_METHOD v3_subject_sign_tool = {
++    NID_subjectSignTool, 0, ASN1_ITEM_ref(ASN1_UTF8STRING),
++    0, 0, 0, 0,
++    (X509V3_EXT_I2S)i2s_ASN1_UTF8STRING,
++    (X509V3_EXT_S2I)s2i_ASN1_UTF8STRING,
++    0, 0, 0, 0, NULL
++};
++
++typedef struct ISSUER_SIGN_TOOL_st {
++    ASN1_UTF8STRING *signTool;
++    ASN1_UTF8STRING *cATool;
++    ASN1_UTF8STRING *signToolCert;
++    ASN1_UTF8STRING *cAToolCert;
++} ISSUER_SIGN_TOOL;
++
++ASN1_SEQUENCE(ISSUER_SIGN_TOOL) = {
++        ASN1_SIMPLE(ISSUER_SIGN_TOOL, signTool, ASN1_UTF8STRING),
++        ASN1_SIMPLE(ISSUER_SIGN_TOOL, cATool, ASN1_UTF8STRING),
++        ASN1_SIMPLE(ISSUER_SIGN_TOOL, signToolCert, ASN1_UTF8STRING),
++        ASN1_SIMPLE(ISSUER_SIGN_TOOL, cAToolCert, ASN1_UTF8STRING)
++} ASN1_SEQUENCE_END(ISSUER_SIGN_TOOL)
++
++IMPLEMENT_ASN1_FUNCTIONS(ISSUER_SIGN_TOOL)
++
++static int i2r_ISSUER_SIGN_TOOL(X509V3_EXT_METHOD *method,
++                                 ISSUER_SIGN_TOOL *ist, BIO *out,
++                                 int indent)
++{
++    if (ist->signTool) {
++              BIO_printf(out, "%*s", indent, "");
++        BIO_write(out, "signTool:     ", 14);
++                              BIO_write(out, ist->signTool->data, ist->signTool->length);
++                              BIO_write(out, "\n", 1);
++    }
++    if (ist->cATool) {
++              BIO_printf(out, "%*s", indent, "");
++        BIO_write(out, "cATool:       ", 14);
++                              BIO_write(out, ist->cATool->data, ist->cATool->length);
++                              BIO_write(out, "\n", 1);
++    }
++    if (ist->signToolCert) {
++              BIO_printf(out, "%*s", indent, "");
++        BIO_write(out, "signToolCert: ", 14);
++                              BIO_write(out, ist->signToolCert->data, ist->signToolCert->length);
++                              BIO_write(out, "\n", 1);
++    }
++    if (ist->cAToolCert) {
++              BIO_printf(out, "%*s", indent, "");
++        BIO_write(out, "cAToolCert:   ", 14);
++                              BIO_write(out, ist->cAToolCert->data, ist->cAToolCert->length);
++                              BIO_write(out, "\n", 1);
++    }
++    return 1;
++}
++
++const X509V3_EXT_METHOD v3_issuer_sign_tool = {
++    NID_issuerSignTool, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(ISSUER_SIGN_TOOL),
++    0, 0, 0, 0,
++              0, 0,
++    0, /*(X509V3_EXT_I2V)i2v_ISSUER_SIGN_TOOL,*/
++    0,
++    (X509V3_EXT_I2R)i2r_ISSUER_SIGN_TOOL, 0, NULL
++};
+Index: crypto/err/openssl.txt
+===================================================================
+--- crypto/err/openssl.txt     (revision 14523)
++++ crypto/err/openssl.txt     (working copy)
+@@ -239,6 +239,7 @@
+ CMS_F_CMS_ADD0_RECIPIENT_KEY:100:CMS_add0_recipient_key
+ CMS_F_CMS_ADD0_RECIPIENT_PASSWORD:165:CMS_add0_recipient_password
+ CMS_F_CMS_ADD1_RECEIPTREQUEST:158:CMS_add1_ReceiptRequest
++CMS_F_CMS_ADD1_RECIPIENT:181:CMS_add1_recipient
+ CMS_F_CMS_ADD1_RECIPIENT_CERT:101:CMS_add1_recipient_cert
+ CMS_F_CMS_ADD1_SIGNER:102:CMS_add1_signer
+ CMS_F_CMS_ADD1_SIGNINGTIME:103:cms_add1_signingTime
+@@ -254,6 +255,7 @@
+ CMS_F_CMS_DECRYPT_SET1_KEY:113:CMS_decrypt_set1_key
+ CMS_F_CMS_DECRYPT_SET1_PASSWORD:166:CMS_decrypt_set1_password
+ CMS_F_CMS_DECRYPT_SET1_PKEY:114:CMS_decrypt_set1_pkey
++CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER:182:CMS_decrypt_set1_pkey_and_peer
+ CMS_F_CMS_DIGESTALGORITHM_FIND_CTX:115:cms_DigestAlgorithm_find_ctx
+ CMS_F_CMS_DIGESTALGORITHM_INIT_BIO:116:cms_DigestAlgorithm_init_bio
+ CMS_F_CMS_DIGESTEDDATA_DO_FINAL:117:cms_DigestedData_do_final
+@@ -266,6 +268,11 @@
+ CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT:122:CMS_EncryptedData_encrypt
+ CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY:123:CMS_EncryptedData_set1_key
+ CMS_F_CMS_ENVELOPEDDATA_CREATE:124:CMS_EnvelopedData_create
++CMS_F_CMS_ENVELOPEDDATA_DECRYPTION_INIT_BIO:184:\
++      cms_EnvelopedData_Decryption_init_bio
++CMS_F_CMS_ENVELOPEDDATA_ENCRYPTION_INIT_BIO:185:\
++      cms_EnvelopedData_Encryption_init_bio
++CMS_F_CMS_ENVELOPEDDATA_FINAL:186:cms_EnvelopedData_final
+ CMS_F_CMS_ENVELOPEDDATA_INIT_BIO:125:cms_EnvelopedData_init_bio
+ CMS_F_CMS_ENVELOPED_DATA_INIT:126:cms_enveloped_data_init
+ CMS_F_CMS_ENV_ASN1_CTRL:171:cms_env_asn1_ctrl
+@@ -1180,7 +1187,7 @@
+ SSL_F_OSSL_STATEM_SERVER_POST_PROCESS_MESSAGE:601:\
+       ossl_statem_server_post_process_message
+ SSL_F_OSSL_STATEM_SERVER_POST_WORK:602:ossl_statem_server_post_work
+-SSL_F_OSSL_STATEM_SERVER_PRE_WORK:640:
++SSL_F_OSSL_STATEM_SERVER_PRE_WORK:640:ossl_statem_server_pre_work
+ SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE:603:ossl_statem_server_process_message
+ SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION:418:ossl_statem_server_read_transition
+ SSL_F_OSSL_STATEM_SERVER_WRITE_TRANSITION:604:\
+@@ -1395,6 +1402,7 @@
+ SSL_F_TLS_CONSTRUCT_CKE_DHE:404:tls_construct_cke_dhe
+ SSL_F_TLS_CONSTRUCT_CKE_ECDHE:405:tls_construct_cke_ecdhe
+ SSL_F_TLS_CONSTRUCT_CKE_GOST:406:tls_construct_cke_gost
++SSL_F_TLS_CONSTRUCT_CKE_GOST18:639:tls_construct_cke_gost18
+ SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE:407:tls_construct_cke_psk_preamble
+ SSL_F_TLS_CONSTRUCT_CKE_RSA:409:tls_construct_cke_rsa
+ SSL_F_TLS_CONSTRUCT_CKE_SRP:410:tls_construct_cke_srp
+@@ -1526,6 +1534,7 @@
+ SSL_F_TLS_PROCESS_CKE_DHE:411:tls_process_cke_dhe
+ SSL_F_TLS_PROCESS_CKE_ECDHE:412:tls_process_cke_ecdhe
+ SSL_F_TLS_PROCESS_CKE_GOST:413:tls_process_cke_gost
++SSL_F_TLS_PROCESS_CKE_GOST18:641:tls_process_cke_gost18
+ SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE:414:tls_process_cke_psk_preamble
+ SSL_F_TLS_PROCESS_CKE_RSA:415:tls_process_cke_rsa
+ SSL_F_TLS_PROCESS_CKE_SRP:416:tls_process_cke_srp
+@@ -1648,6 +1657,7 @@
+ X509V3_F_I2S_ASN1_ENUMERATED:121:i2s_ASN1_ENUMERATED
+ X509V3_F_I2S_ASN1_IA5STRING:149:i2s_ASN1_IA5STRING
+ X509V3_F_I2S_ASN1_INTEGER:120:i2s_ASN1_INTEGER
++X509V3_F_I2S_ASN1_UTF8STRING:173:i2s_ASN1_UTF8STRING
+ X509V3_F_I2V_AUTHORITY_INFO_ACCESS:138:i2v_AUTHORITY_INFO_ACCESS
+ X509V3_F_LEVEL_ADD_NODE:168:level_add_node
+ X509V3_F_NOTICE_SECTION:132:notice_section
+@@ -1662,6 +1672,7 @@
+ X509V3_F_S2I_ASN1_IA5STRING:100:s2i_ASN1_IA5STRING
+ X509V3_F_S2I_ASN1_INTEGER:108:s2i_ASN1_INTEGER
+ X509V3_F_S2I_ASN1_OCTET_STRING:112:s2i_ASN1_OCTET_STRING
++X509V3_F_S2I_ASN1_UTF8STRING:174:s2i_ASN1_UTF8STRING
+ X509V3_F_S2I_SKEY_ID:115:s2i_skey_id
+ X509V3_F_SET_DIST_POINT_NAME:158:set_dist_point_name
+ X509V3_F_SXNET_ADD_ID_ASC:125:SXNET_add_id_asc
+Index: crypto/asn1/p8_pkey.c
+===================================================================
+--- crypto/asn1/p8_pkey.c      (revision 14523)
++++ crypto/asn1/p8_pkey.c      (working copy)
+@@ -78,3 +78,18 @@
+         return 1;
+     return 0;
+ }
++
++int PKCS8_pkey_add1_attr_by_OBJ(PKCS8_PRIV_KEY_INFO *p8, const ASN1_OBJECT *obj, int type,
++                                const unsigned char *bytes, int len)
++{
++    if (X509at_add1_attr_by_OBJ(&p8->attributes, obj, type, bytes, len) != NULL)
++        return 1;
++    return 0;
++}
++
++int PKCS8_pkey_add1_attr(PKCS8_PRIV_KEY_INFO *p8, X509_ATTRIBUTE *attr)
++{
++    if (X509at_add1_attr(&p8->attributes, attr) != NULL)
++        return 1;
++    return 0;
++}
+Index: include/openssl/sslerr.h
+===================================================================
+--- include/openssl/sslerr.h   (revision 14523)
++++ include/openssl/sslerr.h   (working copy)
+@@ -11,9 +11,7 @@
+ #ifndef HEADER_SSLERR_H
+ # define HEADER_SSLERR_H
+-# ifndef HEADER_SYMHACKS_H
+-#  include <openssl/symhacks.h>
+-# endif
++# include <openssl/symhacks.h>
+ # ifdef  __cplusplus
+ extern "C"
+@@ -296,6 +294,7 @@
+ # define SSL_F_TLS_CONSTRUCT_CKE_DHE                      404
+ # define SSL_F_TLS_CONSTRUCT_CKE_ECDHE                    405
+ # define SSL_F_TLS_CONSTRUCT_CKE_GOST                     406
++# define SSL_F_TLS_CONSTRUCT_CKE_GOST18                   639
+ # define SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE             407
+ # define SSL_F_TLS_CONSTRUCT_CKE_RSA                      409
+ # define SSL_F_TLS_CONSTRUCT_CKE_SRP                      410
+@@ -420,6 +419,7 @@
+ # define SSL_F_TLS_PROCESS_CKE_DHE                        411
+ # define SSL_F_TLS_PROCESS_CKE_ECDHE                      412
+ # define SSL_F_TLS_PROCESS_CKE_GOST                       413
++# define SSL_F_TLS_PROCESS_CKE_GOST18                     641
+ # define SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE               414
+ # define SSL_F_TLS_PROCESS_CKE_RSA                        415
+ # define SSL_F_TLS_PROCESS_CKE_SRP                        416
+Index: include/openssl/x509.h
+===================================================================
+--- include/openssl/x509.h     (revision 14523)
++++ include/openssl/x509.h     (working copy)
+@@ -1020,8 +1020,11 @@
+ const STACK_OF(X509_ATTRIBUTE) *
+ PKCS8_pkey_get0_attrs(const PKCS8_PRIV_KEY_INFO *p8);
++int PKCS8_pkey_add1_attr(PKCS8_PRIV_KEY_INFO *p8, X509_ATTRIBUTE *attr);
+ int PKCS8_pkey_add1_attr_by_NID(PKCS8_PRIV_KEY_INFO *p8, int nid, int type,
+                                 const unsigned char *bytes, int len);
++int PKCS8_pkey_add1_attr_by_OBJ(PKCS8_PRIV_KEY_INFO *p8, const ASN1_OBJECT *obj,
++                                int type, const unsigned char *bytes, int len);
+ int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj,
+                            int ptype, void *pval,
+Index: include/openssl/cms.h
+===================================================================
+--- include/openssl/cms.h      (revision 14523)
++++ include/openssl/cms.h      (working copy)
+@@ -73,6 +73,7 @@
+ # define CMS_DEBUG_DECRYPT               0x20000
+ # define CMS_KEY_PARAM                   0x40000
+ # define CMS_ASCIICRLF                   0x80000
++# define CMS_USE_ORIGINATOR_KEYID        0x100000
+ const ASN1_OBJECT *CMS_get0_type(const CMS_ContentInfo *cms);
+@@ -143,6 +144,7 @@
+                 BIO *dcont, BIO *out, unsigned int flags);
+ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert);
++int CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert, X509 *peer);
+ int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
+                          unsigned char *key, size_t keylen,
+                          const unsigned char *id, size_t idlen);
+@@ -155,6 +157,8 @@
+ CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
+ CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
+                                            X509 *recip, unsigned int flags);
++CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip, 
++     EVP_PKEY *originatorPrivKey, X509 * originator, unsigned int flags);
+ int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey);
+ int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert);
+ int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
+@@ -319,6 +323,7 @@
+ int CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek,
+                                        X509 *cert);
+ int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk);
++int CMS_RecipientInfo_kari_set0_pkey_and_peer(CMS_RecipientInfo *ri, EVP_PKEY *pk, X509 *peer);
+ EVP_CIPHER_CTX *CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri);
+ int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms,
+                                    CMS_RecipientInfo *ri,
+Index: include/openssl/tls1.h
+===================================================================
+--- include/openssl/tls1.h     (revision 14523)
++++ include/openssl/tls1.h     (working copy)
+@@ -613,6 +613,12 @@
+ # define TLS1_3_CK_AES_128_CCM_SHA256                     0x03001304
+ # define TLS1_3_CK_AES_128_CCM_8_SHA256                   0x03001305
++/* https://tools.ietf.org/html/draft-smyshlyaev-tls13-gost-suites */
++# define TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L        0x0300C103
++# define TLS_GOSTR341112_256_WITH_MAGMA_MGM_L             0x0300C104
++# define TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S        0x0300C105
++# define TLS_GOSTR341112_256_WITH_MAGMA_MGM_S             0x0300C106
++
+ /* Aria ciphersuites from RFC6209 */
+ # define TLS1_CK_RSA_WITH_ARIA_128_GCM_SHA256             0x0300C050
+ # define TLS1_CK_RSA_WITH_ARIA_256_GCM_SHA384             0x0300C051
+@@ -1135,8 +1141,10 @@
+ # define TLS_CT_RSA_FIXED_ECDH           65
+ # define TLS_CT_ECDSA_FIXED_ECDH         66
+ # define TLS_CT_GOST01_SIGN              22
+-# define TLS_CT_GOST12_SIGN              238
+-# define TLS_CT_GOST12_512_SIGN          239
++# define TLS_CT_GOST12_SIGN              67 
++# define TLS_CT_GOST12_512_SIGN          68
++# define TLS_CT_GOST12_SIGN_LEGACY       238
++# define TLS_CT_GOST12_512_SIGN_LEGACY   239
+ /*
+  * when correcting this number, correct also SSL3_CT_NUMBER in ssl3.h (see
+Index: include/openssl/ssl.h
+===================================================================
+--- include/openssl/ssl.h      (revision 14523)
++++ include/openssl/ssl.h      (working copy)
+@@ -81,6 +81,7 @@
+ # define SSL_TXT_kECDHEPSK       "kECDHEPSK"
+ # define SSL_TXT_kDHEPSK         "kDHEPSK"
+ # define SSL_TXT_kGOST           "kGOST"
++# define SSL_TXT_kGOST18         "kGOST18"
+ # define SSL_TXT_kSRP            "kSRP"
+ # define SSL_TXT_aRSA            "aRSA"
+@@ -908,6 +909,8 @@
+ # define SSL_MAC_FLAG_READ_MAC_STREAM 1
+ # define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
++# define SSL_MAC_FLAG_READ_MAC_TLSTREE 4
++# define SSL_MAC_FLAG_WRITE_MAC_TLSTREE 8
+ /*
+  * A callback for logging out TLS key material. This callback should log out
+Index: include/openssl/obj_mac.h
+===================================================================
+--- include/openssl/obj_mac.h  (revision 14523)
++++ include/openssl/obj_mac.h  (working copy)
+@@ -4162,6 +4162,26 @@
+ #define NID_id_GostR3410_2001_ParamSet_cc               854
+ #define OBJ_id_GostR3410_2001_ParamSet_cc               OBJ_cryptocom,1L,8L,1L
++#define SN_id_tc26_modules              "id-tc26-modules"
++#define LN_id_tc26_modules              "GOST TC26 ASN.1 modules"
++#define NID_id_tc26_modules             1203
++#define OBJ_id_tc26_modules             OBJ_id_tc26,0L
++
++#define SN_id_tc26_cms          "id-tc26-cms"
++#define LN_id_tc26_cms          "GOST TC26 SMS"
++#define NID_id_tc26_cms         1204
++#define OBJ_id_tc26_cms         OBJ_id_tc26_modules,6L
++
++#define SN_id_tc26_cms_attrs            "id-tc26-cms-attrs"
++#define LN_id_tc26_cms_attrs            "GOST TC26 SMS attributes"
++#define NID_id_tc26_cms_attrs           1205
++#define OBJ_id_tc26_cms_attrs           OBJ_id_tc26_cms,1L
++
++#define SN_id_tc26_mac_attr             "id-tc26-mac-attr"
++#define LN_id_tc26_mac_attr             "GOST TC26 SMS content-mac attribute"
++#define NID_id_tc26_mac_attr            1206
++#define OBJ_id_tc26_mac_attr            OBJ_id_tc26_cms_attrs,1L
++
+ #define SN_id_tc26_algorithms           "id-tc26-algorithms"
+ #define NID_id_tc26_algorithms          977
+ #define OBJ_id_tc26_algorithms          OBJ_id_tc26,1L
+@@ -4230,25 +4250,25 @@
+ #define NID_id_tc26_cipher_gostr3412_2015_magma         1173
+ #define OBJ_id_tc26_cipher_gostr3412_2015_magma         OBJ_id_tc26_cipher,1L
+-#define SN_id_tc26_cipher_gostr3412_2015_magma_ctracpkm         "id-tc26-cipher-gostr3412-2015-magma-ctracpkm"
+-#define NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm                1174
+-#define OBJ_id_tc26_cipher_gostr3412_2015_magma_ctracpkm                OBJ_id_tc26_cipher_gostr3412_2015_magma,1L
++#define SN_magma_ctr_acpkm              "magma-ctr-acpkm"
++#define NID_magma_ctr_acpkm             1174
++#define OBJ_magma_ctr_acpkm             OBJ_id_tc26_cipher_gostr3412_2015_magma,1L
+-#define SN_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac            "id-tc26-cipher-gostr3412-2015-magma-ctracpkm-omac"
+-#define NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac           1175
+-#define OBJ_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac           OBJ_id_tc26_cipher_gostr3412_2015_magma,2L
++#define SN_magma_ctr_acpkm_omac         "magma-ctr-acpkm-omac"
++#define NID_magma_ctr_acpkm_omac                1175
++#define OBJ_magma_ctr_acpkm_omac                OBJ_id_tc26_cipher_gostr3412_2015_magma,2L
+ #define SN_id_tc26_cipher_gostr3412_2015_kuznyechik             "id-tc26-cipher-gostr3412-2015-kuznyechik"
+ #define NID_id_tc26_cipher_gostr3412_2015_kuznyechik            1176
+ #define OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik            OBJ_id_tc26_cipher,2L
+-#define SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm            "id-tc26-cipher-gostr3412-2015-kuznyechik-ctracpkm"
+-#define NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm           1177
+-#define OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm           OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik,1L
++#define SN_kuznyechik_ctr_acpkm         "kuznyechik-ctr-acpkm"
++#define NID_kuznyechik_ctr_acpkm                1177
++#define OBJ_kuznyechik_ctr_acpkm                OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik,1L
+-#define SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac               "id-tc26-cipher-gostr3412-2015-kuznyechik-ctracpkm-omac"
+-#define NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac              1178
+-#define OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac              OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik,2L
++#define SN_kuznyechik_ctr_acpkm_omac            "kuznyechik-ctr-acpkm-omac"
++#define NID_kuznyechik_ctr_acpkm_omac           1178
++#define OBJ_kuznyechik_ctr_acpkm_omac           OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik,2L
+ #define SN_id_tc26_agreement            "id-tc26-agreement"
+ #define NID_id_tc26_agreement           991
+@@ -4270,17 +4290,17 @@
+ #define NID_id_tc26_wrap_gostr3412_2015_magma           1180
+ #define OBJ_id_tc26_wrap_gostr3412_2015_magma           OBJ_id_tc26_wrap,1L
+-#define SN_id_tc26_wrap_gostr3412_2015_magma_kexp15             "id-tc26-wrap-gostr3412-2015-magma-kexp15"
+-#define NID_id_tc26_wrap_gostr3412_2015_magma_kexp15            1181
+-#define OBJ_id_tc26_wrap_gostr3412_2015_magma_kexp15            OBJ_id_tc26_wrap_gostr3412_2015_magma,1L
++#define SN_magma_kexp15         "magma-kexp15"
++#define NID_magma_kexp15                1181
++#define OBJ_magma_kexp15                OBJ_id_tc26_wrap_gostr3412_2015_magma,1L
+ #define SN_id_tc26_wrap_gostr3412_2015_kuznyechik               "id-tc26-wrap-gostr3412-2015-kuznyechik"
+ #define NID_id_tc26_wrap_gostr3412_2015_kuznyechik              1182
+ #define OBJ_id_tc26_wrap_gostr3412_2015_kuznyechik              OBJ_id_tc26_wrap,2L
+-#define SN_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15                "id-tc26-wrap-gostr3412-2015-kuznyechik-kexp15"
+-#define NID_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15               1183
+-#define OBJ_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15               OBJ_id_tc26_wrap_gostr3412_2015_kuznyechik,1L
++#define SN_kuznyechik_kexp15            "kuznyechik-kexp15"
++#define NID_kuznyechik_kexp15           1183
++#define OBJ_kuznyechik_kexp15           OBJ_id_tc26_wrap_gostr3412_2015_kuznyechik,1L
+ #define SN_id_tc26_constants            "id-tc26-constants"
+ #define NID_id_tc26_constants           994
+@@ -4370,6 +4390,11 @@
+ #define NID_SNILS               1006
+ #define OBJ_SNILS               OBJ_member_body,643L,100L,3L
++#define SN_OGRNIP               "OGRNIP"
++#define LN_OGRNIP               "OGRNIP"
++#define NID_OGRNIP              1195
++#define OBJ_OGRNIP              OBJ_member_body,643L,100L,5L
++
+ #define SN_subjectSignTool              "subjectSignTool"
+ #define LN_subjectSignTool              "Signing Tool of Subject"
+ #define NID_subjectSignTool             1007
+@@ -4380,24 +4405,62 @@
+ #define NID_issuerSignTool              1008
+ #define OBJ_issuerSignTool              OBJ_member_body,643L,100L,112L
+-#define SN_grasshopper_ecb              "grasshopper-ecb"
+-#define NID_grasshopper_ecb             1012
++#define SN_classSignTool                "classSignTool"
++#define LN_classSignTool                "Class of Signing Tool"
++#define NID_classSignTool               1196
++#define OBJ_classSignTool               OBJ_member_body,643L,100L,113L
+-#define SN_grasshopper_ctr              "grasshopper-ctr"
+-#define NID_grasshopper_ctr             1013
++#define SN_classSignToolKC1             "classSignToolKC1"
++#define LN_classSignToolKC1             "Class of Signing Tool KC1"
++#define NID_classSignToolKC1            1197
++#define OBJ_classSignToolKC1            OBJ_member_body,643L,100L,113L,1L
+-#define SN_grasshopper_ofb              "grasshopper-ofb"
+-#define NID_grasshopper_ofb             1014
++#define SN_classSignToolKC2             "classSignToolKC2"
++#define LN_classSignToolKC2             "Class of Signing Tool KC2"
++#define NID_classSignToolKC2            1198
++#define OBJ_classSignToolKC2            OBJ_member_body,643L,100L,113L,2L
+-#define SN_grasshopper_cbc              "grasshopper-cbc"
+-#define NID_grasshopper_cbc             1015
++#define SN_classSignToolKC3             "classSignToolKC3"
++#define LN_classSignToolKC3             "Class of Signing Tool KC3"
++#define NID_classSignToolKC3            1199
++#define OBJ_classSignToolKC3            OBJ_member_body,643L,100L,113L,3L
+-#define SN_grasshopper_cfb              "grasshopper-cfb"
+-#define NID_grasshopper_cfb             1016
++#define SN_classSignToolKB1             "classSignToolKB1"
++#define LN_classSignToolKB1             "Class of Signing Tool KB1"
++#define NID_classSignToolKB1            1200
++#define OBJ_classSignToolKB1            OBJ_member_body,643L,100L,113L,4L
+-#define SN_grasshopper_mac              "grasshopper-mac"
+-#define NID_grasshopper_mac             1017
++#define SN_classSignToolKB2             "classSignToolKB2"
++#define LN_classSignToolKB2             "Class of Signing Tool KB2"
++#define NID_classSignToolKB2            1201
++#define OBJ_classSignToolKB2            OBJ_member_body,643L,100L,113L,5L
++#define SN_classSignToolKA1             "classSignToolKA1"
++#define LN_classSignToolKA1             "Class of Signing Tool KA1"
++#define NID_classSignToolKA1            1202
++#define OBJ_classSignToolKA1            OBJ_member_body,643L,100L,113L,6L
++
++#define SN_kuznyechik_ecb               "kuznyechik-ecb"
++#define NID_kuznyechik_ecb              1012
++
++#define SN_kuznyechik_ctr               "kuznyechik-ctr"
++#define NID_kuznyechik_ctr              1013
++
++#define SN_kuznyechik_ofb               "kuznyechik-ofb"
++#define NID_kuznyechik_ofb              1014
++
++#define SN_kuznyechik_cbc               "kuznyechik-cbc"
++#define NID_kuznyechik_cbc              1015
++
++#define SN_kuznyechik_cfb               "kuznyechik-cfb"
++#define NID_kuznyechik_cfb              1016
++
++#define SN_kuznyechik_mac               "kuznyechik-mac"
++#define NID_kuznyechik_mac              1017
++
++#define SN_kuznyechik_mgm               "kuznyechik-mgm"
++#define NID_kuznyechik_mgm              1207
++
+ #define SN_magma_ecb            "magma-ecb"
+ #define NID_magma_ecb           1187
+@@ -4416,6 +4479,9 @@
+ #define SN_magma_mac            "magma-mac"
+ #define NID_magma_mac           1192
++#define SN_magma_mgm            "magma-mgm"
++#define NID_magma_mgm           1208
++
+ #define SN_camellia_128_cbc             "CAMELLIA-128-CBC"
+ #define LN_camellia_128_cbc             "camellia-128-cbc"
+ #define NID_camellia_128_cbc            751
+@@ -5196,3 +5262,49 @@
+ #define LN_uacurve9             "DSTU curve 9"
+ #define NID_uacurve9            1169
+ #define OBJ_uacurve9            OBJ_dstu4145le,2L,9L
++
++#ifndef OPENSSL_NO_DEPRECATED_3_0
++
++#define SN_id_tc26_cipher_gostr3412_2015_magma_ctracpkm                 SN_magma_ctr_acpkm
++#define NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm                NID_magma_ctr_acpkm
++#define OBJ_id_tc26_cipher_gostr3412_2015_magma_ctracpkm                OBJ_magma_ctr_acpkm
++
++#define SN_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac            SN_magma_ctr_acpkm_omac
++#define NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac           NID_magma_ctr_acpkm_omac
++#define OBJ_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac           OBJ_magma_ctr_acpkm_omac
++
++#define SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm            SN_kuznyechik_ctr_acpkm
++#define NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm           NID_kuznyechik_ctr_acpkm
++#define OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm           OBJ_kuznyechik_ctr_acpkm
++
++#define SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac               SN_kuznyechik_ctr_acpkm_omac
++#define NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac              NID_kuznyechik_ctr_acpkm_omac
++#define OBJ_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac              OBJ_kuznyechik_ctr_acpkm_omac
++
++#define SN_id_tc26_wrap_gostr3412_2015_magma_kexp15             SN_magma_kexp15
++#define NID_id_tc26_wrap_gostr3412_2015_magma_kexp15            NID_magma_kexp15
++#define OBJ_id_tc26_wrap_gostr3412_2015_magma_kexp15            OBJ_magma_kexp15
++
++#define SN_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15                SN_kuznyechik_kexp15
++#define NID_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15               NID_kuznyechik_kexp15
++#define OBJ_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15               OBJ_kuznyechik_kexp15
++
++#define SN_grasshopper_ecb              SN_kuznyechik_ecb
++#define NID_grasshopper_ecb             NID_kuznyechik_ecb
++
++#define SN_grasshopper_ctr              SN_kuznyechik_ctr
++#define NID_grasshopper_ctr             NID_kuznyechik_ctr
++
++#define SN_grasshopper_ofb              SN_kuznyechik_ofb
++#define NID_grasshopper_ofb             NID_kuznyechik_ofb
++
++#define SN_grasshopper_cbc              SN_kuznyechik_cbc
++#define NID_grasshopper_cbc             NID_kuznyechik_cbc
++
++#define SN_grasshopper_cfb              SN_kuznyechik_cfb
++#define NID_grasshopper_cfb             NID_kuznyechik_cfb
++
++#define SN_grasshopper_mac              SN_kuznyechik_mac
++#define NID_grasshopper_mac             NID_kuznyechik_mac
++
++#endif
+Index: include/openssl/evp.h
+===================================================================
+--- include/openssl/evp.h      (revision 14523)
++++ include/openssl/evp.h      (working copy)
+@@ -20,7 +20,10 @@
+ # define EVP_MAX_KEY_LENGTH              64
+ # define EVP_MAX_IV_LENGTH               16
+ # define EVP_MAX_BLOCK_LENGTH            32
++# define EVP_MAX_AEAD_TAG_LEN            16/* longest known AEAD tag size */
++#define EVP_MAX_MAC_SIZE EVP_MAX_AEAD_TAG_LEN
++
+ # define PKCS5_SALT_LEN                  8
+ /* Default PKCS#5 iteration count */
+ # define PKCS5_DEFAULT_ITER              2048
+@@ -139,6 +142,7 @@
+ #  define EVP_MD_CTRL_DIGALGID                    0x1
+ #  define EVP_MD_CTRL_MICALG                      0x2
+ #  define EVP_MD_CTRL_XOF_LEN                     0x3
++#  define EVP_MD_CTRL_TLSTREE                     0x4
+ /* Minimum Algorithm specific ctrl value */
+@@ -277,8 +281,9 @@
+ # define         EVP_CIPH_FLAG_AEAD_CIPHER       0x200000
+ # define         EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0x400000
+ /* Cipher can handle pipeline operations */
+-# define         EVP_CIPH_FLAG_PIPELINE          0X800000
+-
++# define         EVP_CIPH_FLAG_PIPELINE          0x800000
++# define         EVP_CIPH_FLAG_CIPHER_WITH_MAC  0x1000000
++# define         EVP_CIPH_FLAG_GET_WRAP_CIPHER     0X4000000
+ /*
+  * Cipher context flag to indicate we can handle wrap mode: if allowed in
+  * older applications it could overflow buffers.
+@@ -352,7 +357,21 @@
+ # define         EVP_CTRL_SET_PIPELINE_INPUT_LENS        0x24
+ # define         EVP_CTRL_GET_IVLEN                      0x25
++/* Indicates TLSTREE key diversification during TLS processing */
++# define         EVP_CTRL_TLSTREE                        0x26
++#define          EVP_CTRL_AEAD_MAX_TAG_LEN               0x27
++# define         EVP_CTRL_GET_WRAP_CIPHER                0X28
++
++# define         EVP_CTRL_GET_MAC_LEN                    EVP_CTRL_AEAD_MAX_TAG_LEN
++# define         EVP_CTRL_GET_MAC                        EVP_CTRL_AEAD_GET_TAG
++# define         EVP_CTRL_SET_EXPECTED_MAC               EVP_CTRL_AEAD_SET_TAG
++/* GOST CMS requires processing unprotected attributes in some cases*/
++# define         EVP_CTRL_PROCESS_UNPROTECTED            0x29
++/* Set GOST TLSTREE params */
++# define         EVP_CTRL_SET_TLSTREE_PARAMS             0x2A
++
++
+ /* Padding modes */
+ #define EVP_PADDING_PKCS7       1
+ #define EVP_PADDING_ISO7816_4   2
+@@ -390,6 +409,10 @@
+ /* Length of CCM8 tag for TLS */
+ # define EVP_CCM8_TLS_TAG_LEN                            8
++/* GOST TLS 1.3 tag lengths */
++# define EVP_MAGMA_TLS_TAG_LEN                           8
++# define EVP_KUZNYECHIK_TLS_TAG_LEN                      16
++
+ /* Length of tag for TLS */
+ # define EVP_CHACHAPOLY_TLS_TAG_LEN                      16
+@@ -1142,6 +1165,10 @@
+ # define ASN1_PKEY_CTRL_SET1_TLS_ENCPT   0x9
+ # define ASN1_PKEY_CTRL_GET1_TLS_ENCPT   0xa
++// This control use for decryption 
++// when algorithm support multiple ri types
++# define ASN1_PKEY_CTRL_CMS_IS_RI_TYPE_SUPPORTED      0xb
++
+ int EVP_PKEY_asn1_get_count(void);
+ const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx);
+ const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pe, int type);
+Index: include/openssl/cmserr.h
+===================================================================
+--- include/openssl/cmserr.h   (revision 14523)
++++ include/openssl/cmserr.h   (working copy)
+@@ -11,9 +11,7 @@
+ #ifndef HEADER_CMSERR_H
+ # define HEADER_CMSERR_H
+-# ifndef HEADER_SYMHACKS_H
+-#  include <openssl/symhacks.h>
+-# endif
++# include <openssl/symhacks.h>
+ # include <openssl/opensslconf.h>
+@@ -32,6 +30,7 @@
+ #  define CMS_F_CMS_ADD0_RECIPIENT_KEY                     100
+ #  define CMS_F_CMS_ADD0_RECIPIENT_PASSWORD                165
+ #  define CMS_F_CMS_ADD1_RECEIPTREQUEST                    158
++#  define CMS_F_CMS_ADD1_RECIPIENT                         181
+ #  define CMS_F_CMS_ADD1_RECIPIENT_CERT                    101
+ #  define CMS_F_CMS_ADD1_SIGNER                            102
+ #  define CMS_F_CMS_ADD1_SIGNINGTIME                       103
+@@ -47,6 +46,7 @@
+ #  define CMS_F_CMS_DECRYPT_SET1_KEY                       113
+ #  define CMS_F_CMS_DECRYPT_SET1_PASSWORD                  166
+ #  define CMS_F_CMS_DECRYPT_SET1_PKEY                      114
++#  define CMS_F_CMS_DECRYPT_SET1_PKEY_AND_PEER             182
+ #  define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX               115
+ #  define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO               116
+ #  define CMS_F_CMS_DIGESTEDDATA_DO_FINAL                  117
+@@ -59,6 +59,9 @@
+ #  define CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT                  122
+ #  define CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY                 123
+ #  define CMS_F_CMS_ENVELOPEDDATA_CREATE                   124
++#  define CMS_F_CMS_ENVELOPEDDATA_DECRYPTION_INIT_BIO      184
++#  define CMS_F_CMS_ENVELOPEDDATA_ENCRYPTION_INIT_BIO      185
++#  define CMS_F_CMS_ENVELOPEDDATA_FINAL                    186
+ #  define CMS_F_CMS_ENVELOPEDDATA_INIT_BIO                 125
+ #  define CMS_F_CMS_ENVELOPED_DATA_INIT                    126
+ #  define CMS_F_CMS_ENV_ASN1_CTRL                          171
+Index: include/openssl/x509v3err.h
+===================================================================
+--- include/openssl/x509v3err.h        (revision 14523)
++++ include/openssl/x509v3err.h        (working copy)
+@@ -37,6 +37,7 @@
+ # define X509V3_F_I2S_ASN1_ENUMERATED                     121
+ # define X509V3_F_I2S_ASN1_IA5STRING                      149
+ # define X509V3_F_I2S_ASN1_INTEGER                        120
++# define X509V3_F_I2S_ASN1_UTF8STRING                     173
+ # define X509V3_F_I2V_AUTHORITY_INFO_ACCESS               138
+ # define X509V3_F_LEVEL_ADD_NODE                          168
+ # define X509V3_F_NOTICE_SECTION                          132
+@@ -51,6 +52,7 @@
+ # define X509V3_F_S2I_ASN1_IA5STRING                      100
+ # define X509V3_F_S2I_ASN1_INTEGER                        108
+ # define X509V3_F_S2I_ASN1_OCTET_STRING                   112
++# define X509V3_F_S2I_ASN1_UTF8STRING                     174
+ # define X509V3_F_S2I_SKEY_ID                             115
+ # define X509V3_F_SET_DIST_POINT_NAME                     158
+ # define X509V3_F_SXNET_ADD_ID_ASC                        125
+Index: Configurations/unix-Makefile.tmpl
+===================================================================
+--- Configurations/unix-Makefile.tmpl  (revision 14523)
++++ Configurations/unix-Makefile.tmpl  (working copy)
+@@ -888,6 +888,7 @@
+                               crypto/objects/obj_mac.num \
+                               crypto/objects/obj_xref.txt \
+                               > crypto/objects/obj_xref.h )
++      ( cd $(SRCDIR); cat crypto/objects/obj_compat.h >> include/openssl/obj_mac.h )
+ generate_crypto_conf:
+       ( cd $(SRCDIR); $(PERL) crypto/conf/keysets.pl \
+Index: ssl/t1_trce.c
+===================================================================
+--- ssl/t1_trce.c      (revision 14523)
++++ ssl/t1_trce.c      (working copy)
+@@ -443,6 +443,9 @@
+     {0xFEFF, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"},
+     {0xFF85, "GOST2012-GOST8912-GOST8912"},
+     {0xFF87, "GOST2012-NULL-GOST12"},
++    {0xC100, "GOST2012-KUZNYECHIK-KUZNYECHIKOMAC"},
++    {0xC101, "GOST2012-MAGMA-MAGMAOMAC"},
++    {0xC102, "GOST2012-GOST8912-IANA"},
+ };
+ /* Compression methods */
+@@ -522,6 +525,13 @@
+     {28, "brainpoolP512r1"},
+     {29, "ecdh_x25519"},
+     {30, "ecdh_x448"},
++    {34, "GC256A"},
++    {35, "GC256B"},
++    {36, "GC256C"},
++    {37, "GC256D"},
++    {38, "GC512A"},
++    {39, "GC512B"},
++    {40, "GC512C"},
+     {256, "ffdhe2048"},
+     {257, "ffdhe3072"},
+     {258, "ffdhe4096"},
+@@ -571,6 +581,8 @@
+     {TLSEXT_SIGALG_dsa_sha1, "dsa_sha1"},
+     {TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256, "gost2012_256"},
+     {TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512, "gost2012_512"},
++    {TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256_legacy, "gost2012_256"},
++    {TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512_legacy, "gost2012_512"},
+     {TLSEXT_SIGALG_gostr34102001_gostr3411, "gost2001_gost94"},
+ };
+@@ -584,7 +596,9 @@
+     {20, "fortezza_dms"},
+     {64, "ecdsa_sign"},
+     {65, "rsa_fixed_ecdh"},
+-    {66, "ecdsa_fixed_ecdh"}
++    {66, "ecdsa_fixed_ecdh"},
++    {67, "gost_sign256"},
++    {68, "gost_sign512"},
+ };
+ static const ssl_trace_tbl ssl_psk_kex_modes_tbl[] = {
+@@ -1072,6 +1086,10 @@
+         *pname = "GOST";
+         return SSL_kGOST;
+     }
++    if (alg_k & SSL_kGOST18) {
++        *pname = "GOST18";
++        return SSL_kGOST18;
++    }
+     *pname = "UNKNOWN";
+     return 0;
+ }
+@@ -1114,7 +1132,16 @@
+         if (!ssl_print_hexbuf(bio, indent + 2, "ecdh_Yc", 1, &msg, &msglen))
+             return 0;
+         break;
+-
++#ifndef OPENSSL_NO_GOST
++    case SSL_kGOST:
++        ssl_print_hex(bio, indent + 2, "GOST-wrapped PreMasterSecret", msg, msglen);
++        break;
++    case SSL_kGOST18:
++            ssl_print_hex(bio, indent + 2,
++                                "GOST-wrapped PreMasterSecret", msg, msglen);
++                return 0;
++        break;
++#endif
+     }
+     return !msglen;
+Index: ssl/ssl_err.c
+===================================================================
+--- ssl/ssl_err.c      (revision 14523)
++++ ssl/ssl_err.c      (working copy)
+@@ -1,6 +1,6 @@
+ /*
+  * Generated by util/mkerr.pl DO NOT EDIT
+- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
++ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+  *
+  * Licensed under the OpenSSL license (the "License").  You may not use
+  * this file except in compliance with the License.  You can obtain a copy
+@@ -112,6 +112,8 @@
+      "ossl_statem_server_post_process_message"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_POST_WORK, 0),
+      "ossl_statem_server_post_work"},
++    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PRE_WORK, 0),
++     "ossl_statem_server_pre_work"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE, 0),
+      "ossl_statem_server_process_message"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION, 0),
+@@ -437,6 +439,8 @@
+      "tls_construct_cke_ecdhe"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_GOST, 0),
+      "tls_construct_cke_gost"},
++    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_GOST18, 0),
++     "tls_construct_cke_gost18"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, 0),
+      "tls_construct_cke_psk_preamble"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CKE_RSA, 0),
+@@ -664,6 +668,8 @@
+      "tls_process_cke_ecdhe"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_GOST, 0),
+      "tls_process_cke_gost"},
++    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_GOST18, 0),
++     "tls_process_cke_gost18"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, 0),
+      "tls_process_cke_psk_preamble"},
+     {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PROCESS_CKE_RSA, 0),
+Index: ssl/t1_lib.c
+===================================================================
+--- ssl/t1_lib.c       (revision 14523)
++++ ssl/t1_lib.c       (working copy)
+@@ -169,6 +169,18 @@
+     {NID_brainpoolP512r1, 256, TLS_CURVE_PRIME}, /* brainpool512r1 (28) */
+     {EVP_PKEY_X25519, 128, TLS_CURVE_CUSTOM}, /* X25519 (29) */
+     {EVP_PKEY_X448, 224, TLS_CURVE_CUSTOM}, /* X448 (30) */
++#ifndef OPENSSL_NO_GOST
++    {NID_undef, 0, TLS_CURVE_CUSTOM}, /* 31 */
++    {NID_undef, 0, TLS_CURVE_CUSTOM}, /* 32 */
++    {NID_undef, 0, TLS_CURVE_CUSTOM}, /* 33 */
++    {NID_id_tc26_gost_3410_2012_256_paramSetA, 128, TLS_CURVE_GOST},
++    {NID_id_tc26_gost_3410_2012_256_paramSetB, 128, TLS_CURVE_GOST},
++    {NID_id_tc26_gost_3410_2012_256_paramSetC, 128, TLS_CURVE_GOST},
++    {NID_id_tc26_gost_3410_2012_256_paramSetD, 128, TLS_CURVE_GOST},
++    {NID_id_tc26_gost_3410_2012_512_paramSetA, 256, TLS_CURVE_GOST},
++    {NID_id_tc26_gost_3410_2012_512_paramSetB, 256, TLS_CURVE_GOST},
++    {NID_id_tc26_gost_3410_2012_512_paramSetC, 256, TLS_CURVE_GOST},
++#endif
+ };
+ static const unsigned char ecformats_default[] = {
+@@ -184,6 +196,15 @@
+     30,                      /* X448 (30) */
+     25,                      /* secp521r1 (25) */
+     24,                      /* secp384r1 (24) */
++#ifndef OPENSSL_NO_GOST
++    34,
++    35,
++    36,
++    37,
++    38,
++    39,
++    40,
++#endif
+ };
+ static const uint16_t suiteb_curves[] = {
+@@ -196,6 +217,8 @@
+     /* ECC curves from RFC 4492 and RFC 7027 */
+     if (group_id < 1 || group_id > OSSL_NELEM(nid_list))
+         return NULL;
++    if (nid_list[group_id - 1].nid == NID_undef)
++        return NULL;
+     return &nid_list[group_id - 1];
+ }
+@@ -380,6 +403,33 @@
+     int nid_arr[MAX_CURVELIST];
+ } nid_cb_st;
++#ifndef OPENSSL_NO_GOST
++typedef struct {
++    const char *name;           /* Name of GOST curve */
++    int nid;                    /* Curve NID */
++} EC_GOST_NAME;
++
++static EC_GOST_NAME gost_curves[] = {
++    {"GC256A", NID_id_tc26_gost_3410_2012_256_paramSetA},
++    {"GC256B", NID_id_tc26_gost_3410_2012_256_paramSetB},
++    {"GC256C", NID_id_tc26_gost_3410_2012_256_paramSetC},
++    {"GC256D", NID_id_tc26_gost_3410_2012_256_paramSetD},
++    {"GC512A", NID_id_tc26_gost_3410_2012_512_paramSetA},
++    {"GC512B", NID_id_tc26_gost_3410_2012_512_paramSetB},
++    {"GC512C", NID_id_tc26_gost_3410_2012_512_paramSetC},
++};
++
++int GOST_curve2nid(const char *name)
++{
++    size_t i;
++    for (i = 0; i < OSSL_NELEM(gost_curves); i++) {
++        if (strcmp(gost_curves[i].name, name) == 0)
++            return gost_curves[i].nid;
++    }
++    return NID_undef;
++}
++#endif
++
+ static int nid_cb(const char *elem, int len, void *arg)
+ {
+     nid_cb_st *narg = arg;
+@@ -395,7 +445,12 @@
+     memcpy(etmp, elem, len);
+     etmp[len] = 0;
+     nid = EC_curve_nist2nid(etmp);
++#ifndef OPENSSL_NO_GOST
++              /* FIXME beldmit */
+     if (nid == NID_undef)
++        nid = GOST_curve2nid(etmp);
++#endif
++    if (nid == NID_undef)
+         nid = OBJ_sn2nid(etmp);
+     if (nid == NID_undef)
+         nid = OBJ_ln2nid(etmp);
+@@ -670,8 +725,17 @@
+     TLSEXT_SIGALG_dsa_sha512,
+ #endif
+ #ifndef OPENSSL_NO_GOST
++    TLSEXT_SIGALG_gostr34102012_256a,
++    TLSEXT_SIGALG_gostr34102012_256b,
++    TLSEXT_SIGALG_gostr34102012_256c,
++    TLSEXT_SIGALG_gostr34102012_256d,
++    TLSEXT_SIGALG_gostr34102012_512a,
++    TLSEXT_SIGALG_gostr34102012_512b,
++    TLSEXT_SIGALG_gostr34102012_512c,
+     TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256,
+     TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512,
++    TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256_legacy,
++    TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512_legacy,
+     TLSEXT_SIGALG_gostr34102001_gostr3411,
+ #endif
+ };
+@@ -758,6 +822,34 @@
+      NID_dsaWithSHA1, NID_undef},
+ #endif
+ #ifndef OPENSSL_NO_GOST
++    {"gostr34102012_256a", TLSEXT_SIGALG_gostr34102012_256a,
++     NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX,
++     NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256,
++     NID_undef, NID_undef},
++    {"gostr34102012_256b", TLSEXT_SIGALG_gostr34102012_256b,
++     NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX,
++     NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256,
++     NID_undef, NID_undef},
++    {"gostr34102012_256c", TLSEXT_SIGALG_gostr34102012_256c,
++     NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX,
++     NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256,
++     NID_undef, NID_undef},
++    {"gostr34102012_256d", TLSEXT_SIGALG_gostr34102012_256d,
++     NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX,
++     NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256,
++     NID_undef, NID_undef},
++    {"gostr34102012_512a", TLSEXT_SIGALG_gostr34102012_512a,
++     NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX,
++     NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512,
++     NID_undef, NID_undef},
++    {"gostr34102012_512b", TLSEXT_SIGALG_gostr34102012_512b,
++     NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX,
++     NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512,
++     NID_undef, NID_undef},
++    {"gostr34102012_512c", TLSEXT_SIGALG_gostr34102012_512c,
++     NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX,
++     NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512,
++     NID_undef, NID_undef},
+     {NULL, TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256,
+      NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX,
+      NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256,
+@@ -766,6 +858,14 @@
+      NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX,
+      NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512,
+      NID_undef, NID_undef},
++    {NULL, TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256_legacy,
++     NID_id_GostR3411_2012_256, SSL_MD_GOST12_256_IDX,
++     NID_id_GostR3410_2012_256, SSL_PKEY_GOST12_256,
++     NID_undef, NID_undef},
++    {NULL, TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512_legacy,
++     NID_id_GostR3411_2012_512, SSL_MD_GOST12_512_IDX,
++     NID_id_GostR3410_2012_512, SSL_PKEY_GOST12_512,
++     NID_undef, NID_undef},
+     {NULL, TLSEXT_SIGALG_gostr34102001_gostr3411,
+      NID_id_GostR3411_94, SSL_MD_GOST94_IDX,
+      NID_id_GostR3410_2001, SSL_PKEY_GOST01,
+@@ -886,6 +986,24 @@
+                     }
+                 }
+             }
++            /*
++             * Here is another fallback: when broken implementations did not sent
++             * proper signature_algorithm extension, we try to use this function.
++             *
++             * As both SSL_PKEY_GOST12_512 and SSL_PKEY_GOST12_256 indices can be used
++             * with new (aGOST12-only) ciphersuites, we should find out which one is available really.
++             * */
++            else if (idx == SSL_PKEY_GOST12_256) {
++                int real_idx;
++
++                for (real_idx = SSL_PKEY_GOST12_512; real_idx >= SSL_PKEY_GOST12_256;
++                     real_idx--) {
++                    if (s->cert->pkeys[real_idx].privatekey != NULL) {
++                        idx = real_idx;
++                        break;
++                    }
++                }
++            }
+         } else {
+             idx = s->cert->key - s->cert->pkeys;
+         }
+@@ -1612,10 +1730,8 @@
+     if (ssl_cert_is_disabled(lu->sig_idx))
+         return 0;
+-    if (lu->sig == NID_id_GostR3410_2012_256
+-            || lu->sig == NID_id_GostR3410_2012_512
+-            || lu->sig == NID_id_GostR3410_2001) {
+-        /* We never allow GOST sig algs on the server with TLSv1.3 */
++    if (lu->sig == NID_id_GostR3410_2001) {
++        /* GOST sig algs on the server with TLSv1.3 are allowed for GOST2012 */
+         if (s->server && SSL_IS_TLS13(s))
+             return 0;
+         if (!s->server
+@@ -1643,7 +1759,7 @@
+                 if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED, 0))
+                     continue;
+-                if ((c->algorithm_mkey & SSL_kGOST) != 0)
++                if ((c->algorithm_mkey & (SSL_kGOST | SSL_kGOST18)) != 0)
+                     break;
+             }
+             if (i == num)
+Index: ssl/ssl_local.h
+===================================================================
+--- ssl/ssl_local.h    (revision 14523)
++++ ssl/ssl_local.h    (working copy)
+@@ -176,6 +176,8 @@
+ # define SSL_kRSAPSK             0x00000040U
+ # define SSL_kECDHEPSK           0x00000080U
+ # define SSL_kDHEPSK             0x00000100U
++/* GOST KDF key exchange, draft-smyshlyaev-tls12-gost-suites */
++# define SSL_kGOST18             0x00000200U
+ /* all PSK */
+@@ -230,6 +232,10 @@
+ # define SSL_CHACHA20POLY1305    0x00080000U
+ # define SSL_ARIA128GCM          0x00100000U
+ # define SSL_ARIA256GCM          0x00200000U
++# define SSL_MAGMA               0x00400000U
++# define SSL_KUZNYECHIK          0x00800000U
++# define SSL_MAGMA_MGM           0x01000000U
++# define SSL_KUZNYECHIK_MGM      0x02000000U
+ # define SSL_AESGCM              (SSL_AES128GCM | SSL_AES256GCM)
+ # define SSL_AESCCM              (SSL_AES128CCM | SSL_AES256CCM | SSL_AES128CCM8 | SSL_AES256CCM8)
+@@ -252,6 +258,8 @@
+ # define SSL_GOST12_256          0x00000080U
+ # define SSL_GOST89MAC12         0x00000100U
+ # define SSL_GOST12_512          0x00000200U
++# define SSL_MAGMAOMAC           0x00000400U
++# define SSL_KUZNYECHIKOMAC      0x00000800U
+ /*
+  * When adding new digest in the ssl_ciph.c and increment SSL_MD_NUM_IDX make
+@@ -270,7 +278,9 @@
+ # define SSL_MD_MD5_SHA1_IDX 9
+ # define SSL_MD_SHA224_IDX 10
+ # define SSL_MD_SHA512_IDX 11
+-# define SSL_MAX_DIGEST 12
++# define SSL_MD_MAGMAOMAC_IDX 12
++# define SSL_MD_KUZNYECHIKOMAC_IDX 13
++# define SSL_MAX_DIGEST 14
+ /* Bits for algorithm2 (handshake digests and other extra flags) */
+@@ -299,6 +309,13 @@
+  * goes into algorithm2)
+  */
+ # define TLS1_STREAM_MAC 0x10000
++/*
++ * TLSTREE cipher/mac key derivation used for GOST TLS 1.2/1.3 ciphersuites 
++ * (currently this also goes into algorithm2)
++ */
++# define TLS1_TLSTREE    0x20000
++# define TLS1_TLSTREE_S  0x40000
++# define TLS1_TLSTREE_L  0x80000
+ # define SSL_STRONG_MASK         0x0000001FU
+ # define SSL_DEFAULT_MASK        0X00000020U
+@@ -1512,10 +1529,11 @@
+ } TLS_GROUP_INFO;
+ /* flags values */
+-# define TLS_CURVE_TYPE          0x3 /* Mask for group type */
++# define TLS_CURVE_TYPE          0x7 /* Mask for group type */
+ # define TLS_CURVE_PRIME         0x0
+ # define TLS_CURVE_CHAR2         0x1
+ # define TLS_CURVE_CUSTOM        0x2
++# define TLS_CURVE_GOST          0x4
+ typedef struct cert_pkey_st CERT_PKEY;
+@@ -2043,8 +2061,17 @@
+ #define TLSEXT_SIGALG_dsa_sha512                                0x0602
+ #define TLSEXT_SIGALG_dsa_sha224                                0x0302
+ #define TLSEXT_SIGALG_dsa_sha1                                  0x0202
+-#define TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256       0xeeee
+-#define TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512       0xefef
++#define TLSEXT_SIGALG_gostr34102012_256a                        0x0709
++#define TLSEXT_SIGALG_gostr34102012_256b                        0x070A
++#define TLSEXT_SIGALG_gostr34102012_256c                        0x070B
++#define TLSEXT_SIGALG_gostr34102012_256d                        0x070C
++#define TLSEXT_SIGALG_gostr34102012_512a                        0x070D
++#define TLSEXT_SIGALG_gostr34102012_512b                        0x070E
++#define TLSEXT_SIGALG_gostr34102012_512c                        0x070F
++#define TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256       0x0840
++#define TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512       0x0841
++#define TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256_legacy 0xeeee
++#define TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512_legacy 0xefef
+ #define TLSEXT_SIGALG_gostr34102001_gostr3411                   0xeded
+ #define TLSEXT_SIGALG_ed25519                                   0x0807
+Index: ssl/ssl_lib.c
+===================================================================
+--- ssl/ssl_lib.c      (revision 14523)
++++ ssl/ssl_lib.c      (working copy)
+@@ -3327,11 +3327,11 @@
+ #ifndef OPENSSL_NO_GOST
+     if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) {
+-        mask_k |= SSL_kGOST;
++        mask_k |= SSL_kGOST | SSL_kGOST18;
+         mask_a |= SSL_aGOST12;
+     }
+     if (ssl_has_cert(s, SSL_PKEY_GOST12_256)) {
+-        mask_k |= SSL_kGOST;
++        mask_k |= SSL_kGOST | SSL_kGOST18;
+         mask_a |= SSL_aGOST12;
+     }
+     if (ssl_has_cert(s, SSL_PKEY_GOST01)) {
+Index: ssl/tls13_enc.c
+===================================================================
+--- ssl/tls13_enc.c    (revision 14523)
++++ ssl/tls13_enc.c    (working copy)
+@@ -421,6 +421,21 @@
+         goto err;
+     }
++    if (s->s3->tmp.new_cipher->algorithm2 & TLS1_TLSTREE) {
++      int res = 0;
++      if (s->s3->tmp.new_cipher->algorithm2 & TLS1_TLSTREE_S) {
++          res = EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_SET_TLSTREE_PARAMS, 0, "short");
++      } else if (s->s3->tmp.new_cipher->algorithm2 & TLS1_TLSTREE_L) {
++          res = EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_SET_TLSTREE_PARAMS, 0, "long");
++      }
++
++      if (res <= 0) {
++          SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DERIVE_SECRET_KEY_AND_IV,
++                   ERR_R_EVP_LIB);
++          goto err;
++      }
++    }
++
+     return 1;
+  err:
+     OPENSSL_cleanse(key, sizeof(key));
+Index: ssl/record/ssl3_record.c
+===================================================================
+--- ssl/record/ssl3_record.c   (revision 14523)
++++ ssl/record/ssl3_record.c   (working copy)
+@@ -944,6 +944,8 @@
+     unsigned char padval;
+     int imac_size;
+     const EVP_CIPHER *enc;
++    int tlstree_enc = (sending ? (s->mac_flags & SSL_MAC_FLAG_WRITE_MAC_TLSTREE)
++                      : (s->mac_flags & SSL_MAC_FLAG_READ_MAC_TLSTREE));
+     if (n_recs == 0) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+@@ -1036,7 +1038,6 @@
+                 seq = sending ? RECORD_LAYER_get_write_sequence(&s->rlayer)
+                     : RECORD_LAYER_get_read_sequence(&s->rlayer);
+-
+                 if (SSL_IS_DTLS(s)) {
+                     /* DTLS does not support pipelining */
+                     unsigned char dtlsseq[9], *p = dtlsseq;
+@@ -1122,6 +1123,27 @@
+             }
+         }
++        if (!SSL_IS_DTLS(s) && tlstree_enc) {
++          unsigned char *seq;
++          int decrement_seq = 0;
++          /*
++           * When sending, seq is incremented after MAC calculation.
++           * So if we are in ETM mode, we use seq 'as is' in the ctrl-function.
++           * Otherwise we have to decrease it in the implementation
++           */
++          if (sending && !SSL_WRITE_ETM(s))
++              decrement_seq = 1;
++
++          seq = sending ? RECORD_LAYER_get_write_sequence(&s->rlayer)
++            : RECORD_LAYER_get_read_sequence(&s->rlayer);
++          if(EVP_CIPHER_CTX_ctrl(ds, EVP_CTRL_TLSTREE, decrement_seq, seq) <= 0)
++          {
++            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
++                ERR_R_INTERNAL_ERROR);
++            return -1;
++          }
++        }
++
+         /* TODO(size_t): Convert this call */
+         tmpr = EVP_Cipher(ds, recs[0].data, recs[0].input,
+                           (unsigned int)reclen[0]);
+@@ -1287,6 +1309,8 @@
+     unsigned char header[13];
+     int stream_mac = (sending ? (ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM)
+                       : (ssl->mac_flags & SSL_MAC_FLAG_READ_MAC_STREAM));
++    int tlstree_mac = (sending ? (ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_TLSTREE)
++                      : (ssl->mac_flags & SSL_MAC_FLAG_READ_MAC_TLSTREE));
+     int t;
+     if (sending) {
+@@ -1314,6 +1338,11 @@
+         mac_ctx = hmac;
+     }
++    if (!SSL_IS_DTLS(ssl) && tlstree_mac && EVP_MD_CTX_ctrl(mac_ctx, EVP_MD_CTRL_TLSTREE, 0, seq) <= 0) {
++      EVP_MD_CTX_free(hmac);
++      return 0;
++    }
++
+     if (SSL_IS_DTLS(ssl)) {
+         unsigned char dtlsseq[8], *p = dtlsseq;
+Index: ssl/record/ssl3_record_tls13.c
+===================================================================
+--- ssl/record/ssl3_record_tls13.c     (revision 14523)
++++ ssl/record/ssl3_record_tls13.c     (working copy)
+@@ -107,6 +107,10 @@
+         taglen = EVP_GCM_TLS_TAG_LEN;
+     } else if (alg_enc & SSL_CHACHA20) {
+         taglen = EVP_CHACHAPOLY_TLS_TAG_LEN;
++    } else if (alg_enc & SSL_MAGMA_MGM) {
++        taglen = EVP_MAGMA_TLS_TAG_LEN;
++    } else if (alg_enc & SSL_KUZNYECHIK_MGM) {
++        taglen = EVP_KUZNYECHIK_TLS_TAG_LEN;
+     } else {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
+                  ERR_R_INTERNAL_ERROR);
+@@ -135,6 +139,15 @@
+     for (loop = 0; loop < SEQ_NUM_SIZE; loop++)
+         iv[offset + loop] = staticiv[offset + loop] ^ seq[loop];
++    if (s->s3->tmp.new_cipher->algorithm2 & TLS1_TLSTREE) {
++        if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_TLSTREE,
++                                0, seq) <= 0) {
++            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_ENC,
++                     ERR_R_INTERNAL_ERROR);
++            return -1;
++        }
++    }
++
+     /* Increment the sequence counter */
+     for (loop = SEQ_NUM_SIZE; loop > 0; loop--) {
+         ++seq[loop - 1];
+Index: ssl/ssl_ciph.c
+===================================================================
+--- ssl/ssl_ciph.c     (revision 14523)
++++ ssl/ssl_ciph.c     (working copy)
+@@ -43,7 +43,11 @@
+ #define SSL_ENC_CHACHA_IDX      19
+ #define SSL_ENC_ARIA128GCM_IDX  20
+ #define SSL_ENC_ARIA256GCM_IDX  21
+-#define SSL_ENC_NUM_IDX         22
++#define SSL_ENC_MAGMA_IDX       22
++#define SSL_ENC_KUZNYECHIK_IDX  23
++#define SSL_ENC_MAGMA_MGM_IDX       24
++#define SSL_ENC_KUZNYECHIK_MGM_IDX  25
++#define SSL_ENC_NUM_IDX         26
+ /* NB: make sure indices in these tables match values above */
+@@ -76,6 +80,10 @@
+     {SSL_CHACHA20POLY1305, NID_chacha20_poly1305}, /* SSL_ENC_CHACHA_IDX 19 */
+     {SSL_ARIA128GCM, NID_aria_128_gcm}, /* SSL_ENC_ARIA128GCM_IDX 20 */
+     {SSL_ARIA256GCM, NID_aria_256_gcm}, /* SSL_ENC_ARIA256GCM_IDX 21 */
++    {SSL_MAGMA, NID_magma_ctr_acpkm}, /* SSL_ENC_MAGMA_IDX */
++    {SSL_KUZNYECHIK, NID_kuznyechik_ctr_acpkm}, /* SSL_ENC_KUZNYECHIK_IDX */
++    {SSL_MAGMA_MGM, NID_magma_mgm}, /* SSL_ENC_MAGMA_MGM_IDX */
++    {SSL_KUZNYECHIK_MGM, NID_kuznyechik_mgm}, /* SSL_ENC_KUZNYECHIK_MGM_IDX */
+ };
+ static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX];
+@@ -110,11 +118,13 @@
+     {SSL_GOST12_512, NID_id_GostR3411_2012_512}, /* SSL_MD_GOST12_512_IDX 8 */
+     {0, NID_md5_sha1},          /* SSL_MD_MD5_SHA1_IDX 9 */
+     {0, NID_sha224},            /* SSL_MD_SHA224_IDX 10 */
+-    {0, NID_sha512}             /* SSL_MD_SHA512_IDX 11 */
++    {0, NID_sha512},            /* SSL_MD_SHA512_IDX 11 */
++    {SSL_MAGMAOMAC, NID_magma_mac}, /* SSL_MD_MAGMAOMAC_IDX */
++    {SSL_KUZNYECHIKOMAC, NID_kuznyechik_mac}, /* SSL_MD_KUZNYECHIKOMAC_IDX */
+ };
+ static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = {
+-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
++    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ };
+ /* *INDENT-OFF* */
+@@ -128,6 +138,7 @@
+     {SSL_kPSK,      NID_kx_psk},
+     {SSL_kSRP,      NID_kx_srp},
+     {SSL_kGOST,     NID_kx_gost},
++    {SSL_kGOST18,   NID_kx_gost},/* FIXME beldmit */
+     {SSL_kANY,      NID_kx_any}
+ };
+@@ -171,8 +182,8 @@
+     EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, NID_undef,
+     /* GOST2012_512 */
+     EVP_PKEY_HMAC,
+-    /* MD5/SHA1, SHA224, SHA512 */
+-    NID_undef, NID_undef, NID_undef
++    /* MD5/SHA1, SHA224, SHA512, MAGMAOMAC, KUZNYECHIKOMAC */
++    NID_undef, NID_undef, NID_undef, NID_undef, NID_undef
+ };
+ static size_t ssl_mac_secret_size[SSL_MD_NUM_IDX];
+@@ -228,6 +239,7 @@
+     {0, SSL_TXT_kDHEPSK, NULL, 0, SSL_kDHEPSK},
+     {0, SSL_TXT_kSRP, NULL, 0, SSL_kSRP},
+     {0, SSL_TXT_kGOST, NULL, 0, SSL_kGOST},
++    {0, SSL_TXT_kGOST18, NULL, 0, SSL_kGOST18},
+     /* server authentication aliases */
+     {0, SSL_TXT_aRSA, NULL, 0, 0, SSL_aRSA},
+@@ -261,7 +273,7 @@
+     {0, SSL_TXT_IDEA, NULL, 0, 0, 0, SSL_IDEA},
+     {0, SSL_TXT_SEED, NULL, 0, 0, 0, SSL_SEED},
+     {0, SSL_TXT_eNULL, NULL, 0, 0, 0, SSL_eNULL},
+-    {0, SSL_TXT_GOST, NULL, 0, 0, 0, SSL_eGOST2814789CNT | SSL_eGOST2814789CNT12},
++    {0, SSL_TXT_GOST, NULL, 0, 0, 0, SSL_eGOST2814789CNT | SSL_eGOST2814789CNT12 | SSL_MAGMA | SSL_KUZNYECHIK},
+     {0, SSL_TXT_AES128, NULL, 0, 0, 0,
+      SSL_AES128 | SSL_AES128GCM | SSL_AES128CCM | SSL_AES128CCM8},
+     {0, SSL_TXT_AES256, NULL, 0, 0, 0,
+@@ -419,7 +431,7 @@
+      * Check for presence of GOST 34.10 algorithms, and if they are not
+      * present, disable appropriate auth and key exchange
+      */
+-    ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX] = get_optional_pkey_id("gost-mac");
++    ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX] = get_optional_pkey_id(SN_id_Gost28147_89_MAC);
+     if (ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX])
+         ssl_mac_secret_size[SSL_MD_GOST89MAC_IDX] = 32;
+     else
+@@ -426,17 +438,31 @@
+         disabled_mac_mask |= SSL_GOST89MAC;
+     ssl_mac_pkey_id[SSL_MD_GOST89MAC12_IDX] =
+-        get_optional_pkey_id("gost-mac-12");
++        get_optional_pkey_id(SN_gost_mac_12);
+     if (ssl_mac_pkey_id[SSL_MD_GOST89MAC12_IDX])
+         ssl_mac_secret_size[SSL_MD_GOST89MAC12_IDX] = 32;
+     else
+         disabled_mac_mask |= SSL_GOST89MAC12;
+-    if (!get_optional_pkey_id("gost2001"))
++    ssl_mac_pkey_id[SSL_MD_MAGMAOMAC_IDX] =
++        get_optional_pkey_id(SN_magma_mac);
++    if (ssl_mac_pkey_id[SSL_MD_MAGMAOMAC_IDX])
++        ssl_mac_secret_size[SSL_MD_MAGMAOMAC_IDX] = 32;
++    else
++        disabled_mac_mask |= SSL_MAGMAOMAC;
++
++    ssl_mac_pkey_id[SSL_MD_KUZNYECHIKOMAC_IDX] =
++        get_optional_pkey_id(SN_kuznyechik_mac);
++    if (ssl_mac_pkey_id[SSL_MD_KUZNYECHIKOMAC_IDX])
++        ssl_mac_secret_size[SSL_MD_KUZNYECHIKOMAC_IDX] = 32;
++    else
++        disabled_mac_mask |= SSL_KUZNYECHIKOMAC;
++
++    if (!get_optional_pkey_id(SN_id_GostR3410_2001))
+         disabled_auth_mask |= SSL_aGOST01 | SSL_aGOST12;
+-    if (!get_optional_pkey_id("gost2012_256"))
++    if (!get_optional_pkey_id(SN_id_GostR3410_2012_256))
+         disabled_auth_mask |= SSL_aGOST12;
+-    if (!get_optional_pkey_id("gost2012_512"))
++    if (!get_optional_pkey_id(SN_id_GostR3410_2012_512))
+         disabled_auth_mask |= SSL_aGOST12;
+     /*
+      * Disable GOST key exchange if no GOST signature algs are available *
+@@ -445,6 +471,9 @@
+         (SSL_aGOST01 | SSL_aGOST12))
+         disabled_mkey_mask |= SSL_kGOST;
++    if ((disabled_auth_mask & SSL_aGOST12) ==  SSL_aGOST12)
++        disabled_mkey_mask |= SSL_kGOST18;
++
+     return 1;
+ }
+@@ -1686,6 +1715,9 @@
+     case SSL_kGOST:
+         kx = "GOST";
+         break;
++    case SSL_kGOST18:
++        kx = "GOST18";
++        break;
+     case SSL_kANY:
+         kx = "any";
+         break;
+@@ -1789,6 +1821,14 @@
+     case SSL_eGOST2814789CNT12:
+         enc = "GOST89(256)";
+         break;
++    case SSL_MAGMA:
++    case SSL_MAGMA_MGM:
++        enc = "MAGMA";
++        break;
++    case SSL_KUZNYECHIK:
++    case SSL_KUZNYECHIK_MGM:
++        enc = "KUZNYECHIK";
++        break;
+     case SSL_CHACHA20POLY1305:
+         enc = "CHACHA20/POLY1305(256)";
+         break;
+Index: ssl/t1_enc.c
+===================================================================
+--- ssl/t1_enc.c       (revision 14523)
++++ ssl/t1_enc.c       (working copy)
+@@ -113,6 +113,11 @@
+         else
+             s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM;
++        if (s->s3->tmp.new_cipher->algorithm2 & TLS1_TLSTREE)
++            s->mac_flags |= SSL_MAC_FLAG_READ_MAC_TLSTREE;
++        else
++            s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_TLSTREE;
++
+         if (s->enc_read_ctx != NULL) {
+             reuse_dd = 1;
+         } else if ((s->enc_read_ctx = EVP_CIPHER_CTX_new()) == NULL) {
+@@ -160,6 +165,11 @@
+             s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
+         else
+             s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM;
++
++        if (s->s3->tmp.new_cipher->algorithm2 & TLS1_TLSTREE)
++            s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_TLSTREE;
++        else
++            s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_TLSTREE;
+         if (s->enc_write_ctx != NULL && !SSL_IS_DTLS(s)) {
+             reuse_dd = 1;
+         } else if ((s->enc_write_ctx = EVP_CIPHER_CTX_new()) == NULL) {
+@@ -298,11 +308,11 @@
+             goto err;
+         }
+     } else {
+-        if (!EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE))) {
+-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+-                     ERR_R_INTERNAL_ERROR);
+-            goto err;
+-        }
++      if (!EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE))) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
++            ERR_R_INTERNAL_ERROR);
++        goto err;
++      }
+     }
+     /* Needed for "composite" AEADs, such as RC4-HMAC-MD5 */
+     if ((EVP_CIPHER_flags(c) & EVP_CIPH_FLAG_AEAD_CIPHER) && *mac_secret_size
+@@ -438,7 +448,11 @@
+ {
+     size_t hashlen;
+     unsigned char hash[EVP_MAX_MD_SIZE];
++    size_t finished_size = TLS1_FINISH_MAC_LENGTH;
++    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kGOST18)
++        finished_size = 32;
++
+     if (!ssl3_digest_cached_records(s, 0)) {
+         /* SSLfatal() already called */
+         return 0;
+@@ -451,12 +465,12 @@
+     if (!tls1_PRF(s, str, slen, hash, hashlen, NULL, 0, NULL, 0, NULL, 0,
+                   s->session->master_key, s->session->master_key_length,
+-                  out, TLS1_FINISH_MAC_LENGTH, 1)) {
++                  out, finished_size, 1)) {
+         /* SSLfatal() already called */
+         return 0;
+     }
+     OPENSSL_cleanse(hash, hashlen);
+-    return TLS1_FINISH_MAC_LENGTH;
++    return finished_size;
+ }
+ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
+Index: ssl/s3_lib.c
+===================================================================
+--- ssl/s3_lib.c       (revision 14523)
++++ ssl/s3_lib.c       (working copy)
+@@ -111,7 +111,74 @@
+         SSL_HANDSHAKE_MAC_SHA256,
+         128,
+         128,
+-    }
++    },
++#ifndef OPENSSL_NO_GOST
++/* https://tools.ietf.org/html/draft-smyshlyaev-tls13-gost-suites */
++    {
++        1,
++        "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L", /* FIXME */
++        "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L", /* FIXME */
++        TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L,
++        SSL_kANY,
++        SSL_aANY,
++        SSL_KUZNYECHIK_MGM,
++        SSL_AEAD,
++        TLS1_3_VERSION, TLS1_3_VERSION,
++        0, 0,
++        SSL_HIGH,
++        SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_TLSTREE | TLS1_TLSTREE_L,
++        256,
++        256,
++    },
++    {
++        1,
++        "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L", /* FIXME */
++        "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L", /* FIXME */
++        TLS_GOSTR341112_256_WITH_MAGMA_MGM_L,
++        SSL_kANY,
++        SSL_aANY,
++        SSL_MAGMA_MGM,
++        SSL_AEAD,
++        TLS1_3_VERSION, TLS1_3_VERSION,
++        0, 0,
++        SSL_HIGH,
++        SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_TLSTREE | TLS1_TLSTREE_L,
++        256,
++        256,
++    },
++    {
++        1,
++        "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S", /* FIXME */
++        "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S", /* FIXME */
++        TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S,
++        SSL_kANY,
++        SSL_aANY,
++        SSL_KUZNYECHIK_MGM,
++        SSL_AEAD,
++        TLS1_3_VERSION, TLS1_3_VERSION,
++        0, 0,
++        SSL_HIGH,
++        SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_TLSTREE | TLS1_TLSTREE_S,
++        256,
++        256,
++    },
++    {
++        1,
++        "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S", /* FIXME */
++        "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S", /* FIXME */
++        TLS_GOSTR341112_256_WITH_MAGMA_MGM_S,
++        SSL_kANY,
++        SSL_aANY,
++        SSL_MAGMA_MGM,
++        SSL_AEAD,
++        TLS1_3_VERSION, TLS1_3_VERSION,
++        0, 0,
++        SSL_HIGH,
++        SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_TLSTREE | TLS1_TLSTREE_S,
++        256,
++        256,
++    },
++#endif
+ };
+ /*
+@@ -2665,6 +2732,54 @@
+      0,
+      0,
+      },
++    {
++     1,
++     "GOST2012-KUZNYECHIK-KUZNYECHIKOMAC",
++     NULL,
++     0x0300C100,
++     SSL_kGOST18,
++     SSL_aGOST12,
++     SSL_KUZNYECHIK,
++     SSL_KUZNYECHIKOMAC,
++     TLS1_2_VERSION, TLS1_2_VERSION,
++     0, 0,
++     SSL_HIGH,
++     SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_TLSTREE,
++     256,
++     256,
++     },
++    {
++     1,
++     "GOST2012-MAGMA-MAGMAOMAC",
++     NULL,
++     0x0300C101,
++     SSL_kGOST18,
++     SSL_aGOST12,
++     SSL_MAGMA,
++     SSL_MAGMAOMAC,
++     TLS1_2_VERSION, TLS1_2_VERSION,
++     0, 0,
++     SSL_HIGH,
++     SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_TLSTREE,
++     256,
++     256,
++     },
++    {
++     1,
++     "GOST2012-GOST8912-IANA",
++     NULL,
++     0x0300C102,
++     SSL_kGOST,
++     SSL_aGOST12 | SSL_aGOST01,
++     SSL_eGOST2814789CNT12,
++     SSL_GOST89MAC12,
++     TLS1_VERSION, TLS1_2_VERSION,
++     0, 0,
++     SSL_HIGH,
++     SSL_HANDSHAKE_MAC_GOST12_256 | TLS1_PRF_GOST12_256 | TLS1_STREAM_MAC,
++     256,
++     256,
++     },
+ #endif                          /* OPENSSL_NO_GOST */
+ #ifndef OPENSSL_NO_IDEA
+@@ -4348,6 +4463,11 @@
+     if (s->version >= TLS1_VERSION && (alg_k & SSL_kGOST))
+             return WPACKET_put_bytes_u8(pkt, TLS_CT_GOST01_SIGN)
+                     && WPACKET_put_bytes_u8(pkt, TLS_CT_GOST12_SIGN)
++                    && WPACKET_put_bytes_u8(pkt, TLS_CT_GOST12_512_SIGN)
++                    && WPACKET_put_bytes_u8(pkt, TLS_CT_GOST12_SIGN_LEGACY)
++                    && WPACKET_put_bytes_u8(pkt, TLS_CT_GOST12_512_SIGN_LEGACY);
++    if (s->version >= TLS1_2_VERSION && (alg_k & SSL_kGOST18))
++            return WPACKET_put_bytes_u8(pkt, TLS_CT_GOST12_SIGN)
+                     && WPACKET_put_bytes_u8(pkt, TLS_CT_GOST12_512_SIGN);
+ #endif
+@@ -4695,6 +4815,52 @@
+     return pkey;
+ }
+ #ifndef OPENSSL_NO_EC
++#ifndef OPENSSL_NO_GOST
++
++typedef struct tls_gost_group_param_st {
++    int nid;                    /* Curve params NID */
++    int alg_nid;                /* GOST algorithm nid */
++    const char *params;         /* GOST paramset mnemonics */
++} TLS_GOST_GROUP_PARAM;
++
++TLS_GOST_GROUP_PARAM gost_param[] = {
++    {NID_id_tc26_gost_3410_2012_256_paramSetA, NID_id_GostR3410_2012_256, "TCA"},
++    {NID_id_tc26_gost_3410_2012_256_paramSetB, NID_id_GostR3410_2012_256, "TCB"},
++    {NID_id_tc26_gost_3410_2012_256_paramSetC, NID_id_GostR3410_2012_256, "TCC"},
++    {NID_id_tc26_gost_3410_2012_256_paramSetD, NID_id_GostR3410_2012_256, "TCD"},
++    {NID_id_tc26_gost_3410_2012_512_paramSetA, NID_id_GostR3410_2012_512, "A"},
++    {NID_id_tc26_gost_3410_2012_512_paramSetB, NID_id_GostR3410_2012_512, "B"},
++    {NID_id_tc26_gost_3410_2012_512_paramSetC, NID_id_GostR3410_2012_512, "C"},
++};
++
++static EVP_PKEY_CTX *gost_pkey_nid2ctx(int nid)
++{
++      int i = 0;
++      TLS_GOST_GROUP_PARAM *pGostParam = NULL;
++  EVP_PKEY_CTX *pctx = NULL;
++
++      for (i = 0; i < OSSL_NELEM(gost_param); i++) {
++              if (gost_param[i].nid == nid) {
++                      pGostParam = gost_param + i;
++                      break;
++              }
++      }
++
++      if (pGostParam == NULL) {
++              return NULL;
++      }
++
++      pctx = EVP_PKEY_CTX_new_id(pGostParam->alg_nid, NULL);
++      if (pctx == NULL
++                      || EVP_PKEY_CTX_ctrl_str(pctx, "paramset", pGostParam->params) <= 0) {
++    EVP_PKEY_CTX_free(pctx);
++    return NULL;
++      }
++
++      return pctx;
++}
++
++#endif
+ /* Generate a private key from a group ID */
+ EVP_PKEY *ssl_generate_pkey_group(SSL *s, uint16_t id)
+ {
+@@ -4711,8 +4877,13 @@
+     gtype = ginf->flags & TLS_CURVE_TYPE;
+     if (gtype == TLS_CURVE_CUSTOM)
+         pctx = EVP_PKEY_CTX_new_id(ginf->nid, NULL);
++#ifndef OPENSSL_NO_GOST
++    else if (gtype == TLS_CURVE_GOST)
++                  pctx = gost_pkey_nid2ctx(ginf->nid);
++#endif
+     else
+         pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
++
+     if (pctx == NULL) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_PKEY_GROUP,
+                  ERR_R_MALLOC_FAILURE);
+@@ -4723,7 +4894,7 @@
+                  ERR_R_EVP_LIB);
+         goto err;
+     }
+-    if (gtype != TLS_CURVE_CUSTOM
++    if (gtype != TLS_CURVE_CUSTOM && gtype != TLS_CURVE_GOST
+             && EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ginf->nid) <= 0) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_GENERATE_PKEY_GROUP,
+                  ERR_R_EVP_LIB);
+@@ -4761,13 +4932,21 @@
+         return NULL;
+     }
++#ifndef OPENSSL_NO_GOST
++    if ((ginf->flags & TLS_CURVE_TYPE) == TLS_CURVE_GOST)
++         pctx = gost_pkey_nid2ctx(ginf->nid);
++    else
++#endif
+     pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
++
+     if (pctx == NULL)
+         goto err;
+     if (EVP_PKEY_paramgen_init(pctx) <= 0)
+         goto err;
+-    if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ginf->nid) <= 0)
++    if ((ginf->flags & TLS_CURVE_TYPE) != TLS_CURVE_GOST) {
++      if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ginf->nid) <= 0)
+         goto err;
++    }
+     if (EVP_PKEY_paramgen(pctx, &pkey) <= 0) {
+         EVP_PKEY_free(pkey);
+         pkey = NULL;
+Index: ssl/statem/statem_lib.c
+===================================================================
+--- ssl/statem/statem_lib.c    (revision 14523)
++++ ssl/statem/statem_lib.c    (working copy)
+@@ -410,7 +410,6 @@
+                 md == NULL ? "n/a" : EVP_MD_name(md));
+ #endif
+-    /* Check for broken implementations of GOST ciphersuites */
+     /*
+      * If key is GOST and len is exactly 64 or 128, it is signature without
+      * length field (CryptoPro implementations at least till TLS 1.2)
+@@ -1527,8 +1526,6 @@
+         switch (i) {
+         case SSL_PKEY_DSA_SIGN:
+         case SSL_PKEY_GOST01:
+-        case SSL_PKEY_GOST12_256:
+-        case SSL_PKEY_GOST12_512:
+             continue;
+         default:
+             break;
+Index: ssl/statem/statem_srvr.c
+===================================================================
+--- ssl/statem/statem_srvr.c   (revision 14523)
++++ ssl/statem/statem_srvr.c   (working copy)
+@@ -3446,6 +3446,93 @@
+ #endif
+ }
++static int tls_process_cke_gost18(SSL *s, PACKET *pkt)
++{/* FIXME beldmit - function id to be renamed either*/
++#ifndef OPENSSL_NO_GOST
++      unsigned char rnd_dgst[32];
++      EVP_PKEY_CTX *pkey_ctx = NULL;
++      EVP_PKEY *pk = NULL;
++      unsigned char premaster_secret[32];
++      const unsigned char *start = NULL;
++      size_t outlen = 32, inlen = 0;
++      int ret = 0;
++  int cipher_nid = gost18_cke_cipher_nid(s);
++
++  if (cipher_nid == NID_undef) {
++      SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++               ERR_R_INTERNAL_ERROR);
++      return 0;
++  }
++
++      if (gost_ukm(s, rnd_dgst) <= 0) {
++      SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++               ERR_R_INTERNAL_ERROR);
++      goto err;
++  }
++
++      /* Get our certificate private key */
++      pk = s->cert->pkeys[SSL_PKEY_GOST12_512].privatekey
++              ? s->cert->pkeys[SSL_PKEY_GOST12_512].privatekey : s->cert->pkeys[SSL_PKEY_GOST12_256].privatekey;
++      if (pk == NULL) {
++              SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++                              SSL_R_BAD_HANDSHAKE_STATE);
++              return 0;
++      }
++
++      pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
++      if (pkey_ctx == NULL) {
++              SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++                              ERR_R_MALLOC_FAILURE);
++              return 0;
++      }
++      if (EVP_PKEY_decrypt_init(pkey_ctx) <= 0) {
++              SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++                              ERR_R_INTERNAL_ERROR);
++              return 0;
++      }
++      /* 
++       * Reuse EVP_PKEY_CTRL_SET_IV, make choice in engine code depending on size
++       * */
++      if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_DECRYPT,
++                              EVP_PKEY_CTRL_SET_IV, 32, rnd_dgst) < 0) {
++              SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++                              SSL_R_LIBRARY_BUG);
++              goto err;
++      }
++
++      if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_DECRYPT,
++                              EVP_PKEY_CTRL_CIPHER, cipher_nid, NULL) < 0) {
++              SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++                              SSL_R_LIBRARY_BUG);
++              goto err;
++      }
++      inlen = PACKET_remaining(pkt);
++      start = PACKET_data(pkt);
++
++      if (EVP_PKEY_decrypt(pkey_ctx, premaster_secret, &outlen, start,
++                              inlen) <= 0) {
++              SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++                              SSL_R_DECRYPTION_FAILED);
++              goto err;
++      }
++      /* Generate master secret */
++      if (!ssl_generate_master_secret(s, premaster_secret,
++                              sizeof(premaster_secret), 0)) {
++              /* SSLfatal() already called */
++              goto err;
++      }
++      ret = 1;
++err:
++      EVP_PKEY_CTX_free(pkey_ctx);
++      return ret;
++#else
++      /* Should never happen */
++      SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_GOST18,
++                      ERR_R_INTERNAL_ERROR);
++      return 0;
++#endif
++}
++
+ MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
+ {
+     unsigned long alg_k;
+@@ -3496,6 +3583,11 @@
+             /* SSLfatal() already called */
+             goto err;
+         }
++    } else if (alg_k & SSL_kGOST18) {
++        if (!tls_process_cke_gost18(s, pkt)) {
++            /* SSLfatal() already called */
++            goto err;
++        }
+     } else {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                  SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+Index: ssl/statem/extensions_srvr.c
+===================================================================
+--- ssl/statem/extensions_srvr.c       (revision 14523)
++++ ssl/statem/extensions_srvr.c       (working copy)
+@@ -624,7 +624,7 @@
+     if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0)
+         return 1;
+-
++/* FIXME beldmit GOST */
+     /* Sanity check */
+     if (s->s3->peer_tmp != NULL) {
+         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
+@@ -1623,7 +1623,9 @@
+     if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD
+         || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
+         || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
+-        || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12) {
++        || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12
++        || s->s3->tmp.new_cipher->algorithm_enc == SSL_MAGMA
++        || s->s3->tmp.new_cipher->algorithm_enc == SSL_KUZNYECHIK) {
+         s->ext.use_etm = 0;
+         return EXT_RETURN_NOT_SENT;
+     }
+@@ -1682,6 +1684,7 @@
+                                         unsigned int context, X509 *x,
+                                         size_t chainidx)
+ {
++/* FIXME beldmit GOST */
+ #ifndef OPENSSL_NO_TLS1_3
+     unsigned char *encodedPoint;
+     size_t encoded_pt_len = 0;
+Index: ssl/statem/statem_local.h
+===================================================================
+--- ssl/statem/statem_local.h  (revision 14523)
++++ ssl/statem/statem_local.h  (working copy)
+@@ -153,6 +153,11 @@
+ __owur int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt);
+ MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt);
++#ifndef OPENSSL_NO_GOST
++/* These functions are used in GOST18 CKE, both for client and server */
++int gost18_cke_cipher_nid(const SSL *s);
++int gost_ukm(const SSL *s, unsigned char *dgst_buf);
++#endif
+ /* Extension processing */
+Index: ssl/statem/statem_clnt.c
+===================================================================
+--- ssl/statem/statem_clnt.c   (revision 14523)
++++ ssl/statem/statem_clnt.c   (working copy)
+@@ -3280,6 +3280,144 @@
+ #endif
+ }
++#ifndef OPENSSL_NO_GOST
++int gost18_cke_cipher_nid(const SSL *s)
++{
++    if ((s->s3->tmp.new_cipher->algorithm_enc & SSL_MAGMA) != 0)
++        return NID_magma_ctr;
++    else if ((s->s3->tmp.new_cipher->algorithm_enc & SSL_KUZNYECHIK) != 0)
++        return NID_kuznyechik_ctr;
++
++    return NID_undef;
++}
++
++int gost_ukm(const SSL *s, unsigned char *dgst_buf)
++{
++    EVP_MD_CTX * hash = NULL;
++    unsigned int md_len;
++
++    hash = EVP_MD_CTX_new();
++    if (hash == NULL
++        || EVP_DigestInit(hash, EVP_get_digestbynid(NID_id_GostR3411_2012_256)) <= 0
++        || EVP_DigestUpdate(hash, s->s3->client_random, SSL3_RANDOM_SIZE) <= 0
++        || EVP_DigestUpdate(hash, s->s3->server_random, SSL3_RANDOM_SIZE) <= 0
++        || EVP_DigestFinal_ex(hash, dgst_buf, &md_len) <= 0) {
++        EVP_MD_CTX_free(hash);
++        return 0;
++    } else {
++        EVP_MD_CTX_free(hash);
++        return 1;
++    }
++}
++#endif
++
++static int tls_construct_cke_gost18(SSL *s, WPACKET *pkt)
++{
++#ifndef OPENSSL_NO_GOST
++    /* GOST 2018 key exchange message creation */
++    unsigned char rnd_dgst[32], tmp[255];
++    EVP_PKEY_CTX *pkey_ctx = NULL;
++    X509 *peer_cert;
++    unsigned char *pms = NULL;
++    size_t pmslen = 0;
++    size_t msglen;
++    int cipher_nid = gost18_cke_cipher_nid(s);
++
++    if (cipher_nid == NID_undef) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 ERR_R_INTERNAL_ERROR);
++        return 0;
++    }
++
++              if (gost_ukm(s, rnd_dgst) <= 0) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++
++    /* Pre-master secret - random bytes */
++    pmslen = 32;
++    pms = OPENSSL_malloc(pmslen);
++    if (pms == NULL) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 ERR_R_MALLOC_FAILURE);
++        goto err;
++    }
++
++    if (RAND_bytes(pms, (int)pmslen) <= 0) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++
++    /*
++     * Get server certificate PKEY and create ctx from it
++     */
++    peer_cert = s->session->peer;
++    if (!peer_cert) {
++        SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++               SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
++        return 0;
++    }
++
++    pkey_ctx = EVP_PKEY_CTX_new(X509_get0_pubkey(peer_cert), NULL);
++    if (pkey_ctx == NULL) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 ERR_R_MALLOC_FAILURE);
++        return 0;
++    }
++
++    if (EVP_PKEY_encrypt_init(pkey_ctx) <= 0 ) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 ERR_R_INTERNAL_ERROR);
++        goto err;
++    };
++
++ /* 
++  * Reuse EVP_PKEY_CTRL_SET_IV, make choice in engine code
++  * */
++    if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
++                          EVP_PKEY_CTRL_SET_IV, 32, rnd_dgst) < 0) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 SSL_R_LIBRARY_BUG);
++        goto err;
++    }
++
++    if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
++                          EVP_PKEY_CTRL_CIPHER, cipher_nid, NULL) < 0) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 SSL_R_LIBRARY_BUG);
++        goto err;
++    }
++
++    msglen = 255;
++    if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 SSL_R_LIBRARY_BUG);
++        goto err;
++    }
++
++    if (!WPACKET_memcpy(pkt, tmp, msglen)) {
++        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++                 ERR_R_INTERNAL_ERROR);
++        goto err;
++    }
++
++    EVP_PKEY_CTX_free(pkey_ctx);
++    s->s3->tmp.pms = pms;
++    s->s3->tmp.pmslen = pmslen;
++              return 1;
++ err:
++    EVP_PKEY_CTX_free(pkey_ctx);
++    OPENSSL_clear_free(pms, pmslen);
++    return 0;
++#else
++    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_GOST18,
++             ERR_R_INTERNAL_ERROR);
++    return 0;
++#endif
++}
++
+ static int tls_construct_cke_srp(SSL *s, WPACKET *pkt)
+ {
+ #ifndef OPENSSL_NO_SRP
+@@ -3336,6 +3474,9 @@
+     } else if (alg_k & SSL_kGOST) {
+         if (!tls_construct_cke_gost(s, pkt))
+             goto err;
++    } else if (alg_k & SSL_kGOST18) {
++        if (!tls_construct_cke_gost18(s, pkt))
++            goto err;
+     } else if (alg_k & SSL_kSRP) {
+         if (!tls_construct_cke_srp(s, pkt))
+             goto err;
+Index: util/libcrypto.num
+===================================================================
+--- util/libcrypto.num (revision 14523)
++++ util/libcrypto.num (working copy)
+@@ -4587,3 +4587,8 @@
+ EVP_PKEY_meth_get_digestverify          4541  1_1_1e  EXIST::FUNCTION:
+ EVP_PKEY_meth_get_digestsign            4542  1_1_1e  EXIST::FUNCTION:
+ RSA_get0_pss_params                     4543  1_1_1e  EXIST::FUNCTION:RSA
++CMS_add1_recipient                      4544  1_1_1g  EXIST::FUNCTION:CMS
++PKCS8_pkey_add1_attr                    4545  1_1_1g  EXIST::FUNCTION:
++PKCS8_pkey_add1_attr_by_OBJ             4546  1_1_1g  EXIST::FUNCTION:
++CMS_decrypt_set1_pkey_and_peer          4547  1_1_1g  EXIST::FUNCTION:CMS
++CMS_RecipientInfo_kari_set0_pkey_and_peer 4548        1_1_1g  EXIST::FUNCTION:CMS